rev 58428 : [mq]: XXXXXXX-typos
1 /*
2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package java.lang.constant;
26
27 import java.lang.invoke.CallSite;
28 import java.lang.invoke.MethodHandle;
29 import java.lang.invoke.MethodHandles;
30 import java.util.Arrays;
31 import java.util.Objects;
32 import java.util.stream.Stream;
33
34 import static java.lang.constant.ConstantDescs.CD_String;
35 import static java.lang.constant.ConstantUtils.EMPTY_CONSTANTDESC;
36 import static java.lang.constant.ConstantUtils.validateMemberName;
37 import static java.util.Objects.requireNonNull;
38 import static java.util.stream.Collectors.joining;
39
40 /**
41 * A <a href="package-summary.html#nominal">nominal descriptor</a> for an
42 * {@code invokedynamic} call site.
43 *
44 * <p>Concrete subtypes of {@linkplain DynamicCallSiteDesc} must be
45 * <a href="../doc-files/ValueBased.html">value-based</a>.
46 *
47 * @since 12
48 */
49 public class DynamicCallSiteDesc {
50
51 private final DirectMethodHandleDesc bootstrapMethod;
52 private final ConstantDesc[] bootstrapArgs;
53 private final String invocationName;
54 private final MethodTypeDesc invocationType;
55
56 /**
57 * Creates a nominal descriptor for an {@code invokedynamic} call site.
58 *
59 * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
60 * bootstrap method for the {@code invokedynamic}
61 * @param invocationName The unqualified name that would appear in the {@code NameAndType}
62 * operand of the {@code invokedynamic}
63 * @param invocationType a {@link MethodTypeDesc} describing the invocation
64 * type that would appear in the {@code NameAndType}
65 * operand of the {@code invokedynamic}
66 * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
67 * to the bootstrap, that would appear in the
68 * {@code BootstrapMethods} attribute
69 * @throws NullPointerException if any parameter is null
70 * @throws IllegalArgumentException if the invocation name has the incorrect
71 * format
72 * @jvms 4.2.2 Unqualified Names
73 */
74 private DynamicCallSiteDesc(DirectMethodHandleDesc bootstrapMethod,
75 String invocationName,
76 MethodTypeDesc invocationType,
77 ConstantDesc[] bootstrapArgs) {
78 this.invocationName = validateMemberName(requireNonNull(invocationName), true);
79 this.invocationType = requireNonNull(invocationType);
80 this.bootstrapMethod = requireNonNull(bootstrapMethod);
81 this.bootstrapArgs = requireNonNull(bootstrapArgs.clone());
82 if (invocationName.length() == 0)
83 throw new IllegalArgumentException("Illegal invocation name: " + invocationName);
84 }
85
86 /**
87 * Creates a nominal descriptor for an {@code invokedynamic} call site.
88 *
89 * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
90 * bootstrap method for the {@code invokedynamic}
91 * @param invocationName The unqualified name that would appear in the {@code NameAndType}
92 * operand of the {@code invokedynamic}
93 * @param invocationType a {@link MethodTypeDesc} describing the invocation
94 * type that would appear in the {@code NameAndType}
95 * operand of the {@code invokedynamic}
96 * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
97 * to the bootstrap, that would appear in the
98 * {@code BootstrapMethods} attribute
99 * @return the nominal descriptor
100 * @throws NullPointerException if any parameter is null
101 * @throws IllegalArgumentException if the invocation name has the incorrect
102 * format
103 * @jvms 4.2.2 Unqualified Names
104 */
105 public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
106 String invocationName,
107 MethodTypeDesc invocationType,
108 ConstantDesc... bootstrapArgs) {
109 return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
110 }
111
112 /**
113 * Creates a nominal descriptor for an {@code invokedynamic} call site whose
114 * bootstrap method has no static arguments.
115 *
116 * @param bootstrapMethod The bootstrap method for the {@code invokedynamic}
117 * @param invocationName The invocationName that would appear in the
118 * {@code NameAndType} operand of the {@code invokedynamic}
119 * @param invocationType The invocation invocationType that would appear
120 * in the {@code NameAndType} operand of the {@code invokedynamic}
121 * @return the nominal descriptor
122 * @throws NullPointerException if any parameter is null
123 * @throws IllegalArgumentException if the invocation name has the incorrect
124 * format
125 */
126 public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
127 String invocationName,
128 MethodTypeDesc invocationType) {
129 return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, EMPTY_CONSTANTDESC);
130 }
131
132 /**
133 * Creates a nominal descriptor for an {@code invokedynamic} call site whose
134 * bootstrap method has no static arguments and for which the name parameter
135 * is {@link ConstantDescs#DEFAULT_NAME}.
136 *
137 * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
138 * bootstrap method for the {@code invokedynamic}
139 * @param invocationType a {@link MethodTypeDesc} describing the invocation
140 * type that would appear in the {@code NameAndType}
141 * operand of the {@code invokedynamic}
142 * @return the nominal descriptor
143 * @throws NullPointerException if any parameter is null
144 */
145 public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
146 MethodTypeDesc invocationType) {
147 return of(bootstrapMethod, ConstantDescs.DEFAULT_NAME, invocationType);
148 }
149
150 /**
151 * Returns a nominal descriptor for an {@code invokedynamic} call site whose
152 * bootstrap method, name, and invocation type are the same as this one, but
153 * with the specified bootstrap arguments.
154 *
155 * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
156 * to the bootstrap, that would appear in the
157 * {@code BootstrapMethods} attribute
158 * @return the nominal descriptor
159 * @throws NullPointerException if any parameter is null
160 */
161 public DynamicCallSiteDesc withArgs(ConstantDesc... bootstrapArgs) {
162 return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
163 }
164
165 /**
166 * Returns a nominal descriptor for an {@code invokedynamic} call site whose
167 * bootstrap and bootstrap arguments are the same as this one, but with the
168 * specified invocationName and invocation invocationType
169 *
170 * @param invocationName The unqualified name that would appear in the {@code NameAndType}
171 * operand of the {@code invokedynamic}
172 * @param invocationType a {@link MethodTypeDesc} describing the invocation
173 * type that would appear in the {@code NameAndType}
174 * operand of the {@code invokedynamic}
175 * @return the nominal descriptor
176 * @throws NullPointerException if any parameter is null
177 * @throws IllegalArgumentException if the invocation name has the incorrect
178 * format
179 * @jvms 4.2.2 Unqualified Names
180 */
181 public DynamicCallSiteDesc withNameAndType(String invocationName,
182 MethodTypeDesc invocationType) {
183 return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
184 }
185
186 /**
187 * Returns the invocation name that would appear in the {@code NameAndType}
188 * operand of the {@code invokedynamic}.
189 *
190 * @return the invocation name
191 */
192 public String invocationName() {
193 return invocationName;
194 }
195
196 /**
197 * Returns a {@link MethodTypeDesc} describing the invocation type that
198 * would appear in the {@code NameAndType} operand of the {@code invokedynamic}.
199 *
200 * @return the invocation type
201 */
202 public MethodTypeDesc invocationType() {
203 return invocationType;
204 }
205
206 /**
207 * Returns a {@link MethodHandleDesc} describing the bootstrap method for
208 * the {@code invokedynamic}.
209 *
210 * @return the bootstrap method for the {@code invokedynamic}
211 */
212 public MethodHandleDesc bootstrapMethod() { return bootstrapMethod; }
213
214 /**
215 * Returns {@link ConstantDesc}s describing the bootstrap arguments for the
216 * {@code invokedynamic}. The returned array is always non-null. A zero
217 * length array is returned if this {@linkplain DynamicCallSiteDesc} has no
218 * bootstrap arguments.
219 *
220 * @return the bootstrap arguments for the {@code invokedynamic}
221 */
222 public ConstantDesc[] bootstrapArgs() { return bootstrapArgs.clone(); }
223
224 /**
225 * Reflectively invokes the bootstrap method with the specified arguments,
226 * and return the resulting {@link CallSite}
227 *
228 * @param lookup The {@link MethodHandles.Lookup} used to resolve class names
229 * @return the {@link CallSite}
230 * @throws Throwable if any exception is thrown by the bootstrap method
231 */
232 public CallSite resolveCallSiteDesc(MethodHandles.Lookup lookup) throws Throwable {
233 assert bootstrapMethod.invocationType().parameterType(1).equals(CD_String);
234 MethodHandle bsm = (MethodHandle) bootstrapMethod.resolveConstantDesc(lookup);
235 Object[] args = new Object[bootstrapArgs.length + 3];
236 args[0] = lookup;
237 args[1] = invocationName;
238 args[2] = invocationType.resolveConstantDesc(lookup);
239 System.arraycopy(bootstrapArgs, 0, args, 3, bootstrapArgs.length);
240 return (CallSite) bsm.invokeWithArguments(args);
241 }
242
243 /**
244 * Compares the specified object with this descriptor for equality. Returns
245 * {@code true} if and only if the specified object is also a
246 * {@linkplain DynamicCallSiteDesc}, and both descriptors have equal
247 * bootstrap methods, bootstrap argument lists, invocation name, and
248 * invocation type.
249 *
250 * @param o the {@code DynamicCallSiteDesc} to compare to this
251 * {@code DynamicCallSiteDesc}
252 * @return {@code true} if the specified {@code DynamicCallSiteDesc} is
253 * equal to this {@code DynamicCallSiteDesc}.
254 */
255 @Override
256 public final boolean equals(Object o) {
257 if (this == o) return true;
258 if (o == null || getClass() != o.getClass()) return false;
259 DynamicCallSiteDesc specifier = (DynamicCallSiteDesc) o;
260 return Objects.equals(bootstrapMethod, specifier.bootstrapMethod) &&
261 Arrays.equals(bootstrapArgs, specifier.bootstrapArgs) &&
262 Objects.equals(invocationName, specifier.invocationName) &&
263 Objects.equals(invocationType, specifier.invocationType);
264 }
265
266 @Override
267 public final int hashCode() {
268 int result = Objects.hash(bootstrapMethod, invocationName, invocationType);
269 result = 31 * result + Arrays.hashCode(bootstrapArgs);
270 return result;
271 }
272
273 /**
274 * Returns a compact textual description of this call site description,
275 * including the bootstrap method, the invocation name and type, and
276 * the static bootstrap arguments.
277 *
278 * @return A compact textual description of this call site descriptor
279 */
280 @Override
281 public String toString() {
282 return String.format("DynamicCallSiteDesc[%s::%s(%s%s):%s]",
283 bootstrapMethod.owner().displayName(),
284 bootstrapMethod.methodName(),
285 invocationName.equals(ConstantDescs.DEFAULT_NAME) ? "" : invocationName + "/",
286 Stream.of(bootstrapArgs).map(Object::toString).collect(joining(",")),
287 invocationType.displayDescriptor());
288 }
289 }
--- EOF ---