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