1 /* 2 * Copyright (c) 2017, 2020, 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 static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError; 30 import static java.util.Objects.requireNonNull; 31 32 /** 33 * Bootstrap methods for dynamically-computed constants. 34 * 35 * <p>The bootstrap methods in this class will throw a 36 * {@code NullPointerException} for any reference argument that is {@code null}, 37 * unless the argument is specified to be unused or specified to accept a 38 * {@code null} value. 39 * 40 * @since 11 41 */ 42 public final class ConstantBootstraps { 43 /** 44 * Do not call. 45 */ ConstantBootstraps()46 private ConstantBootstraps() {throw new AssertionError();} 47 48 // implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant: 49 /*non-public*/ makeConstant(MethodHandle bootstrapMethod, String name, Class<?> type, Object info, Class<?> callerClass)50 static Object makeConstant(MethodHandle bootstrapMethod, 51 // Callee information: 52 String name, Class<?> type, 53 // Extra arguments for BSM, if any: 54 Object info, 55 // Caller information: 56 Class<?> callerClass) { 57 // Restrict bootstrap methods to those whose first parameter is Lookup 58 // The motivation here is, in the future, to possibly support BSMs 59 // that do not accept the meta-data of lookup/name/type, thereby 60 // allowing the co-opting of existing methods to be used as BSMs as 61 // long as the static arguments can be passed as method arguments 62 MethodType mt = bootstrapMethod.type(); 63 if (mt.parameterCount() < 2 || 64 !MethodHandles.Lookup.class.isAssignableFrom(mt.parameterType(0))) { 65 throw new BootstrapMethodError( 66 "Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod); 67 } 68 69 // BSMI.invoke handles all type checking and exception translation. 70 // If type is not a reference type, the JVM is expecting a boxed 71 // version, and will manage unboxing on the other side. 72 return BootstrapMethodInvoker.invoke( 73 type, bootstrapMethod, name, type, info, callerClass); 74 } 75 76 /** 77 * Returns a {@code null} object reference for the reference type specified 78 * by {@code type}. 79 * 80 * @param lookup unused 81 * @param name unused 82 * @param type a reference type 83 * @return a {@code null} value 84 * @throws IllegalArgumentException if {@code type} is not a reference type 85 */ nullConstant(MethodHandles.Lookup lookup, String name, Class<?> type)86 public static Object nullConstant(MethodHandles.Lookup lookup, String name, Class<?> type) { 87 if (requireNonNull(type).isPrimitive()) { 88 throw new IllegalArgumentException(String.format("not reference: %s", type)); 89 } 90 91 return null; 92 } 93 94 /** 95 * Returns a {@link Class} mirror for the primitive type whose type 96 * descriptor is specified by {@code name}. 97 * 98 * @param lookup unused 99 * @param name the descriptor (JVMS 4.3) of the desired primitive type 100 * @param type the required result type (must be {@code Class.class}) 101 * @return the {@link Class} mirror 102 * @throws IllegalArgumentException if the name is not a descriptor for a 103 * primitive type or the type is not {@code Class.class} 104 */ primitiveClass(MethodHandles.Lookup lookup, String name, Class<?> type)105 public static Class<?> primitiveClass(MethodHandles.Lookup lookup, String name, Class<?> type) { 106 requireNonNull(name); 107 requireNonNull(type); 108 if (type != Class.class) { 109 throw new IllegalArgumentException(); 110 } 111 if (name.length() != 1) { 112 throw new IllegalArgumentException(String.format("not primitive: %s", name)); 113 } 114 115 return Wrapper.forPrimitiveType(name.charAt(0)).primitiveType(); 116 } 117 118 /** 119 * Returns an {@code enum} constant of the type specified by {@code type} 120 * with the name specified by {@code name}. 121 * 122 * @param lookup the lookup context describing the class performing the 123 * operation (normally stacked by the JVM) 124 * @param name the name of the constant to return, which must exactly match 125 * an enum constant in the specified type. 126 * @param type the {@code Class} object describing the enum type for which 127 * a constant is to be returned 128 * @param <E> The enum type for which a constant value is to be returned 129 * @return the enum constant of the specified enum type with the 130 * specified name 131 * @throws IllegalAccessError if the declaring class or the field is not 132 * accessible to the class performing the operation 133 * @throws IllegalArgumentException if the specified enum type has 134 * no constant with the specified name, or the specified 135 * class object does not represent an enum type 136 * @see Enum#valueOf(Class, String) 137 */ enumConstant(MethodHandles.Lookup lookup, String name, Class<E> type)138 public static <E extends Enum<E>> E enumConstant(MethodHandles.Lookup lookup, String name, Class<E> type) { 139 requireNonNull(lookup); 140 requireNonNull(name); 141 requireNonNull(type); 142 validateClassAccess(lookup, type); 143 144 return Enum.valueOf(type, name); 145 } 146 147 /** 148 * Returns the value of a static final field. 149 * 150 * @param lookup the lookup context describing the class performing the 151 * operation (normally stacked by the JVM) 152 * @param name the name of the field 153 * @param type the type of the field 154 * @param declaringClass the class in which the field is declared 155 * @return the value of the field 156 * @throws IllegalAccessError if the declaring class or the field is not 157 * accessible to the class performing the operation 158 * @throws NoSuchFieldError if the specified field does not exist 159 * @throws IncompatibleClassChangeError if the specified field is not 160 * {@code final} 161 */ getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type, Class<?> declaringClass)162 public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type, 163 Class<?> declaringClass) { 164 requireNonNull(lookup); 165 requireNonNull(name); 166 requireNonNull(type); 167 requireNonNull(declaringClass); 168 169 MethodHandle mh; 170 try { 171 mh = lookup.findStaticGetter(declaringClass, name, type); 172 MemberName member = mh.internalMemberName(); 173 if (!member.isFinal()) { 174 throw new IncompatibleClassChangeError("not a final field: " + name); 175 } 176 } 177 catch (ReflectiveOperationException ex) { 178 throw mapLookupExceptionToError(ex); 179 } 180 181 // Since mh is a handle to a static field only instances of 182 // VirtualMachineError are anticipated to be thrown, such as a 183 // StackOverflowError or an InternalError from the j.l.invoke code 184 try { 185 return mh.invoke(); 186 } 187 catch (RuntimeException | Error e) { 188 throw e; 189 } 190 catch (Throwable e) { 191 throw new LinkageError("Unexpected throwable", e); 192 } 193 } 194 195 /** 196 * Returns the value of a static final field declared in the class which 197 * is the same as the field's type (or, for primitive-valued fields, 198 * declared in the wrapper class.) This is a simplified form of 199 * {@link #getStaticFinal(MethodHandles.Lookup, String, Class, Class)} 200 * for the case where a class declares distinguished constant instances of 201 * itself. 202 * 203 * @param lookup the lookup context describing the class performing the 204 * operation (normally stacked by the JVM) 205 * @param name the name of the field 206 * @param type the type of the field 207 * @return the value of the field 208 * @throws IllegalAccessError if the declaring class or the field is not 209 * accessible to the class performing the operation 210 * @throws NoSuchFieldError if the specified field does not exist 211 * @throws IncompatibleClassChangeError if the specified field is not 212 * {@code final} 213 * @see #getStaticFinal(MethodHandles.Lookup, String, Class, Class) 214 */ getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type)215 public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type) { 216 requireNonNull(type); 217 218 Class<?> declaring = type.isPrimitive() 219 ? Wrapper.forPrimitiveType(type).wrapperType() 220 : type; 221 return getStaticFinal(lookup, name, type, declaring); 222 } 223 224 225 /** 226 * Returns the result of invoking a method handle with the provided 227 * arguments. 228 * <p> 229 * This method behaves as if the method handle to be invoked is the result 230 * of adapting the given method handle, via {@link MethodHandle#asType}, to 231 * adjust the return type to the desired type. 232 * 233 * @param lookup unused 234 * @param name unused 235 * @param type the desired type of the value to be returned, which must be 236 * compatible with the return type of the method handle 237 * @param handle the method handle to be invoked 238 * @param args the arguments to pass to the method handle, as if with 239 * {@link MethodHandle#invokeWithArguments}. Each argument may be 240 * {@code null}. 241 * @return the result of invoking the method handle 242 * @throws WrongMethodTypeException if the handle's method type cannot be 243 * adjusted to take the given number of arguments, or if the handle's return 244 * type cannot be adjusted to the desired type 245 * @throws ClassCastException if an argument or the result produced by 246 * invoking the handle cannot be converted by reference casting 247 * @throws Throwable anything thrown by the method handle invocation 248 */ invoke(MethodHandles.Lookup lookup, String name, Class<?> type, MethodHandle handle, Object... args)249 public static Object invoke(MethodHandles.Lookup lookup, String name, Class<?> type, 250 MethodHandle handle, Object... args) throws Throwable { 251 requireNonNull(type); 252 requireNonNull(handle); 253 requireNonNull(args); 254 255 if (type != handle.type().returnType()) { 256 // Adjust the return type of the handle to be invoked while 257 // preserving variable arity if present 258 handle = handle.asType(handle.type().changeReturnType(type)). 259 withVarargs(handle.isVarargsCollector()); 260 } 261 262 return handle.invokeWithArguments(args); 263 } 264 265 /** 266 * Finds a {@link VarHandle} for an instance field. 267 * 268 * @param lookup the lookup context describing the class performing the 269 * operation (normally stacked by the JVM) 270 * @param name the name of the field 271 * @param type the required result type (must be {@code Class<VarHandle>}) 272 * @param declaringClass the class in which the field is declared 273 * @param fieldType the type of the field 274 * @return the {@link VarHandle} 275 * @throws IllegalAccessError if the declaring class or the field is not 276 * accessible to the class performing the operation 277 * @throws NoSuchFieldError if the specified field does not exist 278 * @throws IllegalArgumentException if the type is not {@code VarHandle} 279 */ fieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, Class<?> declaringClass, Class<?> fieldType)280 public static VarHandle fieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, 281 Class<?> declaringClass, Class<?> fieldType) { 282 requireNonNull(lookup); 283 requireNonNull(name); 284 requireNonNull(type); 285 requireNonNull(declaringClass); 286 requireNonNull(fieldType); 287 if (type != VarHandle.class) { 288 throw new IllegalArgumentException(); 289 } 290 291 try { 292 return lookup.findVarHandle(declaringClass, name, fieldType); 293 } 294 catch (ReflectiveOperationException e) { 295 throw mapLookupExceptionToError(e); 296 } 297 } 298 299 /** 300 * Finds a {@link VarHandle} for a static field. 301 * 302 * @param lookup the lookup context describing the class performing the 303 * operation (normally stacked by the JVM) 304 * @param name the name of the field 305 * @param type the required result type (must be {@code Class<VarHandle>}) 306 * @param declaringClass the class in which the field is declared 307 * @param fieldType the type of the field 308 * @return the {@link VarHandle} 309 * @throws IllegalAccessError if the declaring class or the field is not 310 * accessible to the class performing the operation 311 * @throws NoSuchFieldError if the specified field does not exist 312 * @throws IllegalArgumentException if the type is not {@code VarHandle} 313 */ staticFieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, Class<?> declaringClass, Class<?> fieldType)314 public static VarHandle staticFieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, 315 Class<?> declaringClass, Class<?> fieldType) { 316 requireNonNull(lookup); 317 requireNonNull(name); 318 requireNonNull(type); 319 requireNonNull(declaringClass); 320 requireNonNull(fieldType); 321 if (type != VarHandle.class) { 322 throw new IllegalArgumentException(); 323 } 324 325 try { 326 return lookup.findStaticVarHandle(declaringClass, name, fieldType); 327 } 328 catch (ReflectiveOperationException e) { 329 throw mapLookupExceptionToError(e); 330 } 331 } 332 333 /** 334 * Finds a {@link VarHandle} for an array type. 335 * 336 * @param lookup the lookup context describing the class performing the 337 * operation (normally stacked by the JVM) 338 * @param name unused 339 * @param type the required result type (must be {@code Class<VarHandle>}) 340 * @param arrayClass the type of the array 341 * @return the {@link VarHandle} 342 * @throws IllegalAccessError if the component type of the array is not 343 * accessible to the class performing the operation 344 * @throws IllegalArgumentException if the type is not {@code VarHandle} 345 */ arrayVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, Class<?> arrayClass)346 public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, 347 Class<?> arrayClass) { 348 requireNonNull(lookup); 349 requireNonNull(type); 350 requireNonNull(arrayClass); 351 if (type != VarHandle.class) { 352 throw new IllegalArgumentException(); 353 } 354 355 return MethodHandles.arrayElementVarHandle(validateClassAccess(lookup, arrayClass)); 356 } 357 358 /** 359 * Applies a conversion from a source type to a destination type. 360 * <p> 361 * Given a destination type {@code dstType} and an input 362 * value {@code value}, one of the following will happen: 363 * <ul> 364 * <li>If {@code dstType} is {@code void.class}, 365 * a {@link ClassCastException} is thrown. 366 * <li>If {@code dstType} is {@code Object.class}, {@code value} is returned as is. 367 * </ul> 368 * <p> 369 * Otherwise one of the following conversions is applied to {@code value}: 370 * <ol> 371 * <li>If {@code dstType} is a reference type, a reference cast 372 * is applied to {@code value} as if by calling {@code dstType.cast(value)}. 373 * <li>If {@code dstType} is a primitive type, then, if the runtime type 374 * of {@code value} is a primitive wrapper type (such as {@link Integer}), 375 * a Java unboxing conversion is applied {@jls 5.1.8} followed by a 376 * Java casting conversion {@jls 5.5} converting either directly to 377 * {@code dstType}, or, if {@code dstType} is {@code boolean}, 378 * to {@code int}, which is then converted to either {@code true} 379 * or {@code false} depending on whether the least-significant-bit 380 * is 1 or 0 respectively. If the runtime type of {@code value} is 381 * not a primitive wrapper type a {@link ClassCastException} is thrown. 382 * </ol> 383 * <p> 384 * The result is the same as when using the following code: 385 * <blockquote><pre>{@code 386 * MethodHandle id = MethodHandles.identity(dstType); 387 * MethodType mt = MethodType.methodType(dstType, Object.class); 388 * MethodHandle conv = MethodHandles.explicitCastArguments(id, mt); 389 * return conv.invoke(value); 390 * }</pre></blockquote> 391 * 392 * @param lookup unused 393 * @param name unused 394 * @param dstType the destination type of the conversion 395 * @param value the value to be converted 396 * @return the converted value 397 * @throws ClassCastException when {@code dstType} is {@code void}, 398 * when a cast per (1) fails, or when {@code dstType} is a primitive type 399 * and the runtime type of {@code value} is not a primitive wrapper type 400 * (such as {@link Integer}) 401 * 402 * @since 15 403 */ explicitCast(MethodHandles.Lookup lookup, String name, Class<?> dstType, Object value)404 public static Object explicitCast(MethodHandles.Lookup lookup, String name, Class<?> dstType, Object value) 405 throws ClassCastException { 406 if (dstType == void.class) 407 throw new ClassCastException("Can not convert to void"); 408 if (dstType == Object.class) 409 return value; 410 411 MethodHandle id = MethodHandles.identity(dstType); 412 MethodType mt = MethodType.methodType(dstType, Object.class); 413 MethodHandle conv = MethodHandles.explicitCastArguments(id, mt); 414 try { 415 return conv.invoke(value); 416 } catch (RuntimeException|Error e) { 417 throw e; // let specified CCE and other runtime exceptions/errors through 418 } catch (Throwable throwable) { 419 throw new InternalError(throwable); // Not specified, throw InternalError 420 } 421 } 422 validateClassAccess(MethodHandles.Lookup lookup, Class<T> type)423 private static <T> Class<T> validateClassAccess(MethodHandles.Lookup lookup, Class<T> type) { 424 try { 425 lookup.accessClass(type); 426 return type; 427 } 428 catch (ReflectiveOperationException ex) { 429 throw mapLookupExceptionToError(ex); 430 } 431 } 432 } 433