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