1 /* 2 * Copyright (c) 2017, 2019, 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 */ 46 @Deprecated(forRemoval=true, since="14") 47 public ConstantBootstraps() {} 48 49 // implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant: 50 /*non-public*/ 51 static Object makeConstant(MethodHandle bootstrapMethod, 52 // Callee information: 53 String name, Class<?> type, 54 // Extra arguments for BSM, if any: 55 Object info, 56 // Caller information: 57 Class<?> callerClass) { 58 // Restrict bootstrap methods to those whose first parameter is Lookup 59 // The motivation here is, in the future, to possibly support BSMs 60 // that do not accept the meta-data of lookup/name/type, thereby 61 // allowing the co-opting of existing methods to be used as BSMs as 62 // long as the static arguments can be passed as method arguments 63 MethodType mt = bootstrapMethod.type(); 64 if (mt.parameterCount() < 2 || 65 !MethodHandles.Lookup.class.isAssignableFrom(mt.parameterType(0))) { 66 throw new BootstrapMethodError( 67 "Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod); 68 } 69 70 // BSMI.invoke handles all type checking and exception translation. 71 // If type is not a reference type, the JVM is expecting a boxed 72 // version, and will manage unboxing on the other side. 73 return BootstrapMethodInvoker.invoke( 74 type, bootstrapMethod, name, type, info, callerClass); 75 } 76 77 /** 78 * Returns a {@code null} object reference for the reference type specified 79 * by {@code type}. 80 * 81 * @param lookup unused 82 * @param name unused 83 * @param type a reference type 84 * @return a {@code null} value 85 * @throws IllegalArgumentException if {@code type} is not a reference type 86 */ 87 public static Object nullConstant(MethodHandles.Lookup lookup, String name, Class<?> type) { 88 if (requireNonNull(type).isPrimitive()) { 89 throw new IllegalArgumentException(String.format("not reference: %s", type)); 90 } 91 92 return null; 93 } 94 95 /** 96 * Returns a {@link Class} mirror for the primitive type whose type 97 * descriptor is specified by {@code name}. 98 * 99 * @param lookup unused 100 * @param name the descriptor (JVMS 4.3) of the desired primitive type 101 * @param type the required result type (must be {@code Class.class}) 102 * @return the {@link Class} mirror 103 * @throws IllegalArgumentException if the name is not a descriptor for a 104 * primitive type or the type is not {@code Class.class} 105 */ 106 public static Class<?> primitiveClass(MethodHandles.Lookup lookup, String name, Class<?> type) { 107 requireNonNull(name); 108 requireNonNull(type); 109 if (type != Class.class) { 110 throw new IllegalArgumentException(); 111 } 112 if (name.length() != 1) { 113 throw new IllegalArgumentException(String.format("not primitive: %s", name)); 114 } 115 116 return Wrapper.forPrimitiveType(name.charAt(0)).primitiveType(); 117 } 118 119 /** 120 * Returns an {@code enum} constant of the type specified by {@code type} 121 * with the name specified by {@code name}. 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 constant to return, which must exactly match 126 * an enum constant in the specified type. 127 * @param type the {@code Class} object describing the enum type for which 128 * a constant is to be returned 129 * @param <E> The enum type for which a constant value is to be returned 130 * @return the enum constant of the specified enum type with the 131 * specified name 132 * @throws IllegalAccessError if the declaring class or the field is not 133 * accessible to the class performing the operation 134 * @throws IllegalArgumentException if the specified enum type has 135 * no constant with the specified name, or the specified 136 * class object does not represent an enum type 137 * @see Enum#valueOf(Class, String) 138 */ 139 public static <E extends Enum<E>> E enumConstant(MethodHandles.Lookup lookup, String name, Class<E> type) { 140 requireNonNull(lookup); 141 requireNonNull(name); 142 requireNonNull(type); 143 validateClassAccess(lookup, type); 144 145 return Enum.valueOf(type, name); 146 } 147 148 /** 149 * Returns the value of a static final field. 150 * 151 * @param lookup the lookup context describing the class performing the 152 * operation (normally stacked by the JVM) 153 * @param name the name of the field 154 * @param type the type of the field 155 * @param declaringClass the class in which the field is declared 156 * @return the value of the field 157 * @throws IllegalAccessError if the declaring class or the field is not 158 * accessible to the class performing the operation 159 * @throws NoSuchFieldError if the specified field does not exist 160 * @throws IncompatibleClassChangeError if the specified field is not 161 * {@code final} 162 */ 163 public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type, 164 Class<?> declaringClass) { 165 requireNonNull(lookup); 166 requireNonNull(name); 167 requireNonNull(type); 168 requireNonNull(declaringClass); 169 170 MethodHandle mh; 171 try { 172 mh = lookup.findStaticGetter(declaringClass, name, type); 173 MemberName member = mh.internalMemberName(); 174 if (!member.isFinal()) { 175 throw new IncompatibleClassChangeError("not a final field: " + name); 176 } 177 } 178 catch (ReflectiveOperationException ex) { 179 throw mapLookupExceptionToError(ex); 180 } 181 182 // Since mh is a handle to a static field only instances of 183 // VirtualMachineError are anticipated to be thrown, such as a 184 // StackOverflowError or an InternalError from the j.l.invoke code 185 try { 186 return mh.invoke(); 187 } 188 catch (RuntimeException | Error e) { 189 throw e; 190 } 191 catch (Throwable e) { 192 throw new LinkageError("Unexpected throwable", e); 193 } 194 } 195 196 /** 197 * Returns the value of a static final field declared in the class which 198 * is the same as the field's type (or, for primitive-valued fields, 199 * declared in the wrapper class.) This is a simplified form of 200 * {@link #getStaticFinal(MethodHandles.Lookup, String, Class, Class)} 201 * for the case where a class declares distinguished constant instances of 202 * itself. 203 * 204 * @param lookup the lookup context describing the class performing the 205 * operation (normally stacked by the JVM) 206 * @param name the name of the field 207 * @param type the type of the field 208 * @return the value of the field 209 * @throws IllegalAccessError if the declaring class or the field is not 210 * accessible to the class performing the operation 211 * @throws NoSuchFieldError if the specified field does not exist 212 * @throws IncompatibleClassChangeError if the specified field is not 213 * {@code final} 214 * @see #getStaticFinal(MethodHandles.Lookup, String, Class, Class) 215 */ 216 public static Object getStaticFinal(MethodHandles.Lookup lookup, String name, Class<?> type) { 217 requireNonNull(type); 218 219 Class<?> declaring = type.isPrimitive() 220 ? Wrapper.forPrimitiveType(type).wrapperType() 221 : type; 222 return getStaticFinal(lookup, name, type, declaring); 223 } 224 225 226 /** 227 * Returns the result of invoking a method handle with the provided 228 * arguments. 229 * <p> 230 * This method behaves as if the method handle to be invoked is the result 231 * of adapting the given method handle, via {@link MethodHandle#asType}, to 232 * adjust the return type to the desired type. 233 * 234 * @param lookup unused 235 * @param name unused 236 * @param type the desired type of the value to be returned, which must be 237 * compatible with the return type of the method handle 238 * @param handle the method handle to be invoked 239 * @param args the arguments to pass to the method handle, as if with 240 * {@link MethodHandle#invokeWithArguments}. Each argument may be 241 * {@code null}. 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 public static Object invoke(MethodHandles.Lookup lookup, String name, Class<?> type, 251 MethodHandle handle, Object... args) throws Throwable { 252 requireNonNull(type); 253 requireNonNull(handle); 254 requireNonNull(args); 255 256 if (type != handle.type().returnType()) { 257 // Adjust the return type of the handle to be invoked while 258 // preserving variable arity if present 259 handle = handle.asType(handle.type().changeReturnType(type)). 260 withVarargs(handle.isVarargsCollector()); 261 } 262 263 return handle.invokeWithArguments(args); 264 } 265 266 /** 267 * Finds a {@link VarHandle} for an instance field. 268 * 269 * @param lookup the lookup context describing the class performing the 270 * operation (normally stacked by the JVM) 271 * @param name the name of the field 272 * @param type the required result type (must be {@code Class<VarHandle>}) 273 * @param declaringClass the class in which the field is declared 274 * @param fieldType the type of the field 275 * @return the {@link VarHandle} 276 * @throws IllegalAccessError if the declaring class or the field is not 277 * accessible to the class performing the operation 278 * @throws NoSuchFieldError if the specified field does not exist 279 * @throws IllegalArgumentException if the type is not {@code VarHandle} 280 */ 281 public static VarHandle fieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, 282 Class<?> declaringClass, Class<?> fieldType) { 283 requireNonNull(lookup); 284 requireNonNull(name); 285 requireNonNull(type); 286 requireNonNull(declaringClass); 287 requireNonNull(fieldType); 288 if (type != VarHandle.class) { 289 throw new IllegalArgumentException(); 290 } 291 292 try { 293 return lookup.findVarHandle(declaringClass, name, fieldType); 294 } 295 catch (ReflectiveOperationException e) { 296 throw mapLookupExceptionToError(e); 297 } 298 } 299 300 /** 301 * Finds a {@link VarHandle} for a static field. 302 * 303 * @param lookup the lookup context describing the class performing the 304 * operation (normally stacked by the JVM) 305 * @param name the name of the field 306 * @param type the required result type (must be {@code Class<VarHandle>}) 307 * @param declaringClass the class in which the field is declared 308 * @param fieldType the type of the field 309 * @return the {@link VarHandle} 310 * @throws IllegalAccessError if the declaring class or the field is not 311 * accessible to the class performing the operation 312 * @throws NoSuchFieldError if the specified field does not exist 313 * @throws IllegalArgumentException if the type is not {@code VarHandle} 314 */ 315 public static VarHandle staticFieldVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, 316 Class<?> declaringClass, Class<?> fieldType) { 317 requireNonNull(lookup); 318 requireNonNull(name); 319 requireNonNull(type); 320 requireNonNull(declaringClass); 321 requireNonNull(fieldType); 322 if (type != VarHandle.class) { 323 throw new IllegalArgumentException(); 324 } 325 326 try { 327 return lookup.findStaticVarHandle(declaringClass, name, fieldType); 328 } 329 catch (ReflectiveOperationException e) { 330 throw mapLookupExceptionToError(e); 331 } 332 } 333 334 /** 335 * Finds a {@link VarHandle} for an array type. 336 * 337 * @param lookup the lookup context describing the class performing the 338 * operation (normally stacked by the JVM) 339 * @param name unused 340 * @param type the required result type (must be {@code Class<VarHandle>}) 341 * @param arrayClass the type of the array 342 * @return the {@link VarHandle} 343 * @throws IllegalAccessError if the component type of the array is not 344 * accessible to the class performing the operation 345 * @throws IllegalArgumentException if the type is not {@code VarHandle} 346 */ 347 public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, String name, Class<VarHandle> type, 348 Class<?> arrayClass) { 349 requireNonNull(lookup); 350 requireNonNull(type); 351 requireNonNull(arrayClass); 352 if (type != VarHandle.class) { 353 throw new IllegalArgumentException(); 354 } 355 356 return MethodHandles.arrayElementVarHandle(validateClassAccess(lookup, arrayClass)); 357 } 358 359 private static <T> Class<T> validateClassAccess(MethodHandles.Lookup lookup, Class<T> type) { 360 try { 361 lookup.accessClass(type); 362 return type; 363 } 364 catch (ReflectiveOperationException ex) { 365 throw mapLookupExceptionToError(ex); 366 } 367 } 368 }