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