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