1 /* 2 * Copyright (c) 2017, 2018, 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.invoke; 26 27 import sun.invoke.util.Wrapper; 28 29 import java.lang.constant.ConstantDesc; 30 import java.util.Arrays; 31 32 import static java.lang.invoke.AbstractBootstrapCallInfo.maybeShareArguments; 33 import static java.lang.invoke.BootstrapMethodInvoker.invokeCommon; 34 import static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError; 35 import static java.lang.invoke.MethodHandles.Lookup; 36 import static java.util.Objects.requireNonNull; 37 38 /** 39 * Bootstrap methods for dynamically-computed constants. 40 * 41 * <p>The bootstrap methods in this class will throw a 42 * {@code NullPointerException} for any reference argument that is {@code null}, 43 * unless the argument is specified to be unused or specified to accept a 44 * {@code null} value. 45 * 46 * @since 11 47 */ 48 public final class ConstantBootstraps { 49 /** 50 * Returns a {@code null} object reference for the reference type specified 51 * by {@code type}. 52 * 53 * @param lookup unused 54 * @param name unused 55 * @param type a reference type 56 * @return a {@code null} value 57 * @throws IllegalArgumentException if {@code type} is not a reference type 58 */ 59 public static Object nullConstant(MethodHandles.Lookup lookup, String name, Class<?> type) { 60 if (requireNonNull(type).isPrimitive()) { 61 throw new IllegalArgumentException(String.format("not reference: %s", type)); 62 } 63 64 return null; 65 } 66 67 /** 68 * Returns a {@link Class} mirror for the primitive type whose type 69 * descriptor is specified by {@code name}. 70 * 71 * @param lookup unused 72 * @param name the descriptor (JVMS 4.3) of the desired primitive type 73 * @param type the required result type (must be {@code Class.class}) 74 * @return the {@link Class} mirror 75 * @throws IllegalArgumentException if the name is not a descriptor for a 76 * primitive type or the type is not {@code Class.class} 77 */ 78 public static Class<?> primitiveClass(MethodHandles.Lookup lookup, String name, Class<?> type) { 79 requireNonNull(name); 80 requireNonNull(type); 81 if (type != Class.class) { 82 throw new IllegalArgumentException(); 83 } 84 if (name.length() == 0 || name.length() > 1) { 85 throw new IllegalArgumentException(String.format("not primitive: %s", name)); 86 } 87 88 return Wrapper.forPrimitiveType(name.charAt(0)).primitiveType(); 89 } 90 91 /** 92 * Returns an {@code enum} constant of the type specified by {@code type} 93 * with the name specified by {@code name}. 94 * 95 * @param lookup the lookup context describing the class performing the 96 * operation (normally stacked by the JVM) 97 * @param name the name of the constant to return, which must exactly match 98 * an enum constant in the specified type. 99 * @param type the {@code Class} object describing the enum type for which 100 * a constant is to be returned 101 * @param <E> The enum type for which a constant value is to be returned 102 * @return the enum constant of the specified enum type with the 103 * specified name 104 * @throws IllegalAccessError if the declaring class or the field is not 105 * accessible to the class performing the operation 106 * @throws IllegalArgumentException if the specified enum type has 107 * no constant with the specified name, or the specified 108 * class object does not represent an enum type 109 * @see Enum#valueOf(Class, String) 110 */ 111 public static <E extends Enum<E>> E enumConstant(MethodHandles.Lookup lookup, String name, Class<E> type) { 112 requireNonNull(lookup); 113 requireNonNull(name); 114 requireNonNull(type); 115 validateClassAccess(lookup, type); 116 117 return Enum.valueOf(type, name); 118 } 119 120 /** 121 * Returns the value of a static final field. 122 * 123 * @param lookup the lookup context describing the class performing the 124 * operation (normally stacked by the JVM) 125 * @param name the name of the field 126 * @param type the type of the field 127 * @param declaringClass the class in which the field is declared 128 * @return the value of the field 129 * @throws IllegalAccessError if the declaring class or the field is not 130 * accessible to the class performing the operation 131 * @throws NoSuchFieldError if the specified field does not exist 132 * @throws IncompatibleClassChangeError if the specified field is not 133 * {@code final} 134 */ 135 public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type, 136 Class<?> declaringClass) { 137 requireNonNull(lookup); 138 requireNonNull(name); 139 requireNonNull(type); 140 requireNonNull(declaringClass); 141 142 MethodHandle mh; 143 try { 144 mh = lookup.findStaticGetter(declaringClass, name, type); 145 MemberName member = mh.internalMemberName(); 146 if (!member.isFinal()) { 147 throw new IncompatibleClassChangeError("not a final field: " + name); 148 } 149 } 150 catch (ReflectiveOperationException ex) { 151 throw mapLookupExceptionToError(ex); 152 } 153 154 // Since mh is a handle to a static field only instances of 155 // VirtualMachineError are anticipated to be thrown, such as a 156 // StackOverflowError or an InternalError from the j.l.invoke code 157 try { 158 return mh.invoke(); 159 } 160 catch (RuntimeException | Error e) { 161 throw e; 162 } 163 catch (Throwable e) { 164 throw new LinkageError("Unexpected throwable", e); 165 } 166 } 167 168 /** 169 * Returns the value of a static final field declared in the class which 170 * is the same as the field's type (or, for primitive-valued fields, 171 * declared in the wrapper class.) This is a simplified form of 172 * {@link #getStaticFinal(MethodHandles.Lookup, String, Class, Class)} 173 * for the case where a class declares distinguished constant instances of 174 * itself. 175 * 176 * @param lookup the lookup context describing the class performing the 177 * operation (normally stacked by the JVM) 178 * @param name the name of the field 179 * @param type the type of the field 180 * @return the value of the field 181 * @throws IllegalAccessError if the declaring class or the field is not 182 * accessible to the class performing the operation 183 * @throws NoSuchFieldError if the specified field does not exist 184 * @throws IncompatibleClassChangeError if the specified field is not 185 * {@code final} 186 * @see #getStaticFinal(MethodHandles.Lookup, String, Class, Class) 187 */ 188 public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type) { 189 requireNonNull(type); 190 191 Class<?> declaring = type.isPrimitive() 192 ? Wrapper.forPrimitiveType(type).wrapperType() 193 : type; 194 return getStaticFinal(lookup, name, type, declaring); 195 } 196 197 198 /** 199 * Returns the result of invoking a bootstrap method handle on static 200 * arguments, but without metadata. 201 * <p> 202 * This method behaves as if the method handle to be invoked is the result 203 * of adapting the given method handle, via {@link MethodHandle#asType}, to 204 * adjust the return type to {@code invocationType} of the bootstrap call. 205 * 206 * @param lookup unused 207 * @param name unused 208 * @param type the desired type of the value to be returned, which must be 209 * compatible with the return type of the method handle 210 * @param handle the method handle to be invoked 211 * @param args the arguments to pass to the method handle, as if with 212 * {@link MethodHandle#invokeWithArguments}. Each argument may be 213 * {@code null}. 214 * @return the result of invoking the method handle 215 * @throws WrongMethodTypeException if the handle's method type cannot be 216 * adjusted to take the given number of arguments, or if the handle's return 217 * type cannot be adjusted to the desired type 218 * @throws ClassCastException if an argument or the result produced by 219 * invoking the handle cannot be converted by reference casting 220 * @throws Throwable anything thrown by the method handle invocation 221 */ 222 public static Object invoke(MethodHandles.Lookup lookup, String name, Class<?> type, 223 MethodHandle handle, Object... args) throws Throwable { 224 requireNonNull(type); 225 requireNonNull(handle); 226 requireNonNull(args); 227 228 Object result = invokeCommon(handle, null, null, null, args, null); 229 return BootstrapCallInfo.convertResult(type, handle.type().returnType(), result); 230 } 231 232 /** 233 * Returns the result of invoking a bootstrap method handle on static 234 * arguments, but without metadata. 235 * <p> 236 * This method behaves as if the method handle to be invoked is the result 237 * of adapting the given method handle, via {@link MethodHandle#asType}, to 238 * adjust the return type to {@code invocationType} of the bootstrap call. 239 * 240 * @param lookup unused 241 * @param bsci the container of the bootstrap method 242 * @return the result of invoking the method handle 243 * @throws WrongMethodTypeException if the handle's method type cannot be 244 * adjusted to take the given number of arguments, or if the handle's return 245 * type cannot be adjusted to the desired type 246 * @throws ClassCastException if an argument or the result produced by 247 * invoking the handle cannot be converted by reference casting 248 * @throws Throwable anything thrown by the method handle invocation 249 */ 250 // not public until BootstrapCallInfo is public 251 static Object invoke(MethodHandles.Lookup lookup, BootstrapCallInfo<?> bsci) throws Throwable { 252 MethodHandle bsm = bsci.bootstrapMethod(); 253 Object result = invokeCommon(bsm, 254 null, null, null, 255 maybeShareArguments(bsci), 256 bsci.argumentList()); 257 return BootstrapCallInfo.convertResult((Class<?>) bsci.invocationType(), bsm.type().returnType(), result); 258 } 259 260 /** 261 * Returns the result of invoking a bootstrap method handle on static 262 * arguments, but without metadata. In addition, any arguments of type 263 * {@code Object} or of any type assignable to {@code ConstantDesc} will 264 * be provided symbolic references, rather than resolved values, for 265 * the corresponding static arguments. 266 * <p> 267 * Finally, any single argument of type {@code Lookup} will be passed the 268 * lookup object directly, rather than either a symbolic reference or 269 * resolved argument value. 270 * <p> 271 * This method behaves as if the method handle to be invoked is the result 272 * of adapting the given method handle, via {@link MethodHandle#asType}, to 273 * adjust the return type to {@code invocationType} of the bootstrap call. 274 * 275 * @param lookup unused 276 * @param bsci the container of the bootstrap method 277 * @return the result of invoking the method handle 278 * @throws WrongMethodTypeException if the handle's method type cannot be 279 * adjusted to take the given number of arguments, or if the handle's return 280 * type cannot be adjusted to the desired type 281 * @throws ClassCastException if an argument or the result produced by 282 * invoking the handle cannot be converted by reference casting 283 * @throws Throwable anything thrown by the method handle invocation 284 */ 285 // not public until BootstrapCallInfo is public 286 static Object symbolic(MethodHandles.Lookup lookup, BootstrapCallInfo<?> bsci) throws Throwable { 287 MethodHandle bsm = bsci.bootstrapMethod(); 288 MethodType bsmType = bsm.type(); 289 boolean passLookup = bsmType.parameterList().contains(Lookup.class); 290 Object[] argv = new Object[bsci.argumentCount() + (passLookup ? 1 : 0)]; 291 int pos = 0; 292 int maxPos = bsmType.parameterCount() - (bsm.isVarargsCollector() ? 1 : 0); 293 int bargPos = 0; 294 for (Class<?> ptype : bsmType.parameterList()) { 295 if (pos == maxPos) break; 296 if (ptype == Lookup.class && passLookup) { 297 argv[pos++] = lookup; 298 passLookup = false; 299 } else if (isSymbolicArgType(ptype)) { 300 argv[pos++] = bsci.argumentDesc(bargPos++); 301 } else { 302 argv[pos++] = bsci.argument(bargPos++); 303 } 304 } 305 Class<?> ptype = bsmType.lastParameterType().componentType(); 306 while (pos < argv.length) { 307 assert(ptype != null); 308 if (isSymbolicArgType(ptype)) { 309 argv[pos++] = bsci.argumentDesc(bargPos++); 310 } else { 311 argv[pos++] = bsci.argument(bargPos++); 312 } 313 } 314 Object result = invokeCommon(bsm, 315 null, null, null, 316 argv, null); 317 return BootstrapCallInfo.convertResult((Class<?>)bsci.invocationType(), bsmType.returnType(), result); 318 } 319 320 private static boolean isSymbolicArgType(Class<?> ptype) { 321 return (ptype == Object.class || ConstantDesc.class.isAssignableFrom(ptype)); 322 } 323 324 /** 325 * Trivial method which returns its sole argument, which must be a 326 * ConstantDesc of some sort. This method is useful as an 327 * expression-mode bootstrap method with the operation "symbolic". 328 * 329 * @param desc the value to be returned 330 * @param <T> the type of the value to be returned 331 * @return desc 332 * @see DynamicConstantDesc#ofSymbolic 333 */ 334 public static <T extends ConstantDesc<?>> T constantDesc(T desc) { 335 return desc; 336 } 337 338 /** 339 * Returns the result of invoking a bootstrap method handle in 340 * expression mode. The exact behavior of this mode depends on 341 * the {@code name} string. If the name is {@code "invoke"}, 342 * then the bootstrap method is applied directly to the arguments, 343 * as if it were the leading static argument to {@link #invoke}. 344 * If the name is {@code "symbolic"} then bootstrap arguments 345 * are extracted as unresolved symbolic references from the 346 * constant pool and returned. 347 * Other {@code name} strings are reserved for future use. 348 * <p> 349 * @apiNote 350 * This method behaves like the following: 351 * <blockquote><pre>{@code 352 String name = bsci.invocationName(); 353 switch (name) { 354 case "invoke": return invoke(lookup, bsci); 355 case "symbolic": return symbolic(lookup, bsci); 356 } 357 * }</pre></blockquote> 358 * <p> 359 * 360 * @param lookup must be non-null, otherwise presently unused 361 * @param bsci bootstrap call information 362 * @return the result of invoking the bootstrap method handle on appropriate arguments 363 * @throws WrongMethodTypeException if the handle's method type cannot be 364 * adjusted to take the given number of arguments, or if the handle's return 365 * type cannot be adjusted to the desired type 366 * @throws ClassCastException if an argument or the result produced by 367 * invoking the handle cannot be converted by reference casting 368 * @throws IllegalArgumentException if the {@code name} is invalid 369 * @throws Throwable anything thrown by an action selected by {@code name} 370 */ 371 // not public until BootstrapCallInfo is public 372 static Object linkExpression(MethodHandles.Lookup lookup, 373 BootstrapCallInfo<?> bsci) throws Throwable { 374 requireNonNull(lookup); 375 requireNonNull(bsci); 376 377 String name = bsci.invocationName(); 378 switch (name) { 379 case "invoke": return invoke(lookup, bsci); 380 case "symbolic": return symbolic(lookup, bsci); 381 } 382 383 throw new IllegalArgumentException("invalid name for expression-mode constant: "+bsci); 384 } 385 386 /** 387 * Finds a {@link VarHandle} for an instance field. 388 * 389 * @param lookup the lookup context describing the class performing the 390 * operation (normally stacked by the JVM) 391 * @param name the name of the field 392 * @param type the required result type (must be {@code Class<VarHandle>}) 393 * @param declaringClass the class in which the field is declared 394 * @param fieldType the type of the field 395 * @return the {@link VarHandle} 396 * @throws IllegalAccessError if the declaring class or the field is not 397 * accessible to the class performing the operation 398 * @throws NoSuchFieldError if the specified field does not exist 399 * @throws IllegalArgumentException if the type is not {@code VarHandle} 400 */ 401 public static VarHandle fieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, 402 Class<?> declaringClass, Class<?> fieldType) { 403 requireNonNull(lookup); 404 requireNonNull(name); 405 requireNonNull(type); 406 requireNonNull(declaringClass); 407 requireNonNull(fieldType); 408 if (type != VarHandle.class) { 409 throw new IllegalArgumentException(); 410 } 411 412 try { 413 return lookup.findVarHandle(declaringClass, name, fieldType); 414 } 415 catch (ReflectiveOperationException e) { 416 throw mapLookupExceptionToError(e); 417 } 418 } 419 420 /** 421 * Finds a {@link VarHandle} for a static field. 422 * 423 * @param lookup the lookup context describing the class performing the 424 * operation (normally stacked by the JVM) 425 * @param name the name of the field 426 * @param type the required result type (must be {@code Class<VarHandle>}) 427 * @param declaringClass the class in which the field is declared 428 * @param fieldType the type of the field 429 * @return the {@link VarHandle} 430 * @throws IllegalAccessError if the declaring class or the field is not 431 * accessible to the class performing the operation 432 * @throws NoSuchFieldError if the specified field does not exist 433 * @throws IllegalArgumentException if the type is not {@code VarHandle} 434 */ 435 public static VarHandle staticFieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, 436 Class<?> declaringClass, Class<?> fieldType) { 437 requireNonNull(lookup); 438 requireNonNull(name); 439 requireNonNull(type); 440 requireNonNull(declaringClass); 441 requireNonNull(fieldType); 442 if (type != VarHandle.class) { 443 throw new IllegalArgumentException(); 444 } 445 446 try { 447 return lookup.findStaticVarHandle(declaringClass, name, fieldType); 448 } 449 catch (ReflectiveOperationException e) { 450 throw mapLookupExceptionToError(e); 451 } 452 } 453 454 /** 455 * Finds a {@link VarHandle} for an array type. 456 * 457 * @param lookup the lookup context describing the class performing the 458 * operation (normally stacked by the JVM) 459 * @param name unused 460 * @param type the required result type (must be {@code Class<VarHandle>}) 461 * @param arrayClass the type of the array 462 * @return the {@link VarHandle} 463 * @throws IllegalAccessError if the component type of the array is not 464 * accessible to the class performing the operation 465 * @throws IllegalArgumentException if the type is not {@code VarHandle} 466 */ 467 public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, 468 Class<?> arrayClass) { 469 requireNonNull(lookup); 470 requireNonNull(type); 471 requireNonNull(arrayClass); 472 if (type != VarHandle.class) { 473 throw new IllegalArgumentException(); 474 } 475 476 return MethodHandles.arrayElementVarHandle(validateClassAccess(lookup, arrayClass)); 477 } 478 479 private static <T> Class<T> validateClassAccess(MethodHandles.Lookup lookup, Class<T> type) { 480 try { 481 lookup.accessClass(type); 482 return type; 483 } 484 catch (ReflectiveOperationException ex) { 485 throw mapLookupExceptionToError(ex); 486 } 487 } 488 }