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