1 /* 2 * Copyright (c) 2010, 2013, 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 26 package jdk.nashorn.internal.runtime.linker; 27 28 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL; 29 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; 30 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; 31 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; 32 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER; 33 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS; 34 import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL; 35 import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; 36 import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE; 37 import static jdk.internal.org.objectweb.asm.Opcodes.DUP; 38 import static jdk.internal.org.objectweb.asm.Opcodes.IFNONNULL; 39 import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD; 40 import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE; 41 import static jdk.internal.org.objectweb.asm.Opcodes.POP; 42 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; 43 import static jdk.nashorn.internal.lookup.Lookup.MH; 44 import static jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome.ERROR_NO_ACCESSIBLE_CONSTRUCTOR; 45 46 import java.lang.invoke.MethodHandle; 47 import java.lang.invoke.MethodType; 48 import java.lang.reflect.AccessibleObject; 49 import java.lang.reflect.Constructor; 50 import java.lang.reflect.Method; 51 import java.lang.reflect.Modifier; 52 import java.security.AccessControlContext; 53 import java.security.AccessController; 54 import java.security.PrivilegedAction; 55 import java.util.Arrays; 56 import java.util.Collection; 57 import java.util.HashSet; 58 import java.util.Iterator; 59 import java.util.List; 60 import java.util.Set; 61 import jdk.internal.org.objectweb.asm.ClassWriter; 62 import jdk.internal.org.objectweb.asm.Handle; 63 import jdk.internal.org.objectweb.asm.Label; 64 import jdk.internal.org.objectweb.asm.Opcodes; 65 import jdk.internal.org.objectweb.asm.Type; 66 import jdk.internal.org.objectweb.asm.commons.InstructionAdapter; 67 import jdk.nashorn.internal.objects.Global; 68 import jdk.nashorn.internal.runtime.Context; 69 import jdk.nashorn.internal.runtime.ScriptFunction; 70 import jdk.nashorn.internal.runtime.ScriptObject; 71 import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome; 72 import sun.reflect.CallerSensitive; 73 74 /** 75 * Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}. 76 * </p><p> 77 * For every protected or public constructor in the extended class, the adapter class will have either one or two 78 * public constructors (visibility of protected constructors in the extended class is promoted to public). 79 * <li> 80 * <li>For adapter classes with instance-level overrides, a constructor taking a trailing ScriptObject argument preceded 81 * by original constructor arguments is always created on the adapter class. When such a constructor is invoked, the 82 * passed ScriptObject's member functions are used to implement and/or override methods on the original class, 83 * dispatched by name. A single JavaScript function will act as the implementation for all overloaded methods of the 84 * same name. When methods on an adapter instance are invoked, the functions are invoked having the ScriptObject passed 85 * in the instance constructor as their "this". Subsequent changes to the ScriptObject (reassignment or removal of its 86 * functions) are not reflected in the adapter instance; the method implementations are bound to functions at 87 * constructor invocation time. 88 * {@code java.lang.Object} methods {@code equals}, {@code hashCode}, and {@code toString} can also be overridden. The 89 * only restriction is that since every JavaScript object already has a {@code toString} function through the 90 * {@code Object.prototype}, the {@code toString} in the adapter is only overridden if the passed ScriptObject has a 91 * {@code toString} function as its own property, and not inherited from a prototype. All other adapter methods can be 92 * implemented or overridden through a prototype-inherited function of the ScriptObject passed to the constructor too. 93 * </li> 94 * <li> 95 * If the original types collectively have only one abstract method, or have several of them, but all share the 96 * same name, an additional constructor for instance-level override adapter is provided for every original constructor; 97 * this one takes a ScriptFunction as its last argument preceded by original constructor arguments. This constructor 98 * will use the passed function as the implementation for all abstract methods. For consistency, any concrete methods 99 * sharing the single abstract method name will also be overridden by the function. When methods on the adapter instance 100 * are invoked, the ScriptFunction is invoked with UNDEFINED or Global as its "this" depending whether the function is 101 * strict or not. 102 * </li> 103 * <li> 104 * If the adapter being generated can have class-level overrides, constructors taking same arguments as the superclass 105 * constructors are created. These constructors simply delegate to the superclass constructor. They are simply used to 106 * create instances of the adapter class, with no instance-level overrides, as they don't have them. 107 * </li> 108 * </ul> 109 * </p><p> 110 * For adapter methods that return values, all the JavaScript-to-Java conversions supported by Nashorn will be in effect 111 * to coerce the JavaScript function return value to the expected Java return type. 112 * </p><p> 113 * Since we are adding a trailing argument to the generated constructors in the adapter class, they will never be 114 * declared as variable arity, even if the original constructor in the superclass was declared as variable arity. The 115 * reason we are passing the additional argument at the end of the argument list instead at the front is that the 116 * source-level script expression <code>new X(a, b) { ... }</code> (which is a proprietary syntax extension Nashorn uses 117 * to resemble Java anonymous classes) is actually equivalent to <code>new X(a, b, { ... })</code>. 118 * </p><p> 119 * It is possible to create two different adapter classes: those that can have class-level overrides, and those that can 120 * have instance-level overrides. When {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked 121 * with non-null {@code classOverrides} parameter, an adapter class is created that can have class-level overrides, and 122 * the passed script object will be used as the implementations for its methods, just as in the above case of the 123 * constructor taking a script object. Note that in the case of class-level overrides, a new adapter class is created on 124 * every invocation, and the implementation object is bound to the class, not to any instance. All created instances 125 * will share these functions. If it is required to have both class-level overrides and instance-level overrides, the 126 * class-level override adapter class should be subclassed with an instance-override adapter. Since adapters delegate to 127 * super class when an overriding method handle is not specified, this will behave as expected. It is not possible to 128 * have both class-level and instance-level overrides in the same class for security reasons: adapter classes are 129 * defined with a protection domain of their creator code, and an adapter class that has both class and instance level 130 * overrides would need to have two potentially different protection domains: one for class-based behavior and one for 131 * instance-based behavior; since Java classes can only belong to a single protection domain, this could not be 132 * implemented securely. 133 */ 134 final class JavaAdapterBytecodeGenerator { 135 static final Type CONTEXT_TYPE = Type.getType(Context.class); 136 static final Type OBJECT_TYPE = Type.getType(Object.class); 137 static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class); 138 static final Type GLOBAL_TYPE = Type.getType(Global.class); 139 140 static final String CONTEXT_TYPE_NAME = CONTEXT_TYPE.getInternalName(); 141 static final String OBJECT_TYPE_NAME = OBJECT_TYPE.getInternalName(); 142 143 static final String INIT = "<init>"; 144 145 static final String GLOBAL_FIELD_NAME = "global"; 146 147 static final String SCRIPT_OBJECT_TYPE_DESCRIPTOR = SCRIPT_OBJECT_TYPE.getDescriptor(); 148 static final String GLOBAL_TYPE_DESCRIPTOR = GLOBAL_TYPE.getDescriptor(); 149 150 151 static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, GLOBAL_TYPE); 152 static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE); 153 154 private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class); 155 private static final Type STRING_TYPE = Type.getType(String.class); 156 private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class); 157 private static final Type METHOD_HANDLE_TYPE = Type.getType(MethodHandle.class); 158 private static final String GET_HANDLE_OBJECT_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE, 159 OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE); 160 private static final String GET_HANDLE_FUNCTION_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE, 161 SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE); 162 private static final String GET_CLASS_INITIALIZER_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE); 163 private static final Type RUNTIME_EXCEPTION_TYPE = Type.getType(RuntimeException.class); 164 private static final Type THROWABLE_TYPE = Type.getType(Throwable.class); 165 private static final Type UNSUPPORTED_OPERATION_TYPE = Type.getType(UnsupportedOperationException.class); 166 167 private static final String SERVICES_CLASS_TYPE_NAME = Type.getInternalName(JavaAdapterServices.class); 168 private static final String RUNTIME_EXCEPTION_TYPE_NAME = RUNTIME_EXCEPTION_TYPE.getInternalName(); 169 private static final String ERROR_TYPE_NAME = Type.getInternalName(Error.class); 170 private static final String THROWABLE_TYPE_NAME = THROWABLE_TYPE.getInternalName(); 171 private static final String UNSUPPORTED_OPERATION_TYPE_NAME = UNSUPPORTED_OPERATION_TYPE.getInternalName(); 172 173 private static final String METHOD_HANDLE_TYPE_DESCRIPTOR = METHOD_HANDLE_TYPE.getDescriptor(); 174 private static final String GET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(GLOBAL_TYPE); 175 private static final String GET_CLASS_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Class.class)); 176 177 // Package used when the adapter can't be defined in the adaptee's package (either because it's sealed, or because 178 // it's a java.* package. 179 private static final String ADAPTER_PACKAGE_PREFIX = "jdk/nashorn/javaadapters/"; 180 // Class name suffix used to append to the adaptee class name, when it can be defined in the adaptee's package. 181 private static final String ADAPTER_CLASS_NAME_SUFFIX = "$$NashornJavaAdapter"; 182 private static final String JAVA_PACKAGE_PREFIX = "java/"; 183 private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255; 184 185 private static final String CLASS_INIT = "<clinit>"; 186 187 // Method name prefix for invoking super-methods 188 static final String SUPER_PREFIX = "super$"; 189 190 /** 191 * Collection of methods we never override: Object.clone(), Object.finalize(). 192 */ 193 private static final Collection<MethodInfo> EXCLUDED = getExcludedMethods(); 194 195 // This is the superclass for our generated adapter. 196 private final Class<?> superClass; 197 // Class loader used as the parent for the class loader we'll create to load the generated class. It will be a class 198 // loader that has the visibility of all original types (class to extend and interfaces to implement) and of the 199 // Nashorn classes. 200 private final ClassLoader commonLoader; 201 // Is this a generator for the version of the class that can have overrides on the class level? 202 private final boolean classOverride; 203 // Binary name of the superClass 204 private final String superClassName; 205 // Binary name of the generated class. 206 private final String generatedClassName; 207 private final Set<String> usedFieldNames = new HashSet<>(); 208 private final Set<String> abstractMethodNames = new HashSet<>(); 209 private final String samName; 210 private final Set<MethodInfo> finalMethods = new HashSet<>(EXCLUDED); 211 private final Set<MethodInfo> methodInfos = new HashSet<>(); 212 private boolean autoConvertibleFromFunction = false; 213 private boolean hasExplicitFinalizer = false; 214 215 private final ClassWriter cw; 216 217 /** 218 * Creates a generator for the bytecode for the adapter for the specified superclass and interfaces. 219 * @param superClass the superclass the adapter will extend. 220 * @param interfaces the interfaces the adapter will implement. 221 * @param commonLoader the class loader that can see all of superClass, interfaces, and Nashorn classes. 222 * @param classOverride true to generate the bytecode for the adapter that has class-level overrides, false to 223 * generate the bytecode for the adapter that has instance-level overrides. 224 * @throws AdaptationException if the adapter can not be generated for some reason. 225 */ 226 JavaAdapterBytecodeGenerator(final Class<?> superClass, final List<Class<?>> interfaces, 227 final ClassLoader commonLoader, final boolean classOverride) throws AdaptationException { 228 assert superClass != null && !superClass.isInterface(); 229 assert interfaces != null; 230 231 this.superClass = superClass; 232 this.classOverride = classOverride; 233 this.commonLoader = commonLoader; 234 cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) { 235 @Override 236 protected String getCommonSuperClass(final String type1, final String type2) { 237 // We need to override ClassWriter.getCommonSuperClass to use this factory's commonLoader as a class 238 // loader to find the common superclass of two types when needed. 239 return JavaAdapterBytecodeGenerator.this.getCommonSuperClass(type1, type2); 240 } 241 }; 242 superClassName = Type.getInternalName(superClass); 243 generatedClassName = getGeneratedClassName(superClass, interfaces); 244 245 cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER, generatedClassName, null, superClassName, getInternalTypeNames(interfaces)); 246 generateGlobalFields(); 247 248 gatherMethods(superClass); 249 gatherMethods(interfaces); 250 samName = abstractMethodNames.size() == 1 ? abstractMethodNames.iterator().next() : null; 251 generateHandleFields(); 252 if(classOverride) { 253 generateClassInit(); 254 } 255 generateConstructors(); 256 generateMethods(); 257 generateSuperMethods(); 258 if (hasExplicitFinalizer) { 259 generateFinalizerMethods(); 260 } 261 // } 262 cw.visitEnd(); 263 } 264 265 private void generateGlobalFields() { 266 cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR, null, null).visitEnd(); 267 usedFieldNames.add(GLOBAL_FIELD_NAME); 268 } 269 270 JavaAdapterClassLoader createAdapterClassLoader() { 271 return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray()); 272 } 273 274 boolean isAutoConvertibleFromFunction() { 275 return autoConvertibleFromFunction; 276 } 277 278 private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) { 279 // The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're 280 // just implementing interfaces or extending Object), then the first implemented interface or Object. 281 final Class<?> namingType = superType == Object.class ? (interfaces.isEmpty()? Object.class : interfaces.get(0)) : superType; 282 final Package pkg = namingType.getPackage(); 283 final String namingTypeName = Type.getInternalName(namingType); 284 final StringBuilder buf = new StringBuilder(); 285 if (namingTypeName.startsWith(JAVA_PACKAGE_PREFIX) || pkg == null || pkg.isSealed()) { 286 // Can't define new classes in java.* packages 287 buf.append(ADAPTER_PACKAGE_PREFIX).append(namingTypeName); 288 } else { 289 buf.append(namingTypeName).append(ADAPTER_CLASS_NAME_SUFFIX); 290 } 291 final Iterator<Class<?>> it = interfaces.iterator(); 292 if(superType == Object.class && it.hasNext()) { 293 it.next(); // Skip first interface, it was used to primarily name the adapter 294 } 295 // Append interface names to the adapter name 296 while(it.hasNext()) { 297 buf.append("$$").append(it.next().getSimpleName()); 298 } 299 return buf.toString().substring(0, Math.min(MAX_GENERATED_TYPE_NAME_LENGTH, buf.length())); 300 } 301 302 /** 303 * Given a list of class objects, return an array with their binary names. Used to generate the array of interface 304 * names to implement. 305 * @param classes the classes 306 * @return an array of names 307 */ 308 private static String[] getInternalTypeNames(final List<Class<?>> classes) { 309 final int interfaceCount = classes.size(); 310 final String[] interfaceNames = new String[interfaceCount]; 311 for(int i = 0; i < interfaceCount; ++i) { 312 interfaceNames[i] = Type.getInternalName(classes.get(i)); 313 } 314 return interfaceNames; 315 } 316 317 private void generateHandleFields() { 318 final int flags = ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0); 319 for (final MethodInfo mi: methodInfos) { 320 cw.visitField(flags, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR, null, null).visitEnd(); 321 } 322 } 323 324 private void generateClassInit() { 325 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_STATIC, CLASS_INIT, 326 Type.getMethodDescriptor(Type.VOID_TYPE), null, null)); 327 328 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getClassOverrides", GET_CLASS_INITIALIZER_DESCRIPTOR, false); 329 final Label initGlobal; 330 if(samName != null) { 331 // If the class is a SAM, allow having a ScriptFunction passed as class overrides 332 final Label notAFunction = new Label(); 333 mv.dup(); 334 mv.instanceOf(SCRIPT_FUNCTION_TYPE); 335 mv.ifeq(notAFunction); 336 mv.checkcast(SCRIPT_FUNCTION_TYPE); 337 338 // Assign MethodHandle fields through invoking getHandle() for a ScriptFunction, only assigning the SAM 339 // method(s). 340 for (final MethodInfo mi : methodInfos) { 341 if(mi.getName().equals(samName)) { 342 mv.dup(); 343 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); 344 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_FUNCTION_DESCRIPTOR, false); 345 } else { 346 mv.visitInsn(ACONST_NULL); 347 } 348 mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); 349 } 350 initGlobal = new Label(); 351 mv.goTo(initGlobal); 352 mv.visitLabel(notAFunction); 353 } else { 354 initGlobal = null; 355 } 356 // Assign MethodHandle fields through invoking getHandle() for a ScriptObject 357 for (final MethodInfo mi : methodInfos) { 358 mv.dup(); 359 mv.aconst(mi.getName()); 360 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); 361 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false); 362 mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); 363 } 364 365 if(initGlobal != null) { 366 mv.visitLabel(initGlobal); 367 } 368 // Assign "global = Context.getGlobal()" 369 invokeGetGlobalWithNullCheck(mv); 370 mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR); 371 372 endInitMethod(mv); 373 } 374 375 private static void invokeGetGlobalWithNullCheck(final InstructionAdapter mv) { 376 invokeGetGlobal(mv); 377 mv.dup(); 378 mv.invokevirtual(OBJECT_TYPE_NAME, "getClass", GET_CLASS_METHOD_DESCRIPTOR, false); // check against null Context 379 mv.pop(); 380 } 381 382 private void generateConstructors() throws AdaptationException { 383 boolean gotCtor = false; 384 for (final Constructor<?> ctor: superClass.getDeclaredConstructors()) { 385 final int modifier = ctor.getModifiers(); 386 if((modifier & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0 && !isCallerSensitive(ctor)) { 387 generateConstructors(ctor); 388 gotCtor = true; 389 } 390 } 391 if(!gotCtor) { 392 throw new AdaptationException(ERROR_NO_ACCESSIBLE_CONSTRUCTOR, superClass.getCanonicalName()); 393 } 394 } 395 396 private void generateConstructors(final Constructor<?> ctor) { 397 if(classOverride) { 398 // Generate a constructor that just delegates to ctor. This is used with class-level overrides, when we want 399 // to create instances without further per-instance overrides. 400 generateDelegatingConstructor(ctor); 401 } else { 402 // Generate a constructor that delegates to ctor, but takes an additional ScriptObject parameter at the 403 // beginning of its parameter list. 404 generateOverridingConstructor(ctor, false); 405 406 if (samName != null) { 407 if (!autoConvertibleFromFunction && ctor.getParameterTypes().length == 0) { 408 // If the original type only has a single abstract method name, as well as a default ctor, then it can 409 // be automatically converted from JS function. 410 autoConvertibleFromFunction = true; 411 } 412 // If all our abstract methods have a single name, generate an additional constructor, one that takes a 413 // ScriptFunction as its first parameter and assigns it as the implementation for all abstract methods. 414 generateOverridingConstructor(ctor, true); 415 } 416 } 417 } 418 419 private void generateDelegatingConstructor(final Constructor<?> ctor) { 420 final Type originalCtorType = Type.getType(ctor); 421 final Type[] argTypes = originalCtorType.getArgumentTypes(); 422 423 // All constructors must be public, even if in the superclass they were protected. 424 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT, 425 Type.getMethodDescriptor(originalCtorType.getReturnType(), argTypes), null, null)); 426 427 mv.visitCode(); 428 // Invoke super constructor with the same arguments. 429 mv.visitVarInsn(ALOAD, 0); 430 int offset = 1; // First arg is at position 1, after this. 431 for (Type argType: argTypes) { 432 mv.load(offset, argType); 433 offset += argType.getSize(); 434 } 435 mv.invokespecial(superClassName, INIT, originalCtorType.getDescriptor(), false); 436 437 endInitMethod(mv); 438 } 439 440 /** 441 * Generates a constructor for the instance adapter class. This constructor will take the same arguments as the supertype 442 * constructor passed as the argument here, and delegate to it. However, it will take an additional argument of 443 * either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize 444 * all the method handle fields of the adapter instance with functions from the script object (or the script 445 * function itself, if that's what's passed). There is one method handle field in the adapter class for every method 446 * that can be implemented or overridden; the name of every field is same as the name of the method, with a number 447 * suffix that makes it unique in case of overloaded methods. The generated constructor will invoke 448 * {@link #getHandle(ScriptFunction, MethodType, boolean)} or {@link #getHandle(Object, String, MethodType, 449 * boolean)} to obtain the method handles; these methods make sure to add the necessary conversions and arity 450 * adjustments so that the resulting method handles can be invoked from generated methods using {@code invokeExact}. 451 * The constructor that takes a script function will only initialize the methods with the same name as the single 452 * abstract method. The constructor will also store the Nashorn global that was current at the constructor 453 * invocation time in a field named "global". The generated constructor will be public, regardless of whether the 454 * supertype constructor was public or protected. The generated constructor will not be variable arity, even if the 455 * supertype constructor was. 456 * @param ctor the supertype constructor that is serving as the base for the generated constructor. 457 * @param fromFunction true if we're generating a constructor that initializes SAM types from a single 458 * ScriptFunction passed to it, false if we're generating a constructor that initializes an arbitrary type from a 459 * ScriptObject passed to it. 460 */ 461 private void generateOverridingConstructor(final Constructor<?> ctor, final boolean fromFunction) { 462 final Type originalCtorType = Type.getType(ctor); 463 final Type[] originalArgTypes = originalCtorType.getArgumentTypes(); 464 final int argLen = originalArgTypes.length; 465 final Type[] newArgTypes = new Type[argLen + 1]; 466 467 // Insert ScriptFunction|Object as the last argument to the constructor 468 final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : OBJECT_TYPE; 469 newArgTypes[argLen] = extraArgumentType; 470 System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen); 471 472 // All constructors must be public, even if in the superclass they were protected. 473 // Existing super constructor <init>(this, args...) triggers generating <init>(this, scriptObj, args...). 474 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT, 475 Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null)); 476 477 mv.visitCode(); 478 // First, invoke super constructor with original arguments. If the form of the constructor we're generating is 479 // <init>(this, args..., scriptFn), then we're invoking super.<init>(this, args...). 480 mv.visitVarInsn(ALOAD, 0); 481 final Class<?>[] argTypes = ctor.getParameterTypes(); 482 int offset = 1; // First arg is at position 1, after this. 483 for (int i = 0; i < argLen; ++i) { 484 final Type argType = Type.getType(argTypes[i]); 485 mv.load(offset, argType); 486 offset += argType.getSize(); 487 } 488 mv.invokespecial(superClassName, INIT, originalCtorType.getDescriptor(), false); 489 490 // Get a descriptor to the appropriate "JavaAdapterFactory.getHandle" method. 491 final String getHandleDescriptor = fromFunction ? GET_HANDLE_FUNCTION_DESCRIPTOR : GET_HANDLE_OBJECT_DESCRIPTOR; 492 493 // Assign MethodHandle fields through invoking getHandle() 494 for (final MethodInfo mi : methodInfos) { 495 mv.visitVarInsn(ALOAD, 0); 496 if (fromFunction && !mi.getName().equals(samName)) { 497 // Constructors initializing from a ScriptFunction only initialize methods with the SAM name. 498 // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overriden too. This 499 // is a deliberate design choice. All other method handles are initialized to null. 500 mv.visitInsn(ACONST_NULL); 501 } else { 502 mv.visitVarInsn(ALOAD, offset); 503 if(!fromFunction) { 504 mv.aconst(mi.getName()); 505 } 506 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString())); 507 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor, false); 508 } 509 mv.putfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); 510 } 511 512 // Assign "this.global = Context.getGlobal()" 513 mv.visitVarInsn(ALOAD, 0); 514 invokeGetGlobalWithNullCheck(mv); 515 mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR); 516 517 endInitMethod(mv); 518 } 519 520 private static void endInitMethod(final InstructionAdapter mv) { 521 mv.visitInsn(RETURN); 522 endMethod(mv); 523 } 524 525 private static void endMethod(final InstructionAdapter mv) { 526 mv.visitMaxs(0, 0); 527 mv.visitEnd(); 528 } 529 530 private static void invokeGetGlobal(final InstructionAdapter mv) { 531 mv.invokestatic(CONTEXT_TYPE_NAME, "getGlobal", GET_GLOBAL_METHOD_DESCRIPTOR, false); 532 } 533 534 private static void invokeSetGlobal(final InstructionAdapter mv) { 535 mv.invokestatic(CONTEXT_TYPE_NAME, "setGlobal", SET_GLOBAL_METHOD_DESCRIPTOR, false); 536 } 537 538 /** 539 * Encapsulation of the information used to generate methods in the adapter classes. Basically, a wrapper around the 540 * reflective Method object, a cached MethodType, and the name of the field in the adapter class that will hold the 541 * method handle serving as the implementation of this method in adapter instances. 542 * 543 */ 544 private static class MethodInfo { 545 private final Method method; 546 private final MethodType type; 547 private String methodHandleFieldName; 548 549 private MethodInfo(final Class<?> clazz, final String name, final Class<?>... argTypes) throws NoSuchMethodException { 550 this(clazz.getDeclaredMethod(name, argTypes)); 551 } 552 553 private MethodInfo(final Method method) { 554 this.method = method; 555 this.type = MH.type(method.getReturnType(), method.getParameterTypes()); 556 } 557 558 @Override 559 public boolean equals(final Object obj) { 560 return obj instanceof MethodInfo && equals((MethodInfo)obj); 561 } 562 563 private boolean equals(final MethodInfo other) { 564 // Only method name and type are used for comparison; method handle field name is not. 565 return getName().equals(other.getName()) && type.equals(other.type); 566 } 567 568 String getName() { 569 return method.getName(); 570 } 571 572 @Override 573 public int hashCode() { 574 return getName().hashCode() ^ type.hashCode(); 575 } 576 577 void setIsCanonical(final JavaAdapterBytecodeGenerator self) { 578 methodHandleFieldName = self.nextName(getName()); 579 } 580 } 581 582 private String nextName(final String name) { 583 int i = 0; 584 String nextName = name; 585 while (!usedFieldNames.add(nextName)) { 586 final String ordinal = String.valueOf(i++); 587 final int maxNameLen = 255 - ordinal.length(); 588 nextName = (name.length() <= maxNameLen ? name : name.substring(0, maxNameLen)).concat(ordinal); 589 } 590 return nextName; 591 } 592 593 private void generateMethods() { 594 for(final MethodInfo mi: methodInfos) { 595 generateMethod(mi); 596 } 597 } 598 599 /** 600 * Generates a method in the adapter class that adapts a method from the original class. The generated methods will 601 * inspect the method handle field assigned to them. If it is null (the JS object doesn't provide an implementation 602 * for the method) then it will either invoke its version in the supertype, or if it is abstract, throw an 603 * {@link UnsupportedOperationException}. Otherwise, if the method handle field's value is not null, the handle is 604 * invoked using invokeExact (signature polymorphic invocation as per JLS 15.12.3). Before the invocation, the 605 * current Nashorn {@link Context} is checked, and if it is different than the global used to create the adapter 606 * instance, the creating global is set to be the current global. In this case, the previously current global is 607 * restored after the invocation. If invokeExact results in a Throwable that is not one of the method's declared 608 * exceptions, and is not an unchecked throwable, then it is wrapped into a {@link RuntimeException} and the runtime 609 * exception is thrown. The method handle retrieved from the field is guaranteed to exactly match the signature of 610 * the method; this is guaranteed by the way constructors of the adapter class obtain them using 611 * {@link #getHandle(Object, String, MethodType, boolean)}. 612 * @param mi the method info describing the method to be generated. 613 */ 614 private void generateMethod(final MethodInfo mi) { 615 final Method method = mi.method; 616 final Class<?>[] exceptions = method.getExceptionTypes(); 617 final String[] exceptionNames = getExceptionNames(exceptions); 618 final MethodType type = mi.type; 619 final String methodDesc = type.toMethodDescriptorString(); 620 final String name = mi.getName(); 621 622 final Type asmType = Type.getMethodType(methodDesc); 623 final Type[] asmArgTypes = asmType.getArgumentTypes(); 624 625 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), name, 626 methodDesc, null, exceptionNames)); 627 mv.visitCode(); 628 629 final Label handleDefined = new Label(); 630 631 final Type asmReturnType = Type.getType(type.returnType()); 632 633 // See if we have overriding method handle defined 634 if(classOverride) { 635 mv.getstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); 636 } else { 637 mv.visitVarInsn(ALOAD, 0); 638 mv.getfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR); 639 } 640 // stack: [handle] 641 jumpIfNonNullKeepOperand(mv, handleDefined); 642 643 // No handle is available, fall back to default behavior 644 if(Modifier.isAbstract(method.getModifiers())) { 645 // If the super method is abstract, throw an exception 646 mv.anew(UNSUPPORTED_OPERATION_TYPE); 647 mv.dup(); 648 mv.invokespecial(UNSUPPORTED_OPERATION_TYPE_NAME, INIT, VOID_NOARG_METHOD_DESCRIPTOR, false); 649 mv.athrow(); 650 } else { 651 // If the super method is not abstract, delegate to it. 652 emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc); 653 } 654 655 mv.visitLabel(handleDefined); 656 // Load the creatingGlobal object 657 if(classOverride) { 658 // If class handle is defined, load the static defining global 659 mv.getstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR); 660 } else { 661 mv.visitVarInsn(ALOAD, 0); 662 mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR); 663 } 664 // stack: [creatingGlobal, handle] 665 final Label setupGlobal = new Label(); 666 mv.visitLabel(setupGlobal); 667 668 // Determine the first index for a local variable 669 int nextLocalVar = 1; // "this" is at 0 670 for(final Type t: asmArgTypes) { 671 nextLocalVar += t.getSize(); 672 } 673 // Set our local variable indices 674 final int currentGlobalVar = nextLocalVar++; 675 final int globalsDifferVar = nextLocalVar++; 676 677 mv.dup(); 678 // stack: [creatingGlobal, creatingGlobal, handle] 679 680 // Emit code for switching to the creating global 681 // Global currentGlobal = Context.getGlobal(); 682 invokeGetGlobal(mv); 683 mv.dup(); 684 685 mv.visitVarInsn(ASTORE, currentGlobalVar); 686 // stack: [currentGlobal, creatingGlobal, creatingGlobal, handle] 687 // if(definingGlobal == currentGlobal) { 688 final Label globalsDiffer = new Label(); 689 mv.ifacmpne(globalsDiffer); 690 // stack: [creatingGlobal, handle] 691 // globalsDiffer = false 692 mv.pop(); 693 // stack: [handle] 694 mv.iconst(0); // false 695 // stack: [false, handle] 696 final Label invokeHandle = new Label(); 697 mv.goTo(invokeHandle); 698 mv.visitLabel(globalsDiffer); 699 // } else { 700 // Context.setGlobal(definingGlobal); 701 // stack: [creatingGlobal, handle] 702 invokeSetGlobal(mv); 703 // stack: [handle] 704 // globalsDiffer = true 705 mv.iconst(1); 706 // stack: [true, handle] 707 708 mv.visitLabel(invokeHandle); 709 mv.visitVarInsn(ISTORE, globalsDifferVar); 710 // stack: [handle] 711 712 // Load all parameters back on stack for dynamic invocation. 713 int varOffset = 1; 714 for (final Type t : asmArgTypes) { 715 mv.load(varOffset, t); 716 varOffset += t.getSize(); 717 } 718 719 // Invoke the target method handle 720 final Label tryBlockStart = new Label(); 721 mv.visitLabel(tryBlockStart); 722 mv.invokevirtual(METHOD_HANDLE_TYPE.getInternalName(), "invokeExact", type.toMethodDescriptorString(), false); 723 final Label tryBlockEnd = new Label(); 724 mv.visitLabel(tryBlockEnd); 725 emitFinally(mv, currentGlobalVar, globalsDifferVar); 726 mv.areturn(asmReturnType); 727 728 // If Throwable is not declared, we need an adapter from Throwable to RuntimeException 729 final boolean throwableDeclared = isThrowableDeclared(exceptions); 730 final Label throwableHandler; 731 if (!throwableDeclared) { 732 // Add "throw new RuntimeException(Throwable)" handler for Throwable 733 throwableHandler = new Label(); 734 mv.visitLabel(throwableHandler); 735 mv.anew(RUNTIME_EXCEPTION_TYPE); 736 mv.dupX1(); 737 mv.swap(); 738 mv.invokespecial(RUNTIME_EXCEPTION_TYPE_NAME, INIT, Type.getMethodDescriptor(Type.VOID_TYPE, THROWABLE_TYPE), false); 739 // Fall through to rethrow handler 740 } else { 741 throwableHandler = null; 742 } 743 final Label rethrowHandler = new Label(); 744 mv.visitLabel(rethrowHandler); 745 // Rethrow handler for RuntimeException, Error, and all declared exception types 746 emitFinally(mv, currentGlobalVar, globalsDifferVar); 747 mv.athrow(); 748 final Label methodEnd = new Label(); 749 mv.visitLabel(methodEnd); 750 751 mv.visitLocalVariable("currentGlobal", GLOBAL_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd, currentGlobalVar); 752 mv.visitLocalVariable("globalsDiffer", Type.INT_TYPE.getDescriptor(), null, setupGlobal, methodEnd, globalsDifferVar); 753 754 if(throwableDeclared) { 755 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, THROWABLE_TYPE_NAME); 756 assert throwableHandler == null; 757 } else { 758 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME); 759 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, ERROR_TYPE_NAME); 760 for(final String excName: exceptionNames) { 761 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, excName); 762 } 763 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME); 764 } 765 endMethod(mv); 766 } 767 768 /** 769 * Emits code for jumping to a label if the top stack operand is not null. The operand is kept on the stack if it 770 * is not null (so is available to code at the jump address) and is popped if it is null. 771 * @param mv the instruction adapter being used to emit code 772 * @param label the label to jump to 773 */ 774 private static void jumpIfNonNullKeepOperand(final InstructionAdapter mv, final Label label) { 775 mv.visitInsn(DUP); 776 mv.visitJumpInsn(IFNONNULL, label); 777 mv.visitInsn(POP); 778 } 779 780 /** 781 * Emit code to restore the previous Nashorn Context when needed. 782 * @param mv the instruction adapter 783 * @param currentGlobalVar index of the local variable holding the reference to the current global at method 784 * entry. 785 * @param globalsDifferVar index of the boolean local variable that is true if the global needs to be restored. 786 */ 787 private static void emitFinally(final InstructionAdapter mv, final int currentGlobalVar, final int globalsDifferVar) { 788 // Emit code to restore the previous Nashorn global if needed 789 mv.visitVarInsn(ILOAD, globalsDifferVar); 790 final Label skip = new Label(); 791 mv.ifeq(skip); 792 mv.visitVarInsn(ALOAD, currentGlobalVar); 793 invokeSetGlobal(mv); 794 mv.visitLabel(skip); 795 } 796 797 private static boolean isThrowableDeclared(final Class<?>[] exceptions) { 798 for (final Class<?> exception : exceptions) { 799 if (exception == Throwable.class) { 800 return true; 801 } 802 } 803 return false; 804 } 805 806 private void generateSuperMethods() { 807 for(final MethodInfo mi: methodInfos) { 808 if(!Modifier.isAbstract(mi.method.getModifiers())) { 809 generateSuperMethod(mi); 810 } 811 } 812 } 813 814 private void generateSuperMethod(MethodInfo mi) { 815 final Method method = mi.method; 816 817 final String methodDesc = mi.type.toMethodDescriptorString(); 818 final String name = mi.getName(); 819 820 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), 821 SUPER_PREFIX + name, methodDesc, null, getExceptionNames(method.getExceptionTypes()))); 822 mv.visitCode(); 823 824 emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc); 825 826 endMethod(mv); 827 } 828 829 private void emitSuperCall(final InstructionAdapter mv, final Class<?> owner, final String name, final String methodDesc) { 830 mv.visitVarInsn(ALOAD, 0); 831 int nextParam = 1; 832 final Type methodType = Type.getMethodType(methodDesc); 833 for(final Type t: methodType.getArgumentTypes()) { 834 mv.load(nextParam, t); 835 nextParam += t.getSize(); 836 } 837 838 // default method - non-abstract, interface method 839 if (Modifier.isInterface(owner.getModifiers())) { 840 mv.invokespecial(Type.getInternalName(owner), name, methodDesc, false); 841 } else { 842 mv.invokespecial(superClassName, name, methodDesc, false); 843 } 844 mv.areturn(methodType.getReturnType()); 845 } 846 847 private void generateFinalizerMethods() { 848 final String finalizerDelegateName = nextName("access$"); 849 generateFinalizerDelegate(finalizerDelegateName); 850 generateFinalizerOverride(finalizerDelegateName); 851 } 852 853 private void generateFinalizerDelegate(final String finalizerDelegateName) { 854 // Generate a delegate that will be invoked from the no-permission trampoline. Note it can be private, as we'll 855 // refer to it with a MethodHandle constant pool entry in the overridden finalize() method (see 856 // generateFinalizerOverride()). 857 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PRIVATE | ACC_STATIC, 858 finalizerDelegateName, Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE), null, null)); 859 860 // Simply invoke super.finalize() 861 mv.visitVarInsn(ALOAD, 0); 862 mv.checkcast(Type.getType(generatedClassName)); 863 mv.invokespecial(superClassName, "finalize", Type.getMethodDescriptor(Type.VOID_TYPE), false); 864 865 mv.visitInsn(RETURN); 866 endMethod(mv); 867 } 868 869 private void generateFinalizerOverride(final String finalizerDelegateName) { 870 final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, "finalize", 871 VOID_NOARG_METHOD_DESCRIPTOR, null, null)); 872 // Overridden finalizer will take a MethodHandle to the finalizer delegating method, ... 873 mv.aconst(new Handle(Opcodes.H_INVOKESTATIC, generatedClassName, finalizerDelegateName, 874 Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE))); 875 mv.visitVarInsn(ALOAD, 0); 876 // ...and invoke it through JavaAdapterServices.invokeNoPermissions 877 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "invokeNoPermissions", 878 Type.getMethodDescriptor(METHOD_HANDLE_TYPE, OBJECT_TYPE), false); 879 mv.visitInsn(RETURN); 880 endMethod(mv); 881 } 882 883 private static String[] getExceptionNames(final Class<?>[] exceptions) { 884 final String[] exceptionNames = new String[exceptions.length]; 885 for (int i = 0; i < exceptions.length; ++i) { 886 exceptionNames[i] = Type.getInternalName(exceptions[i]); 887 } 888 return exceptionNames; 889 } 890 891 private static int getAccessModifiers(final Method method) { 892 return ACC_PUBLIC | (method.isVarArgs() ? ACC_VARARGS : 0); 893 } 894 895 /** 896 * Gathers methods that can be implemented or overridden from the specified type into this factory's 897 * {@link #methodInfos} set. It will add all non-final, non-static methods that are either public or protected from 898 * the type if the type itself is public. If the type is a class, the method will recursively invoke itself for its 899 * superclass and the interfaces it implements, and add further methods that were not directly declared on the 900 * class. 901 * @param type the type defining the methods. 902 */ 903 private void gatherMethods(final Class<?> type) throws AdaptationException { 904 if (Modifier.isPublic(type.getModifiers())) { 905 final Method[] typeMethods = type.isInterface() ? type.getMethods() : type.getDeclaredMethods(); 906 907 for (final Method typeMethod: typeMethods) { 908 final String name = typeMethod.getName(); 909 if(name.startsWith(SUPER_PREFIX)) { 910 continue; 911 } 912 final int m = typeMethod.getModifiers(); 913 if (Modifier.isStatic(m)) { 914 continue; 915 } 916 if (Modifier.isPublic(m) || Modifier.isProtected(m)) { 917 // Is it a "finalize()"? 918 if(name.equals("finalize") && typeMethod.getParameterCount() == 0) { 919 if(type != Object.class) { 920 hasExplicitFinalizer = true; 921 if(Modifier.isFinal(m)) { 922 // Must be able to override an explicit finalizer 923 throw new AdaptationException(Outcome.ERROR_FINAL_FINALIZER, type.getCanonicalName()); 924 } 925 } 926 continue; 927 } 928 929 final MethodInfo mi = new MethodInfo(typeMethod); 930 if (Modifier.isFinal(m) || isCallerSensitive(typeMethod)) { 931 finalMethods.add(mi); 932 } else if (!finalMethods.contains(mi) && methodInfos.add(mi)) { 933 if (Modifier.isAbstract(m)) { 934 abstractMethodNames.add(mi.getName()); 935 } 936 mi.setIsCanonical(this); 937 } 938 } 939 } 940 } 941 // If the type is a class, visit its superclasses and declared interfaces. If it's an interface, we're done. 942 // Needing to invoke the method recursively for a non-interface Class object is the consequence of needing to 943 // see all declared protected methods, and Class.getDeclaredMethods() doesn't provide those declared in a 944 // superclass. For interfaces, we used Class.getMethods(), as we're only interested in public ones there, and 945 // getMethods() does provide those declared in a superinterface. 946 if (!type.isInterface()) { 947 final Class<?> superType = type.getSuperclass(); 948 if (superType != null) { 949 gatherMethods(superType); 950 } 951 for (final Class<?> itf: type.getInterfaces()) { 952 gatherMethods(itf); 953 } 954 } 955 } 956 957 private void gatherMethods(final List<Class<?>> classes) throws AdaptationException { 958 for(final Class<?> c: classes) { 959 gatherMethods(c); 960 } 961 } 962 963 private static final AccessControlContext GET_DECLARED_MEMBERS_ACC_CTXT = ClassAndLoader.createPermAccCtxt("accessDeclaredMembers"); 964 965 /** 966 * Creates a collection of methods that are not final, but we still never allow them to be overridden in adapters, 967 * as explicitly declaring them automatically is a bad idea. Currently, this means {@code Object.finalize()} and 968 * {@code Object.clone()}. 969 * @return a collection of method infos representing those methods that we never override in adapter classes. 970 */ 971 private static Collection<MethodInfo> getExcludedMethods() { 972 return AccessController.doPrivileged(new PrivilegedAction<Collection<MethodInfo>>() { 973 @Override 974 public Collection<MethodInfo> run() { 975 try { 976 return Arrays.asList( 977 new MethodInfo(Object.class, "finalize"), 978 new MethodInfo(Object.class, "clone")); 979 } catch (final NoSuchMethodException e) { 980 throw new AssertionError(e); 981 } 982 } 983 }, GET_DECLARED_MEMBERS_ACC_CTXT); 984 } 985 986 private String getCommonSuperClass(final String type1, final String type2) { 987 try { 988 final Class<?> c1 = Class.forName(type1.replace('/', '.'), false, commonLoader); 989 final Class<?> c2 = Class.forName(type2.replace('/', '.'), false, commonLoader); 990 if (c1.isAssignableFrom(c2)) { 991 return type1; 992 } 993 if (c2.isAssignableFrom(c1)) { 994 return type2; 995 } 996 if (c1.isInterface() || c2.isInterface()) { 997 return OBJECT_TYPE_NAME; 998 } 999 return assignableSuperClass(c1, c2).getName().replace('.', '/'); 1000 } catch(final ClassNotFoundException e) { 1001 throw new RuntimeException(e); 1002 } 1003 } 1004 1005 private static Class<?> assignableSuperClass(final Class<?> c1, final Class<?> c2) { 1006 final Class<?> superClass = c1.getSuperclass(); 1007 return superClass.isAssignableFrom(c2) ? superClass : assignableSuperClass(superClass, c2); 1008 } 1009 1010 private static boolean isCallerSensitive(final AccessibleObject e) { 1011 return e.isAnnotationPresent(CallerSensitive.class); 1012 } 1013 }