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
26 package java.lang.invoke;
27
28 import java.lang.invoke.MethodHandles.Lookup;
29
30 /**
31 * An interface providing full static information about a particular
32 * call to a
33 * <a href="package-summary.html#bsm">bootstrap method</a> of an
34 * dynamic call site or dynamic constant.
35 * This information includes the method itself, the associated
36 * name and type, and any associated static arguments.
37 * <p>
38 * If a bootstrap method declares exactly two arguments, and is
39 * not of variable arity, then it is fed only two arguments by
40 * the JVM, the {@linkplain Lookup lookup object} and an instance
41 * of {@code BootstrapCallInfo} which supplies the rest of the
42 * information about the call.
43 * <p>
44 * The API for accessing the static arguments allows the bootstrap
45 * method to reorder the resolution (in the constant pool) of the
46 * static arguments, and to catch errors resulting from the resolution.
47 * This mode of evaluation <em>pulls</em> bootstrap parameters from
48 * the JVM under control of the bootstrap method, as opposed to
49 * the JVM <em>pushing</em> parameters to a bootstrap method
50 * by resolving them all before the bootstrap method is called.
51 * @apiNote
52 * <p>
53 * The {@linkplain Lookup lookup object} is <em>not</em> included in this
54 * bundle of information, so as not to obscure the access control
55 * logic of the program.
56 * In cases where there are many thousands of parameters, it may
57 * be preferable to pull their resolved values, either singly or in
58 * batches, rather than wait until all of them have been resolved
59 * before a constant or call site can be used.
60 * <p>
61 * A push mode bootstrap method can be adapted to a pull mode
62 * bootstrap method, and vice versa. For example, this generic
63 * adapter pops a push-mode bootstrap method from the beginning
64 * of the static argument list, eagerly resolves all the remaining
65 * static arguments, and invokes the popped method in push mode.
66 * The callee has no way of telling that it was not called directly
67 * from the JVM.
68 * <blockquote><pre>{@code
69 static Object genericBSM(Lookup lookup, BootstrapCallInfo<Object> bsci)
70 throws Throwable {
71 ArrayList<Object> args = new ArrayList<>();
72 args.add(lookup);
73 args.add(bsci.invocationName());
74 args.add(bsci.invocationType());
75 MethodHandle bsm = (MethodHandle) bsci.get(0);
76 List<Object> restOfArgs = bsci.asList().subList(1, bsci.size();
77 // the next line eagerly resolves all remaining static arguments:
78 args.addAll(restOfArgs);
79 return bsm.invokeWithArguments(args);
80 }
81 * }</pre></blockquote>
82 *
83 * <p>
84 * In the other direction, here is a combinator which pops
85 * a pull-mode bootstrap method from the beginning of a list of
86 * static argument values (already resolved), reformats all of
87 * the arguments into a pair of a lookup and a {@code BootstrapCallInfo},
88 * and invokes the popped method. Again the callee has no way of
89 * telling it was not called directly by the JVM, except that
90 * all of the constant values will appear as resolved.
91 * Put another way, if any constant fails to resolve, the
92 * callee will not be able to catch the resulting error,
93 * since the error will be thrown by the JVM before the
94 * bootstrap method is entered.
95 * <blockquote><pre>{@code
96 static Object genericBSM(Lookup lookup, String name, Object type,
97 MethodHandle bsm, Object... args)
98 throws Throwable {
99 ConstantGroup cons = ConstantGroup.makeConstantGroup(Arrays.asList(args));
100 BootstrapCallInfo<Object> bsci = makeBootstrapCallInfo(bsm, name, type, cons);
101 return bsm.invoke(lookup, bsci);
102 }
103 * }</pre></blockquote>
104 *
105 * @since 1.10
106 */
107 // public
108 interface BootstrapCallInfo<T> extends ConstantGroup {
109 /** Returns the bootstrap method for this call.
110 * @return the bootstrap method
111 */
112 MethodHandle bootstrapMethod();
113
114 /** Returns the method name or constant name for this call.
115 * @return the method name or constant name
116 */
117 String invocationName();
118
119 /** Returns the method type or constant type for this call.
120 * @return the method type or constant type
121 */
122 T invocationType();
123
124 /**
125 * Make a new bootstrap call descriptor with the given components.
126 * @param bsm bootstrap method
127 * @param name invocation name
128 * @param type invocation type
129 * @param constants the additional static arguments for the bootstrap method
130 * @param <T> the type of the invocation type, either {@link MethodHandle} or {@link Class}
131 * @return a new bootstrap call descriptor with the given components
132 */
133 static <T> BootstrapCallInfo<T> makeBootstrapCallInfo(MethodHandle bsm,
134 String name,
135 T type,
136 ConstantGroup constants) {
137 AbstractConstantGroup.BSCIWithCache<T> bsci = new AbstractConstantGroup.BSCIWithCache<>(bsm, name, type, constants.size());
138 final Object NP = AbstractConstantGroup.BSCIWithCache.NOT_PRESENT;
139 bsci.initializeCache(constants.asList(NP), NP);
140 return bsci;
141 }
142 }
|
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
26 package java.lang.invoke;
27
28 import java.lang.constant.Constable;
29 import java.lang.constant.ConstantDesc;
30 import java.lang.invoke.AbstractBootstrapCallInfo.*;
31 import java.lang.invoke.MethodHandles.Lookup;
32 import java.util.List;
33 import java.util.Objects;
34 import sun.invoke.util.Wrapper;
35
36 import static java.lang.invoke.BootstrapMethodInvoker.invokeCommon;
37
38 /**
39 * An interface providing full static information about a particular
40 * call to a
41 * <a href="package-summary.html#bsm">bootstrap method</a> of an
42 * dynamic call site or dynamic constant.
43 * This information includes the bootstrap method itself, the associated
44 * name and type, and any associated static arguments.
45 * <p>
46 * If a bootstrap method declares exactly two arguments, and is
47 * not of variable arity, then it is fed only two arguments by
48 * the JVM, the {@linkplain Lookup lookup object} and an instance
49 * of {@code BootstrapCallInfo} which supplies the rest of the
50 * information about the call.
51 * <p>
52 * The API for accessing the static arguments allows the bootstrap
53 * method to reorder the resolution (in the constant pool) of the
54 * static arguments, and to catch errors resulting from the resolution.
55 * This mode of evaluation <em>pulls</em> bootstrap parameters from
56 * the JVM under control of the bootstrap method, as opposed to
57 * the JVM <em>pushing</em> parameters to a bootstrap method
58 * by resolving them all before the bootstrap method is called.
59 * @apiNote
60 * <p>
61 * The {@linkplain Lookup lookup object} is <em>not</em> included in this
62 * bundle of information, so as not to obscure the access control
63 * logic of the program.
64 * In cases where there are many thousands of parameters, it may
65 * be preferable to pull their resolved values, either singly or in
66 * batches, rather than wait until all of them have been resolved
67 * before a constant or call site can be used.
68 * <p>
69 * A push mode bootstrap method can be adapted to a pull mode
70 * bootstrap method, and vice versa. For example, this generic
71 * adapter pops a push-mode bootstrap method from the beginning
72 * of the static argument list, eagerly resolves all the remaining
73 * static arguments, and invokes the popped method in push mode.
74 * The callee has no way of telling that it was not called directly
75 * from the JVM.
76 * <blockquote><pre>{@code
77 static Object genericBSM(Lookup lookup, BootstrapCallInfo<Object> bsci)
78 throws Throwable {
79 ArrayList<Object> args = new ArrayList<>();
80 args.add(lookup);
81 args.add(bsci.invocationName());
82 args.add(bsci.invocationType());
83 MethodHandle bsm = (MethodHandle) bsci.argument(0);
84 List<Object> restOfArgs = bsci.argumentList().subList(1, bsci.argumentCount());
85 // the next line eagerly resolves all remaining static arguments:
86 args.addAll(restOfArgs);
87 return bsm.invokeWithArguments(args);
88 }
89 * }</pre></blockquote>
90 *
91 * @param <T> the type {@code MethodType} or {@code Class}
92 *
93 * @since 12
94 */
95 // public
96 interface BootstrapCallInfo<T extends TypeDescriptor & Constable<T>> {
97
98 /** Returns the bootstrap method for this call.
99 * @return the bootstrap method
100 */
101 MethodHandle bootstrapMethod();
102
103 /** Returns the method name or constant name for this call.
104 * @return the method name or constant name
105 */
106 String invocationName();
107
108 /** Returns the method type or constant type for this call.
109 * @return the method type or constant type
110 */
111 T invocationType();
112
113 /** Returns a ConstantDesc for the method type or constant type for this call.
114 * Does not (by itself) trigger resolution of this type.
115 * @return the method type or constant type
116 */
117 ConstantDesc<T> invocationTypeDesc();
118
119 /**
120 * Returns the number of static arguments.
121 * @return the number of static arguments
122 */
123 int argumentCount();
124
125 /**
126 * Returns the selected static argument, resolving it if necessary.
127 * Throws a linkage error if resolution proves impossible.
128 * @param index which static argument to select
129 * @return the selected static argument
130 * @throws LinkageError if the selected static argument needs resolution
131 * and cannot be resolved
132 */
133 Object argument(int index) throws LinkageError;
134
135 /**
136 * Returns the selected static argument,
137 * or the given sentinel value if there is none available.
138 * If the static argument cannot be resolved, the sentinel will be returned.
139 * If the static argument can (perhaps) be resolved, but has not yet been resolved,
140 * then the sentinel <em>may</em> be returned, at the implementation's discretion.
141 * To force resolution (and a possible exception), call {@link #argument(int)}.
142 * @param index which static argument to select
143 * @param ifNotPresent the sentinel value to return if the static argument is not present
144 * @return the selected static argument, if available, else the sentinel value
145 */
146 default Object argument(int index, Object ifNotPresent) {
147 if (argumentIsPresent(index)) return argument(index);
148 return ifNotPresent;
149 }
150
151 /**
152 * Returns a symbolic reference underlying the selected static argument,
153 * if it is available.
154 * @param index which static argument to select
155 * @return a symbolic reference underlying the selected static argument
156 * @throws IllegalArgumentException if the original symbolic reference is not available,
157 * and a substitute cannot be created on the fly by {@link ConstantDesc}.
158 */
159 ConstantDesc<?> argumentDesc(int index);
160
161 /**
162 * Returns an indication of whether a static argument may be available.
163 * If it returns {@code true}, it will always return true in the future,
164 * and a call to {@link #argument(int)} will never throw an exception.
165 * <p>
166 * After a normal return from {@link #argument(int)} or a present
167 * value is reported from {@link #argument(int,Object)}, this method
168 * must always return true.
169 * <p>
170 * If this method returns {@code false}, nothing in particular
171 * can be inferred, since the query only concerns the internal
172 * logic of the {@code BootstrapCallInfo} object which ensures that a
173 * successful query to a constant will always remain successful.
174 * The only way to force a permanent decision about whether
175 * a static argument is available is to call {@link #argument(int)} and
176 * be ready for an exception if the constant is unavailable.
177 * @param index which constant to select
178 * @return {@code true} if the selected static argument is known by
179 * this object to be present, {@code false} if it is known
180 * not to be present or
181 */
182 boolean argumentIsPresent(int index);
183
184
185 /// Views
186
187 /**
188 * Create a view on the static arguments as a {@link List} view.
189 * Any request for a static argument through this view will
190 * force resolution, and may therefore cause a {@code LinkageError}.
191 * @return a {@code List} view on the static arguments which will force resolution
192 */
193 default List<Object> argumentList() {
194 return new ArgList(this, 0, argumentCount());
195 }
196
197 /**
198 * Create a view on the static arguments as a {@link List} view.
199 * Any request for a static argument through this view will
200 * return the given sentinel value, if the corresponding
201 * call to {@link #argument(int,Object)} would do so.
202 * @param ifNotPresent the sentinel value to return if a static argument is not present
203 * @return a {@code List} view on the static arguments which will not force resolution
204 */
205 default List<Object> argumentList(Object ifNotPresent) {
206 return new ArgList(this, 0, argumentCount(), ifNotPresent);
207 }
208
209 /**
210 * Create a view on the symbolic references of the static arguments as a {@link List} view.
211 * @return a {@code List} view on this group's symbolic references
212 */
213 default List<ConstantDesc<?>> argumentDescList() {
214 List<Object> syms = new ArgList(this, true, 0, argumentCount());
215 @SuppressWarnings({"unchecked", "rawtypes"})
216 List<ConstantDesc<?>> result = (List) syms;
217 return result;
218 }
219
220 /// Factories and helper methods
221
222 /**
223 * Invoke a bootstrap method handle with arguments obtained by resolving
224 * the sequence of constants supplied by a given bootstrap call descriptor,
225 * {@code bci}.
226 * The first argument to the method will be {@code lookup}.
227 * The second argument will be the invocation name of {@code bci}.
228 * The third argument will be the invocation type of {@code bci}.
229 * The fourth and subsequent arguments (if any) will be the resolved
230 * constants, in order, supplied by {@code bci}.
231 * <p>
232 * @apiNote
233 * This method behaves like the following but may be more optimal:
234 * <blockquote><pre>{@code
235 * ArrayList<Object> args = new ArrayList<>();
236 * args.add(lookup);
237 * args.add(name);
238 * args.add(type);
239 * args.addAll(staticArgs);
240 * return handle.invokeWithArguments(args);
241 * }</pre></blockquote>
242 *
243 * @param handle the bootstrap method handle to be invoked on the static arguments
244 * @param lookup the lookup
245 * @param name the name associated with the constant or call site being linked
246 * @param type the type associated with the constant or call site being linked
247 * @param staticArgs the static argument list
248 * @return the result of invocation
249 * @throws Throwable if an error occurs when resolving the constants from
250 * the bootstrap call descriptor or invoking the method handle
251 */
252 static Object invokeWithMetadata(MethodHandle handle,
253 MethodHandles.Lookup lookup,
254 String name,
255 TypeDescriptor type,
256 List<Object> staticArgs)
257 throws Throwable {
258 Objects.requireNonNull(lookup);
259 return invokeCommon(handle, lookup, name, type, null, staticArgs);
260 }
261
262 /**
263 * Invoke a bootstrap method handle with arguments obtained by resolving
264 * the sequence of constants supplied by a given bootstrap call descriptor,
265 * {@code bci}.
266 * The first argument to the method will be {@code lookup}.
267 * The second argument will be the invocation name of {@code bci}.
268 * The third argument will be the invocation type of {@code bci}.
269 * The fourth and subsequent arguments (if any) will be the resolved
270 * constants, in order, supplied by {@code bci}.
271 * <p>
272 * @apiNote
273 * This method behaves like the following but may be more optimal:
274 * <blockquote><pre>{@code
275 * ArrayList<Object> args = new ArrayList<>();
276 * args.add(lookup);
277 * args.add(name);
278 * args.add(type);
279 * args.addAll(Arrays.asList(staticArgs));
280 * return handle.invokeWithArguments(args);
281 * }</pre></blockquote>
282 *
283 * @param handle the bootstrap method handle to be invoked on the static arguments
284 * @param lookup the lookup
285 * @param name the name associated with the constant or call site being linked
286 * @param type the type associated with the constant or call site being linked
287 * @param staticArgs the static argument list
288 * @return the result of invocation
289 * @throws Throwable if an error occurs when resolving the constants from
290 * the bootstrap call descriptor or invoking the method handle
291 */
292 static Object invokeWithMetadata(MethodHandle handle,
293 MethodHandles.Lookup lookup,
294 String name,
295 TypeDescriptor type,
296 Object... staticArgs)
297 throws Throwable {
298 Objects.requireNonNull(lookup);
299 Objects.requireNonNull(staticArgs);
300 return invokeCommon(handle, lookup, name, type, staticArgs, null);
301 }
302
303 /**
304 * Invoke a bootstrap method handle with arguments obtained by resolving
305 * the sequence of constants supplied by a given bootstrap call descriptor,
306 * {@code bci}.
307 * The first argument to the method will be {@code lookup}.
308 * The second argument will be the invocation name of {@code bci}.
309 * The third argument will be the invocation type of {@code bci}.
310 * The fourth and subsequent arguments (if any) will be the resolved
311 * constants, in order, supplied by {@code bci}.
312 * <p>
313 * @apiNote
314 * This method behaves like the following but may be more optimal:
315 * <blockquote><pre>{@code
316 * ArrayList<Object> args = new ArrayList<>();
317 * args.add(lookup);
318 * args.add(bci.invocationName());
319 * args.add(bci.invocationType());
320 * args.addAll(bci.argumentList());
321 * return handle.invokeWithArguments(args);
322 * }</pre></blockquote>
323 *
324 * @param handle the bootstrap method handle to be invoked with resolved
325 * constants supplied by {@code bci}
326 * @param lookup the lookup
327 * @param bsci the bootstrap call descriptor
328 * @return the result of invocation
329 * @throws Throwable if an error occurs when resolving the constants from
330 * the bootstrap call descriptor or invoking the method handle
331 */
332 static Object invokeWithMetadata(MethodHandle handle,
333 MethodHandles.Lookup lookup,
334 BootstrapCallInfo<?> bsci)
335 throws Throwable {
336 Objects.requireNonNull(lookup);
337 return invokeCommon(handle, lookup, bsci.invocationName(), bsci.invocationType(), AbstractBootstrapCallInfo.maybeShareArguments(bsci), bsci.argumentList());
338 }
339
340 /**
341 * Convert the result returned by a bootstrap method to the class
342 * required by the bootstrap method's {@code invocationType}.
343 *
344 * @param bsci the bootstrap call descriptor
345 * @param result the result to be converted
346 * @param <T> the type {@code MethodType} or {@code Class}
347 * @return the converted result
348 * @throws ClassCastException if a value conversion error occurs during conversion
349 * @throws WrongMethodTypeException if a method type mismatch is detected occurs during conversion
350 */
351 static
352 <T extends TypeDescriptor & Constable<T>>
353 Object convertResult(BootstrapCallInfo<T> bsci, Object result) {
354 // FIXME: If invocationType cannot be resolved, some results are still valid.
355 return convertResult(bsci.invocationType(), bsci.bootstrapMethod().type().returnType(), result);
356 }
357
358 /**
359 * Convert the result returned by a bootstrap method to the class
360 * required by the bootstrap method's {@code invocationType}.
361 *
362 * @param type the method type or constant type to be obtained
363 * @param resultType the type of the result (return type of the BSM that returned the result)
364 * @param result the result to be converted
365 * @param <T> the type {@code MethodType} or {@code Class}
366 * @return the converted result
367 * @throws ClassCastException if a value conversion error occurs during conversion
368 * @throws WrongMethodTypeException if a method type mismatch is detected occurs during conversion
369 */
370 static
371 <T extends TypeDescriptor & Constable<T>>
372 Object convertResult(T type, Class<?> resultType, Object result) {
373 Class<?> resultClass;
374 boolean isFieldType;
375 if (type instanceof Class) {
376 isFieldType = true;
377 resultClass = (Class<?>) type;
378 } else {
379 isFieldType = false;
380 resultClass = null;
381 }
382 if (isFieldType && resultClass.isPrimitive()) {
383 Class<?> wrapperClass = Wrapper.asWrapperType(resultClass);
384 if (result.getClass() == wrapperClass) {
385 return result; // fast path
386 }
387 // Non-reference conversions are more than just plain casts.
388 // By pushing the value through a funnel of the form (R x)->x,
389 // the boxed result can be widened as needed. See MH::asType.
390 MethodHandle funnel = MethodHandles.identity(resultClass);
391 if (!MethodType.canConvert(resultType, resultClass)) {
392 // Example: Result type is Integer and resultClass is short.
393 funnel = funnel.asType(MethodType.methodType(resultClass, resultType));
394 assert(false); // should have thrown WMTE
395 }
396 try {
397 result = funnel.invoke(result);
398 } catch (ClassCastException | WrongMethodTypeException ex) {
399 throw ex;
400 } catch (Throwable ex) {
401 throw new InternalError(ex);
402 }
403 // Now it is the wrapper type for resultType.
404 assert(result.getClass() == Wrapper.asWrapperType(resultClass));
405 return result;
406 } else if (isFieldType) {
407 // A reference type.
408 return resultClass.cast(result);
409 } else {
410 // Check or convert the method-like result.
411 MethodType mt = (MethodType) type; // must be either Class or MethodType
412 if (result instanceof CallSite) {
413 CallSite cs = (CallSite) result;
414 if (!cs.type().equals(mt))
415 throw CallSite.wrongTargetType(cs, mt);
416 return cs; // no conversion, just checking
417 }
418 if (result instanceof MethodHandle) {
419 // Method handles can be converted on the fly:
420 MethodHandle mh = (MethodHandle) result;
421 return mh.asType(mt);
422 }
423 throw new ClassCastException("CallSite bootstrap method failed to produce an instance of CallSite");
424 }
425 }
426
427 /**
428 * Produce a string that briefly reports the BSM, name, type,
429 * and argument list. For arguments, use a non-resolving list view,
430 * with unresolved elements being presented as asterisks.
431 * @param bsci the object to produce a string for
432 * @return {@code this.asList("*").toString()}
433 */
434 public static String toString(BootstrapCallInfo<?> bsci) {
435 MethodHandle bsm = bsci.bootstrapMethod();
436 MemberName mem = bsm.internalMemberName();
437 Object bsmStr = bsm;
438 if (mem != null) bsmStr = mem;
439 //bsmStr = bsm.describeConstable()
440 Object typeStr = null;
441 try {
442 typeStr = bsci.invocationType();
443 } catch (LinkageError ex) {
444 typeStr = bsci.invocationTypeDesc();
445 }
446 return (bsmStr
447 + "/" + bsci.invocationName()
448 + ":" + typeStr
449 + bsci.argumentList("*"));
450 }
451 }
|