1 /* 2 * Copyright (c) 2017, 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 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 }