src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java

Thu, 10 Sep 2015 09:59:23 +0530

author
sundar
date
Thu, 10 Sep 2015 09:59:23 +0530
changeset 1526
d731e6ba5037
parent 1416
7095ada9fc82
child 1550
e9ea7010825b
permissions
-rw-r--r--

8130888: Typos in nashorn sources
Reviewed-by: hannesw, mhaupt

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

mercurial