JavaAdapterBytecodeGenerator.java revision 1692:bb6cf30cf892
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.ALOAD;
35import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE;
36import static jdk.internal.org.objectweb.asm.Opcodes.D2F;
37import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
38import static jdk.internal.org.objectweb.asm.Opcodes.I2B;
39import static jdk.internal.org.objectweb.asm.Opcodes.I2S;
40import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
41import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup;
42import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
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.CallSite;
47import java.lang.invoke.MethodHandle;
48import java.lang.invoke.MethodHandles.Lookup;
49import java.lang.invoke.MethodType;
50import java.lang.reflect.AccessibleObject;
51import java.lang.reflect.Constructor;
52import java.lang.reflect.Method;
53import java.lang.reflect.Modifier;
54import java.lang.reflect.Module;
55import java.security.AccessControlContext;
56import java.security.AccessController;
57import java.security.PrivilegedAction;
58import java.util.Arrays;
59import java.util.Collection;
60import java.util.HashSet;
61import java.util.Iterator;
62import java.util.List;
63import java.util.Set;
64import jdk.internal.org.objectweb.asm.ClassWriter;
65import jdk.internal.org.objectweb.asm.Handle;
66import jdk.internal.org.objectweb.asm.Label;
67import jdk.internal.org.objectweb.asm.Opcodes;
68import jdk.internal.org.objectweb.asm.Type;
69import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
70import jdk.nashorn.api.scripting.ScriptUtils;
71import jdk.nashorn.internal.codegen.CompilerConstants.Call;
72import jdk.nashorn.internal.runtime.ScriptFunction;
73import jdk.nashorn.internal.runtime.ScriptObject;
74import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome;
75import jdk.internal.reflect.CallerSensitive;
76
77/**
78 * Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}.
79 * </p><p>
80 * For every protected or public constructor in the extended class, the adapter class will have either one or two
81 * public constructors (visibility of protected constructors in the extended class is promoted to public).
82 * <li>
83 * <li>For adapter classes with instance-level overrides, a constructor taking a trailing ScriptObject argument preceded
84 * by original constructor arguments is always created on the adapter class. When such a constructor is invoked, the
85 * passed ScriptObject's member functions are used to implement and/or override methods on the original class,
86 * dispatched by name. A single JavaScript function will act as the implementation for all overloaded methods of the
87 * same name. When methods on an adapter instance are invoked, the functions are invoked having the ScriptObject passed
88 * in the instance constructor as their "this". Subsequent changes to the ScriptObject (reassignment or removal of its
89 * functions) will be reflected in the adapter instance as it is live dispatching to its members on every method invocation.
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 has 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. If the original
109 * class' constructor was variable arity, the adapter constructor will also be variable arity. Protected constructors
110 * are exposed as public.
111 * </li>
112 * </ul>
113 * </p><p>
114 * For adapter methods that return values, all the JavaScript-to-Java conversions supported by Nashorn will be in effect
115 * to coerce the JavaScript function return value to the expected Java return type.
116 * </p><p>
117 * Since we are adding a trailing argument to the generated constructors in the adapter class with instance-level overrides, they will never be
118 * declared as variable arity, even if the original constructor in the superclass was declared as variable arity. The
119 * reason we are passing the additional argument at the end of the argument list instead at the front is that the
120 * source-level script expression <code>new X(a, b) { ... }</code> (which is a proprietary syntax extension Nashorn uses
121 * to resemble Java anonymous classes) is actually equivalent to <code>new X(a, b, { ... })</code>.
122 * </p><p>
123 * It is possible to create two different adapter classes: those that can have class-level overrides, and those that can
124 * have instance-level overrides. When {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked
125 * with non-null {@code classOverrides} parameter, an adapter class is created that can have class-level overrides, and
126 * the passed script object will be used as the implementations for its methods, just as in the above case of the
127 * constructor taking a script object. Note that in the case of class-level overrides, a new adapter class is created on
128 * every invocation, and the implementation object is bound to the class, not to any instance. All created instances
129 * will share these functions. If it is required to have both class-level overrides and instance-level overrides, the
130 * class-level override adapter class should be subclassed with an instance-override adapter. Since adapters delegate to
131 * super class when an overriding method handle is not specified, this will behave as expected. It is not possible to
132 * have both class-level and instance-level overrides in the same class for security reasons: adapter classes are
133 * defined with a protection domain of their creator code, and an adapter class that has both class and instance level
134 * overrides would need to have two potentially different protection domains: one for class-based behavior and one for
135 * instance-based behavior; since Java classes can only belong to a single protection domain, this could not be
136 * implemented securely.
137 */
138final class JavaAdapterBytecodeGenerator {
139    // Field names in adapters
140    private static final String GLOBAL_FIELD_NAME = "global";
141    private static final String DELEGATE_FIELD_NAME = "delegate";
142    private static final String IS_FUNCTION_FIELD_NAME = "isFunction";
143    private static final String CALL_THIS_FIELD_NAME = "callThis";
144
145    // Initializer names
146    private static final String INIT = "<init>";
147    private static final String CLASS_INIT = "<clinit>";
148
149    // Types often used in generated bytecode
150    private static final Type OBJECT_TYPE = Type.getType(Object.class);
151    private static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
152    private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
153
154    // JavaAdapterServices methods used in generated bytecode
155    private static final Call CHECK_FUNCTION = lookupServiceMethod("checkFunction", ScriptFunction.class, Object.class, String.class);
156    private static final Call EXPORT_RETURN_VALUE = lookupServiceMethod("exportReturnValue", Object.class, Object.class);
157    private static final Call GET_CALL_THIS = lookupServiceMethod("getCallThis", Object.class, ScriptFunction.class, Object.class);
158    private static final Call GET_CLASS_OVERRIDES = lookupServiceMethod("getClassOverrides", ScriptObject.class);
159    private static final Call GET_NON_NULL_GLOBAL = lookupServiceMethod("getNonNullGlobal", ScriptObject.class);
160    private static final Call HAS_OWN_TO_STRING = lookupServiceMethod("hasOwnToString", boolean.class, ScriptObject.class);
161    private static final Call INVOKE_NO_PERMISSIONS = lookupServiceMethod("invokeNoPermissions", void.class, MethodHandle.class, Object.class);
162    private static final Call NOT_AN_OBJECT = lookupServiceMethod("notAnObject", void.class, Object.class);
163    private static final Call SET_GLOBAL = lookupServiceMethod("setGlobal", Runnable.class, ScriptObject.class);
164    private static final Call TO_CHAR_PRIMITIVE = lookupServiceMethod("toCharPrimitive", char.class, Object.class);
165    private static final Call UNSUPPORTED = lookupServiceMethod("unsupported", UnsupportedOperationException.class);
166    private static final Call WRAP_THROWABLE = lookupServiceMethod("wrapThrowable", RuntimeException.class, Throwable.class);
167
168    // Other methods invoked by the generated bytecode
169    private static final Call UNWRAP = staticCallNoLookup(ScriptUtils.class, "unwrap", Object.class, Object.class);
170    private static final Call CHAR_VALUE_OF = staticCallNoLookup(Character.class, "valueOf", Character.class, char.class);
171    private static final Call DOUBLE_VALUE_OF = staticCallNoLookup(Double.class, "valueOf", Double.class, double.class);
172    private static final Call LONG_VALUE_OF = staticCallNoLookup(Long.class, "valueOf", Long.class, long.class);
173    private static final Call RUN = interfaceCallNoLookup(Runnable.class, "run", void.class);
174
175    // ASM handle to the bootstrap method
176    @SuppressWarnings("deprecation")
177    private static final Handle BOOTSTRAP_HANDLE = new Handle(H_INVOKESTATIC,
178            Type.getInternalName(JavaAdapterServices.class), "bootstrap",
179            MethodType.methodType(CallSite.class, Lookup.class, String.class,
180                    MethodType.class, int.class).toMethodDescriptorString());
181
182    // ASM handle to the bootstrap method for array populator
183    @SuppressWarnings("deprecation")
184    private static final Handle CREATE_ARRAY_BOOTSTRAP_HANDLE = new Handle(H_INVOKESTATIC,
185            Type.getInternalName(JavaAdapterServices.class), "createArrayBootstrap",
186            MethodType.methodType(CallSite.class, Lookup.class, String.class,
187                    MethodType.class).toMethodDescriptorString());
188
189    // Field type names used in the generated bytecode
190    private static final String SCRIPT_OBJECT_TYPE_DESCRIPTOR = SCRIPT_OBJECT_TYPE.getDescriptor();
191    private static final String OBJECT_TYPE_DESCRIPTOR = OBJECT_TYPE.getDescriptor();
192    private static final String BOOLEAN_TYPE_DESCRIPTOR = Type.BOOLEAN_TYPE.getDescriptor();
193
194    // Throwable names used in the generated bytecode
195    private static final String RUNTIME_EXCEPTION_TYPE_NAME = Type.getInternalName(RuntimeException.class);
196    private static final String ERROR_TYPE_NAME = Type.getInternalName(Error.class);
197    private static final String THROWABLE_TYPE_NAME = Type.getInternalName(Throwable.class);
198
199    // Some more frequently used method descriptors
200    private static final String GET_METHOD_PROPERTY_METHOD_DESCRIPTOR = Type.getMethodDescriptor(OBJECT_TYPE, SCRIPT_OBJECT_TYPE);
201    private static final String VOID_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
202
203    static final String ADAPTER_PACKAGE_INTERNAL = "jdk/nashorn/javaadapters/";
204    static final String ADAPTER_PACKAGE = "jdk.nashorn.javaadapters";
205    private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255;
206
207    // Method name prefix for invoking super-methods
208    static final String SUPER_PREFIX = "super$";
209
210    // Method name and type for the no-privilege finalizer delegate
211    private static final String FINALIZER_DELEGATE_NAME = "$$nashornFinalizerDelegate";
212    private static final String FINALIZER_DELEGATE_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE);
213
214    /**
215     * Collection of methods we never override: Object.clone(), Object.finalize().
216     */
217    private static final Collection<MethodInfo> EXCLUDED = getExcludedMethods();
218
219    // This is the superclass for our generated adapter.
220    private final Class<?> superClass;
221    // Interfaces implemented by our generated adapter.
222    private final List<Class<?>> interfaces;
223    // Class loader used as the parent for the class loader we'll create to load the generated class. It will be a class
224    // loader that has the visibility of all original types (class to extend and interfaces to implement) and of the
225    // Nashorn classes.
226    private final ClassLoader commonLoader;
227    // Is this a generator for the version of the class that can have overrides on the class level?
228    private final boolean classOverride;
229    // Binary name of the superClass
230    private final String superClassName;
231    // Binary name of the generated class.
232    private final String generatedClassName;
233    private final Set<String> abstractMethodNames = new HashSet<>();
234    private final String samName;
235    private final Set<MethodInfo> finalMethods = new HashSet<>(EXCLUDED);
236    private final Set<MethodInfo> methodInfos = new HashSet<>();
237    private final boolean autoConvertibleFromFunction;
238    private boolean hasExplicitFinalizer = false;
239    private final Set<Module> accessedModules = new HashSet<>();
240
241    private final ClassWriter cw;
242
243    /**
244     * Creates a generator for the bytecode for the adapter for the specified superclass and interfaces.
245     * @param superClass the superclass the adapter will extend.
246     * @param interfaces the interfaces the adapter will implement.
247     * @param commonLoader the class loader that can see all of superClass, interfaces, and Nashorn classes.
248     * @param classOverride true to generate the bytecode for the adapter that has class-level overrides, false to
249     * generate the bytecode for the adapter that has instance-level overrides.
250     * @throws AdaptationException if the adapter can not be generated for some reason.
251     */
252    JavaAdapterBytecodeGenerator(final Class<?> superClass, final List<Class<?>> interfaces,
253            final ClassLoader commonLoader, final boolean classOverride) throws AdaptationException {
254        assert superClass != null && !superClass.isInterface();
255        assert interfaces != null;
256
257        this.superClass = superClass;
258        this.interfaces = interfaces;
259        this.classOverride = classOverride;
260        this.commonLoader = commonLoader;
261        cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
262            @Override
263            protected String getCommonSuperClass(final String type1, final String type2) {
264                // We need to override ClassWriter.getCommonSuperClass to use this factory's commonLoader as a class
265                // loader to find the common superclass of two types when needed.
266                return JavaAdapterBytecodeGenerator.this.getCommonSuperClass(type1, type2);
267            }
268        };
269        superClassName = Type.getInternalName(superClass);
270        generatedClassName = getGeneratedClassName(superClass, interfaces);
271
272        cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER, generatedClassName, null, superClassName, getInternalTypeNames(interfaces));
273        generateField(GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
274        generateField(DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
275
276        gatherMethods(superClass);
277        gatherMethods(interfaces);
278        if (abstractMethodNames.size() == 1) {
279            samName = abstractMethodNames.iterator().next();
280            generateField(CALL_THIS_FIELD_NAME, OBJECT_TYPE_DESCRIPTOR);
281            generateField(IS_FUNCTION_FIELD_NAME, BOOLEAN_TYPE_DESCRIPTOR);
282        } else {
283            samName = null;
284        }
285        if(classOverride) {
286            generateClassInit();
287        }
288        autoConvertibleFromFunction = generateConstructors();
289        generateMethods();
290        generateSuperMethods();
291        if (hasExplicitFinalizer) {
292            generateFinalizerMethods();
293        }
294        // }
295        cw.visitEnd();
296    }
297
298    private void generateField(final String name, final String fieldDesc) {
299        cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), name, fieldDesc, null, null).visitEnd();
300    }
301
302    JavaAdapterClassLoader createAdapterClassLoader() {
303        return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray(), accessedModules);
304    }
305
306    boolean isAutoConvertibleFromFunction() {
307        return autoConvertibleFromFunction;
308    }
309
310    private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) {
311        // The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're
312        // just implementing interfaces or extending Object), then the first implemented interface or Object.
313        final Class<?> namingType = superType == Object.class ? (interfaces.isEmpty()? Object.class : interfaces.get(0)) : superType;
314        final Package pkg = namingType.getPackage();
315        final String namingTypeName = Type.getInternalName(namingType);
316        final StringBuilder buf = new StringBuilder();
317        buf.append(ADAPTER_PACKAGE_INTERNAL).append(namingTypeName.replace('/', '_'));
318        final Iterator<Class<?>> it = interfaces.iterator();
319        if(superType == Object.class && it.hasNext()) {
320            it.next(); // Skip first interface, it was used to primarily name the adapter
321        }
322        // Append interface names to the adapter name
323        while(it.hasNext()) {
324            buf.append("$$").append(it.next().getSimpleName());
325        }
326        return buf.toString().substring(0, Math.min(MAX_GENERATED_TYPE_NAME_LENGTH, buf.length()));
327    }
328
329    /**
330     * Given a list of class objects, return an array with their binary names. Used to generate the array of interface
331     * names to implement.
332     * @param classes the classes
333     * @return an array of names
334     */
335    private static String[] getInternalTypeNames(final List<Class<?>> classes) {
336        final int interfaceCount = classes.size();
337        final String[] interfaceNames = new String[interfaceCount];
338        for(int i = 0; i < interfaceCount; ++i) {
339            interfaceNames[i] = Type.getInternalName(classes.get(i));
340        }
341        return interfaceNames;
342    }
343
344    private void generateClassInit() {
345        final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_STATIC, CLASS_INIT,
346                VOID_METHOD_DESCRIPTOR, null, null));
347
348        // Assign "global = Context.getGlobal()"
349        GET_NON_NULL_GLOBAL.invoke(mv);
350        mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
351
352        GET_CLASS_OVERRIDES.invoke(mv);
353        if(samName != null) {
354            // If the class is a SAM, allow having ScriptFunction passed as class overrides
355            mv.dup();
356            mv.instanceOf(SCRIPT_FUNCTION_TYPE);
357                    mv.dup();
358            mv.putstatic(generatedClassName, IS_FUNCTION_FIELD_NAME, BOOLEAN_TYPE_DESCRIPTOR);
359            final Label notFunction = new Label();
360            mv.ifeq(notFunction);
361            mv.dup();
362            mv.checkcast(SCRIPT_FUNCTION_TYPE);
363            emitInitCallThis(mv);
364            mv.visitLabel(notFunction);
365        }
366        mv.putstatic(generatedClassName, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
367
368        endInitMethod(mv);
369    }
370
371    /**
372     * Emit bytecode for initializing the "callThis" field.
373     */
374    private void emitInitCallThis(final InstructionAdapter mv) {
375        loadField(mv, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
376        GET_CALL_THIS.invoke(mv);
377            if(classOverride) {
378            mv.putstatic(generatedClassName, CALL_THIS_FIELD_NAME, OBJECT_TYPE_DESCRIPTOR);
379            } else {
380            // It is presumed ALOAD 0 was already executed
381            mv.putfield(generatedClassName, CALL_THIS_FIELD_NAME, OBJECT_TYPE_DESCRIPTOR);
382        }
383    }
384
385    private boolean generateConstructors() throws AdaptationException {
386        boolean gotCtor = false;
387        boolean canBeAutoConverted = false;
388        for (final Constructor<?> ctor: superClass.getDeclaredConstructors()) {
389            final int modifier = ctor.getModifiers();
390            if((modifier & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0 && !isCallerSensitive(ctor)) {
391                canBeAutoConverted = generateConstructors(ctor) | canBeAutoConverted;
392                gotCtor = true;
393            }
394        }
395        if(!gotCtor) {
396            throw new AdaptationException(ERROR_NO_ACCESSIBLE_CONSTRUCTOR, superClass.getCanonicalName());
397        }
398        return canBeAutoConverted;
399    }
400
401    private boolean generateConstructors(final Constructor<?> ctor) {
402        for (final Class<?> pt : ctor.getParameterTypes()) {
403            if (pt.isPrimitive()) continue;
404            final Module ptMod = pt.getModule();
405            if (ptMod != null) {
406                accessedModules.add(ptMod);
407            }
408        }
409
410        if(classOverride) {
411            // Generate a constructor that just delegates to ctor. This is used with class-level overrides, when we want
412            // to create instances without further per-instance overrides.
413            generateDelegatingConstructor(ctor);
414            return false;
415        }
416
417            // Generate a constructor that delegates to ctor, but takes an additional ScriptObject parameter at the
418            // beginning of its parameter list.
419            generateOverridingConstructor(ctor, false);
420
421        if (samName == null) {
422            return false;
423                }
424                // If all our abstract methods have a single name, generate an additional constructor, one that takes a
425                // ScriptFunction as its first parameter and assigns it as the implementation for all abstract methods.
426                generateOverridingConstructor(ctor, true);
427        // If the original type only has a single abstract method name, as well as a default ctor, then it can
428        // be automatically converted from JS function.
429        return ctor.getParameterTypes().length == 0;
430    }
431
432    private void generateDelegatingConstructor(final Constructor<?> ctor) {
433        final Type originalCtorType = Type.getType(ctor);
434        final Type[] argTypes = originalCtorType.getArgumentTypes();
435
436        // All constructors must be public, even if in the superclass they were protected.
437        final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC |
438                (ctor.isVarArgs() ? ACC_VARARGS : 0), INIT,
439                Type.getMethodDescriptor(originalCtorType.getReturnType(), argTypes), null, null));
440
441        mv.visitCode();
442        emitSuperConstructorCall(mv, originalCtorType.getDescriptor());
443
444        endInitMethod(mv);
445    }
446
447    /**
448     * Generates a constructor for the instance adapter class. This constructor will take the same arguments as the supertype
449     * constructor passed as the argument here, and delegate to it. However, it will take an additional argument of
450     * either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize
451     * all the method handle fields of the adapter instance with functions from the script object (or the script
452     * function itself, if that's what's passed). There is one method handle field in the adapter class for every method
453     * that can be implemented or overridden; the name of every field is same as the name of the method, with a number
454     * suffix that makes it unique in case of overloaded methods. The generated constructor will invoke
455     * {@link #getHandle(ScriptFunction, MethodType, boolean)} or {@link #getHandle(Object, String, MethodType,
456     * boolean)} to obtain the method handles; these methods make sure to add the necessary conversions and arity
457     * adjustments so that the resulting method handles can be invoked from generated methods using {@code invokeExact}.
458     * The constructor that takes a script function will only initialize the methods with the same name as the single
459     * abstract method. The constructor will also store the Nashorn global that was current at the constructor
460     * invocation time in a field named "global". The generated constructor will be public, regardless of whether the
461     * supertype constructor was public or protected. The generated constructor will not be variable arity, even if the
462     * supertype constructor was.
463     * @param ctor the supertype constructor that is serving as the base for the generated constructor.
464     * @param fromFunction true if we're generating a constructor that initializes SAM types from a single
465     * ScriptFunction passed to it, false if we're generating a constructor that initializes an arbitrary type from a
466     * ScriptObject passed to it.
467     */
468    private void generateOverridingConstructor(final Constructor<?> ctor, final boolean fromFunction) {
469        final Type originalCtorType = Type.getType(ctor);
470        final Type[] originalArgTypes = originalCtorType.getArgumentTypes();
471        final int argLen = originalArgTypes.length;
472        final Type[] newArgTypes = new Type[argLen + 1];
473
474        // Insert ScriptFunction|ScriptObject as the last argument to the constructor
475        final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : SCRIPT_OBJECT_TYPE;
476        newArgTypes[argLen] = extraArgumentType;
477        System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen);
478
479        // All constructors must be public, even if in the superclass they were protected.
480        // Existing super constructor <init>(this, args...) triggers generating <init>(this, args..., delegate).
481        // Any variable arity constructors become fixed-arity with explicit array arguments.
482        final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
483                Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
484
485        mv.visitCode();
486        // First, invoke super constructor with original arguments.
487        final int extraArgOffset = emitSuperConstructorCall(mv, originalCtorType.getDescriptor());
488
489        // Assign "this.global = Context.getGlobal()"
490        mv.visitVarInsn(ALOAD, 0);
491        GET_NON_NULL_GLOBAL.invoke(mv);
492        mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
493
494        // Assign "this.delegate = delegate"
495        mv.visitVarInsn(ALOAD, 0);
496        mv.visitVarInsn(ALOAD, extraArgOffset);
497        mv.putfield(generatedClassName, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
498
499        if (fromFunction) {
500            // Assign "isFunction = true"
501            mv.visitVarInsn(ALOAD, 0);
502            mv.iconst(1);
503            mv.putfield(generatedClassName, IS_FUNCTION_FIELD_NAME, BOOLEAN_TYPE_DESCRIPTOR);
504
505        mv.visitVarInsn(ALOAD, 0);
506            mv.visitVarInsn(ALOAD, extraArgOffset);
507            emitInitCallThis(mv);
508        }
509
510        endInitMethod(mv);
511
512        if (! fromFunction) {
513            newArgTypes[argLen] = OBJECT_TYPE;
514            final InstructionAdapter mv2 = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
515                    Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
516            generateOverridingConstructorWithObjectParam(mv2, originalCtorType.getDescriptor());
517        }
518    }
519
520    // Object additional param accepting constructor - generated to handle null and undefined value
521    // for script adapters. This is effectively to throw TypeError on such script adapters. See
522    // JavaAdapterServices.getHandle as well.
523    private void generateOverridingConstructorWithObjectParam(final InstructionAdapter mv, final String ctorDescriptor) {
524        mv.visitCode();
525        final int extraArgOffset = emitSuperConstructorCall(mv, ctorDescriptor);
526        mv.visitVarInsn(ALOAD, extraArgOffset);
527        NOT_AN_OBJECT.invoke(mv);
528        endInitMethod(mv);
529    }
530
531    private static void endInitMethod(final InstructionAdapter mv) {
532        mv.visitInsn(RETURN);
533        endMethod(mv);
534    }
535
536    private static void endMethod(final InstructionAdapter mv) {
537        mv.visitMaxs(0, 0);
538        mv.visitEnd();
539    }
540
541    /**
542     * Encapsulation of the information used to generate methods in the adapter classes. Basically, a wrapper around the
543     * reflective Method object, a cached MethodType, and the name of the field in the adapter class that will hold the
544     * method handle serving as the implementation of this method in adapter instances.
545     *
546     */
547    private static class MethodInfo {
548        private final Method method;
549        private final MethodType type;
550
551        private MethodInfo(final Class<?> clazz, final String name, final Class<?>... argTypes) throws NoSuchMethodException {
552            this(clazz.getDeclaredMethod(name, argTypes));
553        }
554
555        private MethodInfo(final Method method) {
556            this.method = method;
557            this.type   = MH.type(method.getReturnType(), method.getParameterTypes());
558        }
559
560        @Override
561        public boolean equals(final Object obj) {
562            return obj instanceof MethodInfo && equals((MethodInfo)obj);
563        }
564
565        private boolean equals(final MethodInfo other) {
566            // Only method name and type are used for comparison; method handle field name is not.
567            return getName().equals(other.getName()) && type.equals(other.type);
568        }
569
570        String getName() {
571            return method.getName();
572        }
573
574        @Override
575        public int hashCode() {
576            return getName().hashCode() ^ type.hashCode();
577        }
578    }
579
580    private void generateMethods() {
581        for(final MethodInfo mi: methodInfos) {
582            generateMethod(mi);
583        }
584    }
585
586    /**
587     * Generates a method in the adapter class that adapts a method from the
588     * original class. The generated method will either invoke the delegate
589     * using a CALL dynamic operation call site (if it is a SAM method and the
590     * delegate is a ScriptFunction), or invoke GET_METHOD_PROPERTY dynamic
591     * operation with the method name as the argument and then invoke the
592     * returned ScriptFunction using the CALL dynamic operation. If
593     * GET_METHOD_PROPERTY returns null or undefined (that is, the JS object
594     * doesn't provide an implementation for the method) then the method will
595     * either do a super invocation to base class, or if the method is abstract,
596     * throw an {@link UnsupportedOperationException}. Finally, if
597     * GET_METHOD_PROPERTY returns something other than a ScriptFunction, null,
598     * or undefined, a TypeError is thrown. The current Global is checked before
599     * the dynamic operations, and if it is different  than the Global used to
600     * create the adapter, the creating Global is set to be the current Global.
601     * In this case, the previously current Global is restored after the
602     * invocation. If CALL results in a Throwable that is not one of the
603     * method's declared exceptions, and is not an unchecked throwable, then it
604     * is wrapped into a {@link RuntimeException} and the runtime exception is
605     * thrown.
606     * @param mi the method info describing the method to be generated.
607     */
608    private void generateMethod(final MethodInfo mi) {
609        final Method method = mi.method;
610        final Class<?>[] exceptions = method.getExceptionTypes();
611        final String[] exceptionNames = getExceptionNames(exceptions);
612        final MethodType type = mi.type;
613        final String methodDesc = type.toMethodDescriptorString();
614        final String name = mi.getName();
615
616        final Type asmType = Type.getMethodType(methodDesc);
617        final Type[] asmArgTypes = asmType.getArgumentTypes();
618
619        final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), name,
620                methodDesc, null, exceptionNames));
621        mv.visitCode();
622
623        final Class<?> returnType = type.returnType();
624        final Type asmReturnType = Type.getType(returnType);
625
626        // Determine the first index for a local variable
627        int nextLocalVar = 1; // "this" is at 0
628        for(final Type t: asmArgTypes) {
629            nextLocalVar += t.getSize();
630        }
631        // Set our local variable index
632        final int globalRestoringRunnableVar = nextLocalVar++;
633
634        // Load the creatingGlobal object
635        loadField(mv, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
636
637        // stack: [creatingGlobal]
638        SET_GLOBAL.invoke(mv);
639        // stack: [runnable]
640        mv.visitVarInsn(ASTORE, globalRestoringRunnableVar);
641        // stack: []
642
643        final Label tryBlockStart = new Label();
644        mv.visitLabel(tryBlockStart);
645
646        final Label callCallee = new Label();
647        final Label defaultBehavior = new Label();
648        // If this is a SAM type...
649        if (samName != null) {
650            // ...every method will be checking whether we're initialized with a
651            // function.
652            loadField(mv, IS_FUNCTION_FIELD_NAME, BOOLEAN_TYPE_DESCRIPTOR);
653            // stack: [isFunction]
654            if (name.equals(samName)) {
655                final Label notFunction = new Label();
656                mv.ifeq(notFunction);
657                // stack: []
658                // If it's a SAM method, it'll load delegate as the "callee" and
659                // "callThis" as "this" for the call if delegate is a function.
660                loadField(mv, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
661                // NOTE: if we added "mv.checkcast(SCRIPT_FUNCTION_TYPE);" here
662                // we could emit the invokedynamic CALL instruction with signature
663                // (ScriptFunction, Object, ...) instead of (Object, Object, ...).
664                // We could combine this with an optimization in
665                // ScriptFunction.findCallMethod where it could link a call with a
666                // thinner guard when the call site statically guarantees that the
667                // callee argument is a ScriptFunction. Additionally, we could use
668                // a "ScriptFunction function" field in generated classes instead
669                // of a "boolean isFunction" field to avoid the checkcast.
670                loadField(mv, CALL_THIS_FIELD_NAME, OBJECT_TYPE_DESCRIPTOR);
671                // stack: [callThis, delegate]
672                mv.goTo(callCallee);
673                mv.visitLabel(notFunction);
674        } else {
675                // If it's not a SAM method, and the delegate is a function,
676                // it'll fall back to default behavior
677                mv.ifne(defaultBehavior);
678                // stack: []
679            }
680        }
681
682        // At this point, this is either not a SAM method or the delegate is
683        // not a ScriptFunction. We need to emit a GET_METHOD_PROPERTY Nashorn
684        // invokedynamic.
685
686        if(name.equals("toString")) {
687            // Since every JS Object has a toString, we only override
688            // "String toString()" it if it's explicitly specified on the object.
689            loadField(mv, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
690            // stack: [delegate]
691            HAS_OWN_TO_STRING.invoke(mv);
692            // stack: [hasOwnToString]
693            mv.ifeq(defaultBehavior);
694        }
695
696        loadField(mv, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
697        mv.dup();
698        // stack: [delegate, delegate]
699        final String encodedName = NameCodec.encode(name);
700        mv.visitInvokeDynamicInsn(encodedName,
701                GET_METHOD_PROPERTY_METHOD_DESCRIPTOR, BOOTSTRAP_HANDLE,
702                NashornCallSiteDescriptor.GET_METHOD_PROPERTY);
703        // stack: [callee, delegate]
704        mv.visitLdcInsn(name);
705        // stack: [name, callee, delegate]
706        CHECK_FUNCTION.invoke(mv);
707        // stack: [fnCalleeOrNull, delegate]
708        final Label hasFunction = new Label();
709        mv.dup();
710        // stack: [fnCalleeOrNull, fnCalleeOrNull, delegate]
711        mv.ifnonnull(hasFunction);
712        // stack: [null, delegate]
713        // If it's null or undefined, clear stack and fall back to default
714        // behavior.
715        mv.pop2();
716        // stack: []
717
718        // We can also arrive here from check for "delegate instanceof ScriptFunction"
719        // in a non-SAM method as well as from a check for "hasOwnToString(delegate)"
720        // for a toString delegate.
721        mv.visitLabel(defaultBehavior);
722        final Runnable emitFinally = ()->emitFinally(mv, globalRestoringRunnableVar);
723        final Label normalFinally = new Label();
724        if(Modifier.isAbstract(method.getModifiers())) {
725            // If the super method is abstract, throw UnsupportedOperationException
726            UNSUPPORTED.invoke(mv);
727            // NOTE: no need to invoke emitFinally.run() as we're inside the
728            // tryBlockStart/tryBlockEnd range, so throwing this exception will
729            // transfer control to the rethrow handler and the finally block in it
730            // will execute.
731            mv.athrow();
732        } else {
733            // If the super method is not abstract, delegate to it.
734            emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc);
735            mv.goTo(normalFinally);
736        }
737
738        mv.visitLabel(hasFunction);
739        // stack: [callee, delegate]
740        mv.swap();
741        // stack [delegate, callee]
742        mv.visitLabel(callCallee);
743
744
745        // Load all parameters back on stack for dynamic invocation.
746
747        int varOffset = 1;
748        // If the param list length is more than 253 slots, we can't invoke it
749        // directly as with (callee, this) it'll exceed 255.
750        final boolean isVarArgCall = getParamListLengthInSlots(asmArgTypes) > 253;
751        for (final Type t : asmArgTypes) {
752            mv.load(varOffset, t);
753            convertParam(mv, t, isVarArgCall);
754            varOffset += t.getSize();
755        }
756        // stack: [args..., callee, delegate]
757
758        // If the resulting parameter list length is too long...
759        if (isVarArgCall) {
760            // ... we pack the parameters (except callee and this) into an array
761            // and use Nashorn vararg invocation.
762            mv.visitInvokeDynamicInsn(NameCodec.EMPTY_NAME,
763                    getArrayCreatorMethodType(type).toMethodDescriptorString(),
764                    CREATE_ARRAY_BOOTSTRAP_HANDLE);
765        }
766
767        // Invoke the target method handle
768        mv.visitInvokeDynamicInsn(encodedName,
769                getCallMethodType(isVarArgCall, type).toMethodDescriptorString(),
770                BOOTSTRAP_HANDLE, NashornCallSiteDescriptor.CALL);
771        // stack: [returnValue]
772        convertReturnValue(mv, returnType);
773        mv.visitLabel(normalFinally);
774        emitFinally.run();
775        mv.areturn(asmReturnType);
776
777        // If Throwable is not declared, we need an adapter from Throwable to RuntimeException
778        final boolean throwableDeclared = isThrowableDeclared(exceptions);
779        final Label throwableHandler;
780        if (!throwableDeclared) {
781            // Add "throw new RuntimeException(Throwable)" handler for Throwable
782            throwableHandler = new Label();
783            mv.visitLabel(throwableHandler);
784            WRAP_THROWABLE.invoke(mv);
785            // Fall through to rethrow handler
786        } else {
787            throwableHandler = null;
788        }
789        final Label rethrowHandler = new Label();
790        mv.visitLabel(rethrowHandler);
791        // Rethrow handler for RuntimeException, Error, and all declared exception types
792        emitFinally.run();
793        mv.athrow();
794
795        if(throwableDeclared) {
796            mv.visitTryCatchBlock(tryBlockStart, normalFinally, rethrowHandler, THROWABLE_TYPE_NAME);
797            assert throwableHandler == null;
798        } else {
799            mv.visitTryCatchBlock(tryBlockStart, normalFinally, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME);
800            mv.visitTryCatchBlock(tryBlockStart, normalFinally, rethrowHandler, ERROR_TYPE_NAME);
801            for(final String excName: exceptionNames) {
802                mv.visitTryCatchBlock(tryBlockStart, normalFinally, rethrowHandler, excName);
803            }
804            mv.visitTryCatchBlock(tryBlockStart, normalFinally, throwableHandler, THROWABLE_TYPE_NAME);
805        }
806        endMethod(mv);
807    }
808
809    private static MethodType getCallMethodType(final boolean isVarArgCall, final MethodType type) {
810        final Class<?>[] callParamTypes;
811        if (isVarArgCall) {
812            // Variable arity calls are always (Object callee, Object this, Object[] params)
813            callParamTypes = new Class<?>[] { Object.class, Object.class, Object[].class };
814            } else {
815            // Adjust invocation type signature for conversions we instituted in
816            // convertParam; also, byte and short get passed as ints.
817            final Class<?>[] origParamTypes = type.parameterArray();
818            callParamTypes = new Class<?>[origParamTypes.length + 2];
819            callParamTypes[0] = Object.class; // callee; could be ScriptFunction.class ostensibly
820            callParamTypes[1] = Object.class; // this
821            for(int i = 0; i < origParamTypes.length; ++i) {
822                callParamTypes[i + 2] = getNashornParamType(origParamTypes[i], false);
823            }
824        }
825        return MethodType.methodType(getNashornReturnType(type.returnType()), callParamTypes);
826    }
827
828    private static MethodType getArrayCreatorMethodType(final MethodType type) {
829        final Class<?>[] callParamTypes = type.parameterArray();
830        for(int i = 0; i < callParamTypes.length; ++i) {
831            callParamTypes[i] = getNashornParamType(callParamTypes[i], true);
832        }
833        return MethodType.methodType(Object[].class, callParamTypes);
834    }
835
836    private static Class<?> getNashornParamType(final Class<?> clazz, final boolean varArg) {
837        if (clazz == byte.class || clazz == short.class) {
838            return int.class;
839        } else if (clazz == float.class) {
840            // If using variable arity, we'll pass a Double instead of double
841            // so that floats don't extend the length of the parameter list.
842            // We return Object.class instead of Double.class though as the
843            // array collector will anyway operate on Object.
844            return varArg ? Object.class : double.class;
845        } else if (!clazz.isPrimitive() || clazz == long.class || clazz == char.class) {
846            return Object.class;
847        }
848        return clazz;
849    }
850
851    private static Class<?> getNashornReturnType(final Class<?> clazz) {
852        if (clazz == byte.class || clazz == short.class) {
853            return int.class;
854        } else if (clazz == float.class) {
855            return double.class;
856        } else if (clazz == void.class || clazz == char.class) {
857            return Object.class;
858        }
859        return clazz;
860    }
861
862
863    private void loadField(final InstructionAdapter mv, final String name, final String desc) {
864                if(classOverride) {
865            mv.getstatic(generatedClassName, name, desc);
866                } else {
867                    mv.visitVarInsn(ALOAD, 0);
868            mv.getfield(generatedClassName, name, desc);
869                }
870            }
871
872    private static void convertReturnValue(final InstructionAdapter mv, final Class<?> origReturnType) {
873        if (origReturnType == void.class) {
874            mv.pop();
875        } else if (origReturnType == Object.class) {
876            // Must hide ConsString (and potentially other internal Nashorn types) from callers
877            EXPORT_RETURN_VALUE.invoke(mv);
878        } else if (origReturnType == byte.class) {
879            mv.visitInsn(I2B);
880        } else if (origReturnType == short.class) {
881            mv.visitInsn(I2S);
882        } else if (origReturnType == float.class) {
883            mv.visitInsn(D2F);
884        } else if (origReturnType == char.class) {
885            TO_CHAR_PRIMITIVE.invoke(mv);
886        }
887    }
888
889    /**
890     * Emits instruction for converting a parameter on the top of the stack to
891     * a type that is understood by Nashorn.
892     * @param mv the current method visitor
893     * @param t the type on the top of the stack
894     * @param varArg if the invocation will be variable arity
895     */
896    private static void convertParam(final InstructionAdapter mv, final Type t, final boolean varArg) {
897        // We perform conversions of some primitives to accommodate types that
898        // Nashorn can handle.
899        switch(t.getSort()) {
900        case Type.CHAR:
901            // Chars are boxed, as we don't know if the JS code wants to treat
902            // them as an effective "unsigned short" or as a single-char string.
903            CHAR_VALUE_OF.invoke(mv);
904            break;
905        case Type.FLOAT:
906            // Floats are widened to double.
907            mv.visitInsn(Opcodes.F2D);
908            if (varArg) {
909                // We'll be boxing everything anyway for the vararg invocation,
910                // so we might as well do it proactively here and thus not cause
911                // a widening in the number of slots, as that could even make
912                // the array creation invocation go over 255 param slots.
913                DOUBLE_VALUE_OF.invoke(mv);
914            }
915            break;
916        case Type.LONG:
917            // Longs are boxed as Nashorn can't represent them precisely as a
918            // primitive number.
919            LONG_VALUE_OF.invoke(mv);
920            break;
921        case Type.OBJECT:
922            if(t.equals(OBJECT_TYPE)) {
923                // Object can carry a ScriptObjectMirror and needs to be unwrapped
924                // before passing into a Nashorn function.
925                UNWRAP.invoke(mv);
926            }
927            break;
928        }
929    }
930
931    private static int getParamListLengthInSlots(final Type[] paramTypes) {
932        int len = paramTypes.length;
933        for(final Type t: paramTypes) {
934            final int sort = t.getSort();
935            if (sort == Type.FLOAT || sort == Type.DOUBLE) {
936                // Floats are widened to double, so they'll take up two slots.
937                // Longs on the other hand are always boxed, so their width
938                // becomes 1 and thus they don't contribute an extra slot here.
939                ++len;
940            }
941        }
942        return len;
943    }
944    /**
945     * Emit code to restore the previous Nashorn Context when needed.
946     * @param mv the instruction adapter
947     * @param globalRestoringRunnableVar index of the local variable holding the reference to the global restoring Runnable
948     */
949    private static void emitFinally(final InstructionAdapter mv, final int globalRestoringRunnableVar) {
950        mv.visitVarInsn(ALOAD, globalRestoringRunnableVar);
951        RUN.invoke(mv);
952    }
953
954    private static boolean isThrowableDeclared(final Class<?>[] exceptions) {
955        for (final Class<?> exception : exceptions) {
956            if (exception == Throwable.class) {
957                return true;
958            }
959        }
960        return false;
961    }
962
963    private void generateSuperMethods() {
964        for(final MethodInfo mi: methodInfos) {
965            if(!Modifier.isAbstract(mi.method.getModifiers())) {
966                generateSuperMethod(mi);
967            }
968        }
969    }
970
971    private void generateSuperMethod(final MethodInfo mi) {
972        final Method method = mi.method;
973
974        final String methodDesc = mi.type.toMethodDescriptorString();
975        final String name = mi.getName();
976
977        final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method),
978                SUPER_PREFIX + name, methodDesc, null, getExceptionNames(method.getExceptionTypes())));
979        mv.visitCode();
980
981        emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc);
982        mv.areturn(Type.getType(mi.type.returnType()));
983        endMethod(mv);
984    }
985
986    // find the appropriate super type to use for invokespecial on the given interface
987    private Class<?> findInvokespecialOwnerFor(final Class<?> cl) {
988        assert Modifier.isInterface(cl.getModifiers()) : cl + " is not an interface";
989
990        if (cl.isAssignableFrom(superClass)) {
991            return superClass;
992        }
993
994        for (final Class<?> iface : interfaces) {
995             if (cl.isAssignableFrom(iface)) {
996                 return iface;
997             }
998        }
999
1000        // we better that interface that extends the given interface!
1001        throw new AssertionError("can't find the class/interface that extends " + cl);
1002    }
1003
1004    private int emitSuperConstructorCall(final InstructionAdapter mv, final String methodDesc) {
1005        return emitSuperCall(mv, null, INIT, methodDesc, true);
1006    }
1007
1008    private int emitSuperCall(final InstructionAdapter mv, final Class<?> owner, final String name, final String methodDesc) {
1009        return emitSuperCall(mv, owner, name, methodDesc, false);
1010    }
1011
1012    private int emitSuperCall(final InstructionAdapter mv, final Class<?> owner, final String name, final String methodDesc, final boolean constructor) {
1013        mv.visitVarInsn(ALOAD, 0);
1014        int nextParam = 1;
1015        final Type methodType = Type.getMethodType(methodDesc);
1016        for(final Type t: methodType.getArgumentTypes()) {
1017            mv.load(nextParam, t);
1018            nextParam += t.getSize();
1019        }
1020
1021        // default method - non-abstract, interface method
1022        if (!constructor && Modifier.isInterface(owner.getModifiers())) {
1023            // we should call default method on the immediate "super" type - not on (possibly)
1024            // the indirectly inherited interface class!
1025            mv.invokespecial(Type.getInternalName(findInvokespecialOwnerFor(owner)), name, methodDesc, false);
1026        } else {
1027            mv.invokespecial(superClassName, name, methodDesc, false);
1028        }
1029        return nextParam;
1030    }
1031
1032    private void generateFinalizerMethods() {
1033        generateFinalizerDelegate();
1034        generateFinalizerOverride();
1035    }
1036
1037    private void generateFinalizerDelegate() {
1038        // Generate a delegate that will be invoked from the no-permission trampoline. Note it can be private, as we'll
1039        // refer to it with a MethodHandle constant pool entry in the overridden finalize() method (see
1040        // generateFinalizerOverride()).
1041        final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PRIVATE | ACC_STATIC,
1042                FINALIZER_DELEGATE_NAME, FINALIZER_DELEGATE_METHOD_DESCRIPTOR, null, null));
1043
1044        // Simply invoke super.finalize()
1045        mv.visitVarInsn(ALOAD, 0);
1046        mv.checkcast(Type.getType(generatedClassName));
1047        mv.invokespecial(superClassName, "finalize", VOID_METHOD_DESCRIPTOR, false);
1048
1049        mv.visitInsn(RETURN);
1050        endMethod(mv);
1051    }
1052
1053    @SuppressWarnings("deprecation")
1054    private void generateFinalizerOverride() {
1055        final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, "finalize",
1056                VOID_METHOD_DESCRIPTOR, null, null));
1057        // Overridden finalizer will take a MethodHandle to the finalizer delegating method, ...
1058        mv.aconst(new Handle(Opcodes.H_INVOKESTATIC, generatedClassName, FINALIZER_DELEGATE_NAME,
1059                FINALIZER_DELEGATE_METHOD_DESCRIPTOR));
1060        mv.visitVarInsn(ALOAD, 0);
1061        // ...and invoke it through JavaAdapterServices.invokeNoPermissions
1062        INVOKE_NO_PERMISSIONS.invoke(mv);
1063        mv.visitInsn(RETURN);
1064        endMethod(mv);
1065    }
1066
1067    private static String[] getExceptionNames(final Class<?>[] exceptions) {
1068        final String[] exceptionNames = new String[exceptions.length];
1069        for (int i = 0; i < exceptions.length; ++i) {
1070            exceptionNames[i] = Type.getInternalName(exceptions[i]);
1071        }
1072        return exceptionNames;
1073    }
1074
1075    private static int getAccessModifiers(final Method method) {
1076        return ACC_PUBLIC | (method.isVarArgs() ? ACC_VARARGS : 0);
1077    }
1078
1079    /**
1080     * Gathers methods that can be implemented or overridden from the specified type into this factory's
1081     * {@link #methodInfos} set. It will add all non-final, non-static methods that are either public or protected from
1082     * the type if the type itself is public. If the type is a class, the method will recursively invoke itself for its
1083     * superclass and the interfaces it implements, and add further methods that were not directly declared on the
1084     * class.
1085     * @param type the type defining the methods.
1086     */
1087    private void gatherMethods(final Class<?> type) throws AdaptationException {
1088        if (Modifier.isPublic(type.getModifiers())) {
1089            final Module module = type.getModule();
1090            if (module != null) {
1091                accessedModules.add(module);
1092            }
1093
1094            final Method[] typeMethods = type.isInterface() ? type.getMethods() : type.getDeclaredMethods();
1095
1096            for (final Method typeMethod: typeMethods) {
1097                final String name = typeMethod.getName();
1098                if(name.startsWith(SUPER_PREFIX)) {
1099                    continue;
1100                }
1101                final int m = typeMethod.getModifiers();
1102                if (Modifier.isStatic(m)) {
1103                    continue;
1104                }
1105                if (Modifier.isPublic(m) || Modifier.isProtected(m)) {
1106                    // Is it a "finalize()"?
1107                    if(name.equals("finalize") && typeMethod.getParameterCount() == 0) {
1108                        if(type != Object.class) {
1109                            hasExplicitFinalizer = true;
1110                            if(Modifier.isFinal(m)) {
1111                                // Must be able to override an explicit finalizer
1112                                throw new AdaptationException(Outcome.ERROR_FINAL_FINALIZER, type.getCanonicalName());
1113                            }
1114                        }
1115                        continue;
1116                    }
1117
1118                    for (final Class<?> pt : typeMethod.getParameterTypes()) {
1119                        if (pt.isPrimitive()) continue;
1120                        final Module ptMod = pt.getModule();
1121                        if (ptMod != null) {
1122                            accessedModules.add(ptMod);
1123                        }
1124                    }
1125
1126                    final Class<?> rt = typeMethod.getReturnType();
1127                    if (!rt.isPrimitive()) {
1128                        final Module rtMod = rt.getModule();
1129                        if (rtMod != null) accessedModules.add(rtMod);
1130                    }
1131
1132                    final MethodInfo mi = new MethodInfo(typeMethod);
1133                    if (Modifier.isFinal(m) || isCallerSensitive(typeMethod)) {
1134                        finalMethods.add(mi);
1135                    } else if (!finalMethods.contains(mi) && methodInfos.add(mi) && Modifier.isAbstract(m)) {
1136                            abstractMethodNames.add(mi.getName());
1137                        }
1138                }
1139            }
1140        }
1141        // If the type is a class, visit its superclasses and declared interfaces. If it's an interface, we're done.
1142        // Needing to invoke the method recursively for a non-interface Class object is the consequence of needing to
1143        // see all declared protected methods, and Class.getDeclaredMethods() doesn't provide those declared in a
1144        // superclass. For interfaces, we used Class.getMethods(), as we're only interested in public ones there, and
1145        // getMethods() does provide those declared in a superinterface.
1146        if (!type.isInterface()) {
1147            final Class<?> superType = type.getSuperclass();
1148            if (superType != null) {
1149                gatherMethods(superType);
1150            }
1151            for (final Class<?> itf: type.getInterfaces()) {
1152                gatherMethods(itf);
1153            }
1154        }
1155    }
1156
1157    private void gatherMethods(final List<Class<?>> classes) throws AdaptationException {
1158        for(final Class<?> c: classes) {
1159            gatherMethods(c);
1160        }
1161    }
1162
1163    private static final AccessControlContext GET_DECLARED_MEMBERS_ACC_CTXT = ClassAndLoader.createPermAccCtxt("accessDeclaredMembers");
1164
1165    /**
1166     * Creates a collection of methods that are not final, but we still never allow them to be overridden in adapters,
1167     * as explicitly declaring them automatically is a bad idea. Currently, this means {@code Object.finalize()} and
1168     * {@code Object.clone()}.
1169     * @return a collection of method infos representing those methods that we never override in adapter classes.
1170     */
1171    private static Collection<MethodInfo> getExcludedMethods() {
1172        return AccessController.doPrivileged(new PrivilegedAction<Collection<MethodInfo>>() {
1173            @Override
1174            public Collection<MethodInfo> run() {
1175                try {
1176                    return Arrays.asList(
1177                            new MethodInfo(Object.class, "finalize"),
1178                            new MethodInfo(Object.class, "clone"));
1179                } catch (final NoSuchMethodException e) {
1180                    throw new AssertionError(e);
1181                }
1182            }
1183        }, GET_DECLARED_MEMBERS_ACC_CTXT);
1184    }
1185
1186    private String getCommonSuperClass(final String type1, final String type2) {
1187        try {
1188            final Class<?> c1 = Class.forName(type1.replace('/', '.'), false, commonLoader);
1189            final Class<?> c2 = Class.forName(type2.replace('/', '.'), false, commonLoader);
1190            if (c1.isAssignableFrom(c2)) {
1191                return type1;
1192            }
1193            if (c2.isAssignableFrom(c1)) {
1194                return type2;
1195            }
1196            if (c1.isInterface() || c2.isInterface()) {
1197                return OBJECT_TYPE.getInternalName();
1198            }
1199            return assignableSuperClass(c1, c2).getName().replace('.', '/');
1200        } catch(final ClassNotFoundException e) {
1201            throw new RuntimeException(e);
1202        }
1203    }
1204
1205    private static Class<?> assignableSuperClass(final Class<?> c1, final Class<?> c2) {
1206        final Class<?> superClass = c1.getSuperclass();
1207        return superClass.isAssignableFrom(c2) ? superClass : assignableSuperClass(superClass, c2);
1208    }
1209
1210    private static boolean isCallerSensitive(final AccessibleObject e) {
1211        return e.isAnnotationPresent(CallerSensitive.class);
1212    }
1213
1214    private static final Call lookupServiceMethod(final String name, final Class<?> rtype, final Class<?>... ptypes) {
1215        return staticCallNoLookup(JavaAdapterServices.class, name, rtype, ptypes);
1216    }
1217}
1218