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

Thu, 24 May 2018 16:39:31 +0800

author
aoqi
date
Thu, 24 May 2018 16:39:31 +0800
changeset 1959
61ffdd1b89f2
parent 1550
e9ea7010825b
parent 1490
d85f981c8cf8
permissions
-rw-r--r--

Merge

     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     // Interfaces implemented by our generated adapter.
   207     private final List<Class<?>> interfaces;
   208     // Class loader used as the parent for the class loader we'll create to load the generated class. It will be a class
   209     // loader that has the visibility of all original types (class to extend and interfaces to implement) and of the
   210     // Nashorn classes.
   211     private final ClassLoader commonLoader;
   212     // Is this a generator for the version of the class that can have overrides on the class level?
   213     private final boolean classOverride;
   214     // Binary name of the superClass
   215     private final String superClassName;
   216     // Binary name of the generated class.
   217     private final String generatedClassName;
   218     private final Set<String> usedFieldNames = new HashSet<>();
   219     private final Set<String> abstractMethodNames = new HashSet<>();
   220     private final String samName;
   221     private final Set<MethodInfo> finalMethods = new HashSet<>(EXCLUDED);
   222     private final Set<MethodInfo> methodInfos = new HashSet<>();
   223     private boolean autoConvertibleFromFunction = false;
   224     private boolean hasExplicitFinalizer = false;
   226     /**
   227      * Names of static fields holding type converter method handles for return value conversion. We are emitting code
   228      * for invoking these explicitly after the delegate handle is invoked, instead of doing an asType or
   229      * filterReturnValue on the delegate handle, as that would create a new converter handle wrapping the function's
   230      * handle for every instance of the adapter, causing the handle.invokeExact() call sites to become megamorphic.
   231      */
   232     private final Map<Class<?>, String> converterFields = new LinkedHashMap<>();
   234     /**
   235      * Subset of possible return types for all methods; namely, all possible return types of the SAM methods (we
   236      * identify SAM types by having all of their abstract methods share a single name, so there can be multiple
   237      * overloads with multiple return types. We use this set when emitting the constructor taking a ScriptFunction (the
   238      * SAM initializer) to avoid populating converter fields that will never be used by SAM methods.
   239      */
   240     private final Set<Class<?>> samReturnTypes = new HashSet<>();
   242     private final ClassWriter cw;
   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;
   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);
   273         cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER, generatedClassName, null, superClassName, getInternalTypeNames(interfaces));
   274         generateGlobalFields();
   276         gatherMethods(superClass);
   277         gatherMethods(interfaces);
   278         samName = abstractMethodNames.size() == 1 ? abstractMethodNames.iterator().next() : null;
   279         generateHandleFields();
   280         generateConverterFields();
   281         if(classOverride) {
   282             generateClassInit();
   283         }
   284         generateConstructors();
   285         generateMethods();
   286         generateSuperMethods();
   287         if (hasExplicitFinalizer) {
   288             generateFinalizerMethods();
   289         }
   290         // }
   291         cw.visitEnd();
   292     }
   294     private void generateGlobalFields() {
   295         cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR, null, null).visitEnd();
   296         usedFieldNames.add(GLOBAL_FIELD_NAME);
   297     }
   299     JavaAdapterClassLoader createAdapterClassLoader() {
   300         return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray());
   301     }
   303     boolean isAutoConvertibleFromFunction() {
   304         return autoConvertibleFromFunction;
   305     }
   307     private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) {
   308         // The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're
   309         // just implementing interfaces or extending Object), then the first implemented interface or Object.
   310         final Class<?> namingType = superType == Object.class ? (interfaces.isEmpty()? Object.class : interfaces.get(0)) : superType;
   311         final Package pkg = namingType.getPackage();
   312         final String namingTypeName = Type.getInternalName(namingType);
   313         final StringBuilder buf = new StringBuilder();
   314         if (namingTypeName.startsWith(JAVA_PACKAGE_PREFIX) || pkg == null || pkg.isSealed()) {
   315             // Can't define new classes in java.* packages
   316             buf.append(ADAPTER_PACKAGE_PREFIX).append(namingTypeName);
   317         } else {
   318             buf.append(namingTypeName).append(ADAPTER_CLASS_NAME_SUFFIX);
   319         }
   320         final Iterator<Class<?>> it = interfaces.iterator();
   321         if(superType == Object.class && it.hasNext()) {
   322             it.next(); // Skip first interface, it was used to primarily name the adapter
   323         }
   324         // Append interface names to the adapter name
   325         while(it.hasNext()) {
   326             buf.append("$$").append(it.next().getSimpleName());
   327         }
   328         return buf.toString().substring(0, Math.min(MAX_GENERATED_TYPE_NAME_LENGTH, buf.length()));
   329     }
   331     /**
   332      * Given a list of class objects, return an array with their binary names. Used to generate the array of interface
   333      * names to implement.
   334      * @param classes the classes
   335      * @return an array of names
   336      */
   337     private static String[] getInternalTypeNames(final List<Class<?>> classes) {
   338         final int interfaceCount = classes.size();
   339         final String[] interfaceNames = new String[interfaceCount];
   340         for(int i = 0; i < interfaceCount; ++i) {
   341             interfaceNames[i] = Type.getInternalName(classes.get(i));
   342         }
   343         return interfaceNames;
   344     }
   346     private void generateHandleFields() {
   347         final int flags = ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0);
   348         for (final MethodInfo mi: methodInfos) {
   349             cw.visitField(flags, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR, null, null).visitEnd();
   350         }
   351     }
   353     private void generateConverterFields() {
   354         final int flags = ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0);
   355         for (final MethodInfo mi: methodInfos) {
   356             final Class<?> returnType = mi.type.returnType();
   357             // Handle primitive types, Object, and String specially
   358             if(!returnType.isPrimitive() && returnType != Object.class && returnType != String.class) {
   359                 if(!converterFields.containsKey(returnType)) {
   360                     final String name = nextName("convert");
   361                     converterFields.put(returnType, name);
   362                     if(mi.getName().equals(samName)) {
   363                         samReturnTypes.add(returnType);
   364                     }
   365                     cw.visitField(flags, name, METHOD_HANDLE_TYPE_DESCRIPTOR, null, null).visitEnd();
   366                 }
   367             }
   368         }
   369     }
   371     private void generateClassInit() {
   372         final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_STATIC, CLASS_INIT,
   373                 Type.getMethodDescriptor(Type.VOID_TYPE), null, null));
   375         mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getClassOverrides", GET_CLASS_INITIALIZER_DESCRIPTOR, false);
   376         final Label initGlobal;
   377         if(samName != null) {
   378             // If the class is a SAM, allow having a ScriptFunction passed as class overrides
   379             final Label notAFunction = new Label();
   380             mv.dup();
   381             mv.instanceOf(SCRIPT_FUNCTION_TYPE);
   382             mv.ifeq(notAFunction);
   383             mv.checkcast(SCRIPT_FUNCTION_TYPE);
   385             // Assign MethodHandle fields through invoking getHandle() for a ScriptFunction, only assigning the SAM
   386             // method(s).
   387             for (final MethodInfo mi : methodInfos) {
   388                 if(mi.getName().equals(samName)) {
   389                     mv.dup();
   390                     loadMethodTypeAndGetHandle(mv, mi, GET_HANDLE_FUNCTION_DESCRIPTOR);
   391                 } else {
   392                     mv.visitInsn(ACONST_NULL);
   393                 }
   394                 mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
   395             }
   396             initGlobal = new Label();
   397             mv.goTo(initGlobal);
   398             mv.visitLabel(notAFunction);
   399         } else {
   400             initGlobal = null;
   401         }
   402         // Assign MethodHandle fields through invoking getHandle() for a ScriptObject
   403         for (final MethodInfo mi : methodInfos) {
   404             mv.dup();
   405             mv.aconst(mi.getName());
   406             loadMethodTypeAndGetHandle(mv, mi, GET_HANDLE_OBJECT_DESCRIPTOR);
   407             mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
   408         }
   410         if(initGlobal != null) {
   411             mv.visitLabel(initGlobal);
   412         }
   413         // Assign "global = Context.getGlobal()"
   414         invokeGetGlobalWithNullCheck(mv);
   415         mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
   417         generateConverterInit(mv, false);
   418         endInitMethod(mv);
   419     }
   421     private void generateConverterInit(final InstructionAdapter mv, final boolean samOnly) {
   422         assert !samOnly || !classOverride;
   423         for(final Map.Entry<Class<?>, String> converterField: converterFields.entrySet()) {
   424             final Class<?> returnType = converterField.getKey();
   425             if(!classOverride) {
   426                 mv.visitVarInsn(ALOAD, 0);
   427             }
   429             if(samOnly && !samReturnTypes.contains(returnType)) {
   430                 mv.visitInsn(ACONST_NULL);
   431             } else {
   432                 mv.aconst(Type.getType(converterField.getKey()));
   433                 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getObjectConverter", GET_CONVERTER_METHOD_DESCRIPTOR, false);
   434             }
   436             if(classOverride) {
   437                 mv.putstatic(generatedClassName, converterField.getValue(), METHOD_HANDLE_TYPE_DESCRIPTOR);
   438             } else {
   439                 mv.putfield(generatedClassName, converterField.getValue(), METHOD_HANDLE_TYPE_DESCRIPTOR);
   440             }
   441         }
   442     }
   444     private static void loadMethodTypeAndGetHandle(final InstructionAdapter mv, final MethodInfo mi, final String getHandleDescriptor) {
   445         // NOTE: we're using generic() here because we'll be linking to the "generic" invoker version of
   446         // the functions anyway, so we cut down on megamorphism in the invokeExact() calls in adapter
   447         // bodies. Once we start linking to type-specializing invokers, this should be changed.
   448         mv.aconst(Type.getMethodType(mi.type.generic().toMethodDescriptorString()));
   449         mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor, false);
   450     }
   452     private static void invokeGetGlobalWithNullCheck(final InstructionAdapter mv) {
   453         invokeGetGlobal(mv);
   454         mv.dup();
   455         mv.invokevirtual(OBJECT_TYPE_NAME, "getClass", GET_CLASS_METHOD_DESCRIPTOR, false); // check against null Context
   456         mv.pop();
   457     }
   459     private void generateConstructors() throws AdaptationException {
   460         boolean gotCtor = false;
   461         for (final Constructor<?> ctor: superClass.getDeclaredConstructors()) {
   462             final int modifier = ctor.getModifiers();
   463             if((modifier & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0 && !isCallerSensitive(ctor)) {
   464                 generateConstructors(ctor);
   465                 gotCtor = true;
   466             }
   467         }
   468         if(!gotCtor) {
   469             throw new AdaptationException(ERROR_NO_ACCESSIBLE_CONSTRUCTOR, superClass.getCanonicalName());
   470         }
   471     }
   473     private void generateConstructors(final Constructor<?> ctor) {
   474         if(classOverride) {
   475             // Generate a constructor that just delegates to ctor. This is used with class-level overrides, when we want
   476             // to create instances without further per-instance overrides.
   477             generateDelegatingConstructor(ctor);
   478         } else {
   479             // Generate a constructor that delegates to ctor, but takes an additional ScriptObject parameter at the
   480             // beginning of its parameter list.
   481             generateOverridingConstructor(ctor, false);
   483             if (samName != null) {
   484                 if (!autoConvertibleFromFunction && ctor.getParameterTypes().length == 0) {
   485                     // If the original type only has a single abstract method name, as well as a default ctor, then it can
   486                     // be automatically converted from JS function.
   487                     autoConvertibleFromFunction = true;
   488                 }
   489                 // If all our abstract methods have a single name, generate an additional constructor, one that takes a
   490                 // ScriptFunction as its first parameter and assigns it as the implementation for all abstract methods.
   491                 generateOverridingConstructor(ctor, true);
   492             }
   493         }
   494     }
   496     private void generateDelegatingConstructor(final Constructor<?> ctor) {
   497         final Type originalCtorType = Type.getType(ctor);
   498         final Type[] argTypes = originalCtorType.getArgumentTypes();
   500         // All constructors must be public, even if in the superclass they were protected.
   501         final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC |
   502                 (ctor.isVarArgs() ? ACC_VARARGS : 0), INIT,
   503                 Type.getMethodDescriptor(originalCtorType.getReturnType(), argTypes), null, null));
   505         mv.visitCode();
   506         // Invoke super constructor with the same arguments.
   507         mv.visitVarInsn(ALOAD, 0);
   508         int offset = 1; // First arg is at position 1, after this.
   509         for (final Type argType: argTypes) {
   510             mv.load(offset, argType);
   511             offset += argType.getSize();
   512         }
   513         mv.invokespecial(superClassName, INIT, originalCtorType.getDescriptor(), false);
   515         endInitMethod(mv);
   516     }
   518     /**
   519      * Generates a constructor for the instance adapter class. This constructor will take the same arguments as the supertype
   520      * constructor passed as the argument here, and delegate to it. However, it will take an additional argument of
   521      * either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize
   522      * all the method handle fields of the adapter instance with functions from the script object (or the script
   523      * function itself, if that's what's passed). There is one method handle field in the adapter class for every method
   524      * that can be implemented or overridden; the name of every field is same as the name of the method, with a number
   525      * suffix that makes it unique in case of overloaded methods. The generated constructor will invoke
   526      * {@link #getHandle(ScriptFunction, MethodType, boolean)} or {@link #getHandle(Object, String, MethodType,
   527      * boolean)} to obtain the method handles; these methods make sure to add the necessary conversions and arity
   528      * adjustments so that the resulting method handles can be invoked from generated methods using {@code invokeExact}.
   529      * The constructor that takes a script function will only initialize the methods with the same name as the single
   530      * abstract method. The constructor will also store the Nashorn global that was current at the constructor
   531      * invocation time in a field named "global". The generated constructor will be public, regardless of whether the
   532      * supertype constructor was public or protected. The generated constructor will not be variable arity, even if the
   533      * supertype constructor was.
   534      * @param ctor the supertype constructor that is serving as the base for the generated constructor.
   535      * @param fromFunction true if we're generating a constructor that initializes SAM types from a single
   536      * ScriptFunction passed to it, false if we're generating a constructor that initializes an arbitrary type from a
   537      * ScriptObject passed to it.
   538      */
   539     private void generateOverridingConstructor(final Constructor<?> ctor, final boolean fromFunction) {
   540         final Type originalCtorType = Type.getType(ctor);
   541         final Type[] originalArgTypes = originalCtorType.getArgumentTypes();
   542         final int argLen = originalArgTypes.length;
   543         final Type[] newArgTypes = new Type[argLen + 1];
   545         // Insert ScriptFunction|ScriptObject as the last argument to the constructor
   546         final Type extraArgumentType = fromFunction ? SCRIPT_FUNCTION_TYPE : SCRIPT_OBJECT_TYPE;
   547         newArgTypes[argLen] = extraArgumentType;
   548         System.arraycopy(originalArgTypes, 0, newArgTypes, 0, argLen);
   550         // All constructors must be public, even if in the superclass they were protected.
   551         // Existing super constructor <init>(this, args...) triggers generating <init>(this, args..., scriptObj).
   552         // Any variable arity constructors become fixed-arity with explicit array arguments.
   553         final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
   554                 Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
   556         mv.visitCode();
   557         // First, invoke super constructor with original arguments. If the form of the constructor we're generating is
   558         // <init>(this, args..., scriptFn), then we're invoking super.<init>(this, args...).
   559         mv.visitVarInsn(ALOAD, 0);
   560         final Class<?>[] argTypes = ctor.getParameterTypes();
   561         int offset = 1; // First arg is at position 1, after this.
   562         for (int i = 0; i < argLen; ++i) {
   563             final Type argType = Type.getType(argTypes[i]);
   564             mv.load(offset, argType);
   565             offset += argType.getSize();
   566         }
   567         mv.invokespecial(superClassName, INIT, originalCtorType.getDescriptor(), false);
   569         // Get a descriptor to the appropriate "JavaAdapterFactory.getHandle" method.
   570         final String getHandleDescriptor = fromFunction ? GET_HANDLE_FUNCTION_DESCRIPTOR : GET_HANDLE_OBJECT_DESCRIPTOR;
   572         // Assign MethodHandle fields through invoking getHandle()
   573         for (final MethodInfo mi : methodInfos) {
   574             mv.visitVarInsn(ALOAD, 0);
   575             if (fromFunction && !mi.getName().equals(samName)) {
   576                 // Constructors initializing from a ScriptFunction only initialize methods with the SAM name.
   577                 // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overridden too. This
   578                 // is a deliberate design choice. All other method handles are initialized to null.
   579                 mv.visitInsn(ACONST_NULL);
   580             } else {
   581                 mv.visitVarInsn(ALOAD, offset);
   582                 if(!fromFunction) {
   583                     mv.aconst(mi.getName());
   584                 }
   585                 loadMethodTypeAndGetHandle(mv, mi, getHandleDescriptor);
   586             }
   587             mv.putfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
   588         }
   590         // Assign "this.global = Context.getGlobal()"
   591         mv.visitVarInsn(ALOAD, 0);
   592         invokeGetGlobalWithNullCheck(mv);
   593         mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
   595         // Initialize converters
   596         generateConverterInit(mv, fromFunction);
   597         endInitMethod(mv);
   599         if (! fromFunction) {
   600             newArgTypes[argLen] = OBJECT_TYPE;
   601             final InstructionAdapter mv2 = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, INIT,
   602                     Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
   603             generateOverridingConstructorWithObjectParam(mv2, ctor, originalCtorType.getDescriptor());
   604         }
   605     }
   607     // Object additional param accepting constructor - generated to handle null and undefined value
   608     // for script adapters. This is effectively to throw TypeError on such script adapters. See
   609     // JavaAdapterServices.getHandle as well.
   610     private void generateOverridingConstructorWithObjectParam(final InstructionAdapter mv, final Constructor<?> ctor, final String ctorDescriptor) {
   611         mv.visitCode();
   612         mv.visitVarInsn(ALOAD, 0);
   613         final Class<?>[] argTypes = ctor.getParameterTypes();
   614         int offset = 1; // First arg is at position 1, after this.
   615         for (int i = 0; i < argTypes.length; ++i) {
   616             final Type argType = Type.getType(argTypes[i]);
   617             mv.load(offset, argType);
   618             offset += argType.getSize();
   619         }
   620         mv.invokespecial(superClassName, INIT, ctorDescriptor, false);
   621         mv.visitVarInsn(ALOAD, offset);
   622         mv.visitInsn(ACONST_NULL);
   623         mv.visitInsn(ACONST_NULL);
   624         mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false);
   625         endInitMethod(mv);
   626     }
   628     private static void endInitMethod(final InstructionAdapter mv) {
   629         mv.visitInsn(RETURN);
   630         endMethod(mv);
   631     }
   633     private static void endMethod(final InstructionAdapter mv) {
   634         mv.visitMaxs(0, 0);
   635         mv.visitEnd();
   636     }
   638     private static void invokeGetGlobal(final InstructionAdapter mv) {
   639         mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getGlobal", GET_GLOBAL_METHOD_DESCRIPTOR, false);
   640     }
   642     private static void invokeSetGlobal(final InstructionAdapter mv) {
   643         mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "setGlobal", SET_GLOBAL_METHOD_DESCRIPTOR, false);
   644     }
   646     /**
   647      * Encapsulation of the information used to generate methods in the adapter classes. Basically, a wrapper around the
   648      * reflective Method object, a cached MethodType, and the name of the field in the adapter class that will hold the
   649      * method handle serving as the implementation of this method in adapter instances.
   650      *
   651      */
   652     private static class MethodInfo {
   653         private final Method method;
   654         private final MethodType type;
   655         private String methodHandleFieldName;
   657         private MethodInfo(final Class<?> clazz, final String name, final Class<?>... argTypes) throws NoSuchMethodException {
   658             this(clazz.getDeclaredMethod(name, argTypes));
   659         }
   661         private MethodInfo(final Method method) {
   662             this.method = method;
   663             this.type   = MH.type(method.getReturnType(), method.getParameterTypes());
   664         }
   666         @Override
   667         public boolean equals(final Object obj) {
   668             return obj instanceof MethodInfo && equals((MethodInfo)obj);
   669         }
   671         private boolean equals(final MethodInfo other) {
   672             // Only method name and type are used for comparison; method handle field name is not.
   673             return getName().equals(other.getName()) && type.equals(other.type);
   674         }
   676         String getName() {
   677             return method.getName();
   678         }
   680         @Override
   681         public int hashCode() {
   682             return getName().hashCode() ^ type.hashCode();
   683         }
   685         void setIsCanonical(final JavaAdapterBytecodeGenerator self) {
   686             methodHandleFieldName = self.nextName(getName());
   687         }
   688     }
   690     private String nextName(final String name) {
   691         int i = 0;
   692         String nextName = name;
   693         while (!usedFieldNames.add(nextName)) {
   694             final String ordinal = String.valueOf(i++);
   695             final int maxNameLen = 255 - ordinal.length();
   696             nextName = (name.length() <= maxNameLen ? name : name.substring(0, maxNameLen)).concat(ordinal);
   697         }
   698         return nextName;
   699     }
   701     private void generateMethods() {
   702         for(final MethodInfo mi: methodInfos) {
   703             generateMethod(mi);
   704         }
   705     }
   707     /**
   708      * Generates a method in the adapter class that adapts a method from the original class. The generated methods will
   709      * inspect the method handle field assigned to them. If it is null (the JS object doesn't provide an implementation
   710      * for the method) then it will either invoke its version in the supertype, or if it is abstract, throw an
   711      * {@link UnsupportedOperationException}. Otherwise, if the method handle field's value is not null, the handle is
   712      * invoked using invokeExact (signature polymorphic invocation as per JLS 15.12.3). Before the invocation, the
   713      * current Nashorn {@link Context} is checked, and if it is different than the global used to create the adapter
   714      * instance, the creating global is set to be the current global. In this case, the previously current global is
   715      * restored after the invocation. If invokeExact results in a Throwable that is not one of the method's declared
   716      * exceptions, and is not an unchecked throwable, then it is wrapped into a {@link RuntimeException} and the runtime
   717      * exception is thrown. The method handle retrieved from the field is guaranteed to exactly match the signature of
   718      * the method; this is guaranteed by the way constructors of the adapter class obtain them using
   719      * {@link #getHandle(Object, String, MethodType, boolean)}.
   720      * @param mi the method info describing the method to be generated.
   721      */
   722     private void generateMethod(final MethodInfo mi) {
   723         final Method method = mi.method;
   724         final Class<?>[] exceptions = method.getExceptionTypes();
   725         final String[] exceptionNames = getExceptionNames(exceptions);
   726         final MethodType type = mi.type;
   727         final String methodDesc = type.toMethodDescriptorString();
   728         final String name = mi.getName();
   730         final Type asmType = Type.getMethodType(methodDesc);
   731         final Type[] asmArgTypes = asmType.getArgumentTypes();
   733         final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), name,
   734                 methodDesc, null, exceptionNames));
   735         mv.visitCode();
   737         final Label handleDefined = new Label();
   739         final Class<?> returnType = type.returnType();
   740         final Type asmReturnType = Type.getType(returnType);
   742         // See if we have overriding method handle defined
   743         if(classOverride) {
   744             mv.getstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
   745         } else {
   746             mv.visitVarInsn(ALOAD, 0);
   747             mv.getfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
   748         }
   749         // stack: [handle]
   750         mv.visitInsn(DUP);
   751         mv.visitJumpInsn(IFNONNULL, handleDefined);
   753         // No handle is available, fall back to default behavior
   754         if(Modifier.isAbstract(method.getModifiers())) {
   755             // If the super method is abstract, throw an exception
   756             mv.anew(UNSUPPORTED_OPERATION_TYPE);
   757             mv.dup();
   758             mv.invokespecial(UNSUPPORTED_OPERATION_TYPE_NAME, INIT, VOID_NOARG_METHOD_DESCRIPTOR, false);
   759             mv.athrow();
   760         } else {
   761             mv.visitInsn(POP);
   762             // If the super method is not abstract, delegate to it.
   763             emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc);
   764         }
   766         mv.visitLabel(handleDefined);
   767         // Load the creatingGlobal object
   768         if(classOverride) {
   769             // If class handle is defined, load the static defining global
   770             mv.getstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
   771         } else {
   772             mv.visitVarInsn(ALOAD, 0);
   773             mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
   774         }
   775         // stack: [creatingGlobal, handle]
   776         final Label setupGlobal = new Label();
   777         mv.visitLabel(setupGlobal);
   779         // Determine the first index for a local variable
   780         int nextLocalVar = 1; // "this" is at 0
   781         for(final Type t: asmArgTypes) {
   782             nextLocalVar += t.getSize();
   783         }
   784         // Set our local variable indices
   785         final int currentGlobalVar  = nextLocalVar++;
   786         final int globalsDifferVar  = nextLocalVar++;
   788         mv.dup();
   789         // stack: [creatingGlobal, creatingGlobal, handle]
   791         // Emit code for switching to the creating global
   792         // Global currentGlobal = Context.getGlobal();
   793         invokeGetGlobal(mv);
   794         mv.dup();
   796         mv.visitVarInsn(ASTORE, currentGlobalVar);
   797         // stack: [currentGlobal, creatingGlobal, creatingGlobal, handle]
   798         // if(definingGlobal == currentGlobal) {
   799         final Label globalsDiffer = new Label();
   800         mv.ifacmpne(globalsDiffer);
   801         // stack: [creatingGlobal, handle]
   802         //     globalsDiffer = false
   803         mv.pop();
   804         // stack: [handle]
   805         mv.iconst(0); // false
   806         // stack: [false, handle]
   807         final Label invokeHandle = new Label();
   808         mv.goTo(invokeHandle);
   809         mv.visitLabel(globalsDiffer);
   810         // } else {
   811         //     Context.setGlobal(definingGlobal);
   812         // stack: [creatingGlobal, handle]
   813         invokeSetGlobal(mv);
   814         // stack: [handle]
   815         //     globalsDiffer = true
   816         mv.iconst(1);
   817         // stack: [true, handle]
   819         mv.visitLabel(invokeHandle);
   820         mv.visitVarInsn(ISTORE, globalsDifferVar);
   821         // stack: [handle]
   823         // Load all parameters back on stack for dynamic invocation. NOTE: since we're using a generic
   824         // Object(Object, Object, ...) type signature for the method, we must box all arguments here.
   825         int varOffset = 1;
   826         for (final Type t : asmArgTypes) {
   827             mv.load(varOffset, t);
   828             boxStackTop(mv, t);
   829             varOffset += t.getSize();
   830         }
   832         // Invoke the target method handle
   833         final Label tryBlockStart = new Label();
   834         mv.visitLabel(tryBlockStart);
   835         emitInvokeExact(mv, type.generic());
   836         convertReturnValue(mv, returnType, asmReturnType);
   837         final Label tryBlockEnd = new Label();
   838         mv.visitLabel(tryBlockEnd);
   839         emitFinally(mv, currentGlobalVar, globalsDifferVar);
   840         mv.areturn(asmReturnType);
   842         // If Throwable is not declared, we need an adapter from Throwable to RuntimeException
   843         final boolean throwableDeclared = isThrowableDeclared(exceptions);
   844         final Label throwableHandler;
   845         if (!throwableDeclared) {
   846             // Add "throw new RuntimeException(Throwable)" handler for Throwable
   847             throwableHandler = new Label();
   848             mv.visitLabel(throwableHandler);
   849             mv.anew(RUNTIME_EXCEPTION_TYPE);
   850             mv.dupX1();
   851             mv.swap();
   852             mv.invokespecial(RUNTIME_EXCEPTION_TYPE_NAME, INIT, Type.getMethodDescriptor(Type.VOID_TYPE, THROWABLE_TYPE), false);
   853             // Fall through to rethrow handler
   854         } else {
   855             throwableHandler = null;
   856         }
   857         final Label rethrowHandler = new Label();
   858         mv.visitLabel(rethrowHandler);
   859         // Rethrow handler for RuntimeException, Error, and all declared exception types
   860         emitFinally(mv, currentGlobalVar, globalsDifferVar);
   861         mv.athrow();
   862         final Label methodEnd = new Label();
   863         mv.visitLabel(methodEnd);
   865         mv.visitLocalVariable("currentGlobal", GLOBAL_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd, currentGlobalVar);
   866         mv.visitLocalVariable("globalsDiffer", Type.BOOLEAN_TYPE.getDescriptor(), null, setupGlobal, methodEnd, globalsDifferVar);
   868         if(throwableDeclared) {
   869             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, THROWABLE_TYPE_NAME);
   870             assert throwableHandler == null;
   871         } else {
   872             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME);
   873             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, ERROR_TYPE_NAME);
   874             for(final String excName: exceptionNames) {
   875                 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, excName);
   876             }
   877             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME);
   878         }
   879         endMethod(mv);
   880     }
   882     private void convertReturnValue(final InstructionAdapter mv, final Class<?> returnType, final Type asmReturnType) {
   883         switch(asmReturnType.getSort()) {
   884         case Type.VOID:
   885             mv.pop();
   886             break;
   887         case Type.BOOLEAN:
   888             JSType.TO_BOOLEAN.invoke(mv);
   889             break;
   890         case Type.BYTE:
   891             JSType.TO_INT32.invoke(mv);
   892             mv.visitInsn(Opcodes.I2B);
   893             break;
   894         case Type.SHORT:
   895             JSType.TO_INT32.invoke(mv);
   896             mv.visitInsn(Opcodes.I2S);
   897             break;
   898         case Type.CHAR:
   899             // JSType doesn't have a TO_CHAR, so we have services supply us one.
   900             mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "toCharPrimitive", TO_CHAR_PRIMITIVE_METHOD_DESCRIPTOR, false);
   901             break;
   902         case Type.INT:
   903             JSType.TO_INT32.invoke(mv);
   904             break;
   905         case Type.LONG:
   906             JSType.TO_LONG.invoke(mv);
   907             break;
   908         case Type.FLOAT:
   909             JSType.TO_NUMBER.invoke(mv);
   910             mv.visitInsn(Opcodes.D2F);
   911             break;
   912         case Type.DOUBLE:
   913             JSType.TO_NUMBER.invoke(mv);
   914             break;
   915         default:
   916             if(asmReturnType.equals(OBJECT_TYPE)) {
   917                 // Must hide ConsString (and potentially other internal Nashorn types) from callers
   918                 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "exportReturnValue", EXPORT_RETURN_VALUE_METHOD_DESCRIPTOR, false);
   919             } else if(asmReturnType.equals(STRING_TYPE)){
   920                 // Well-known conversion to String. Not using the JSType one as we want to preserve null as null instead
   921                 // of the string "n,u,l,l".
   922                 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "toString", TO_STRING_METHOD_DESCRIPTOR, false);
   923             } else {
   924                 // Invoke converter method handle for everything else. Note that we could have just added an asType or
   925                 // filterReturnValue to the invoked handle instead, but then every instance would have the function
   926                 // method handle wrapped in a separate converter method handle, making handle.invokeExact() megamorphic.
   927                 if(classOverride) {
   928                     mv.getstatic(generatedClassName, converterFields.get(returnType), METHOD_HANDLE_TYPE_DESCRIPTOR);
   929                 } else {
   930                     mv.visitVarInsn(ALOAD, 0);
   931                     mv.getfield(generatedClassName, converterFields.get(returnType), METHOD_HANDLE_TYPE_DESCRIPTOR);
   932                 }
   933                 mv.swap();
   934                 emitInvokeExact(mv, MethodType.methodType(returnType, Object.class));
   935             }
   936         }
   937     }
   939     private static void emitInvokeExact(final InstructionAdapter mv, final MethodType type) {
   940         mv.invokevirtual(METHOD_HANDLE_TYPE.getInternalName(), "invokeExact", type.toMethodDescriptorString(), false);
   941     }
   943     private static void boxStackTop(final InstructionAdapter mv, final Type t) {
   944         switch(t.getSort()) {
   945         case Type.BOOLEAN:
   946             invokeValueOf(mv, "Boolean", 'Z');
   947             break;
   948         case Type.BYTE:
   949         case Type.SHORT:
   950         case Type.INT:
   951             // bytes and shorts get boxed as integers
   952             invokeValueOf(mv, "Integer", 'I');
   953             break;
   954         case Type.CHAR:
   955             invokeValueOf(mv, "Character", 'C');
   956             break;
   957         case Type.FLOAT:
   958             // floats get boxed as doubles
   959             mv.visitInsn(Opcodes.F2D);
   960             invokeValueOf(mv, "Double", 'D');
   961             break;
   962         case Type.LONG:
   963             invokeValueOf(mv, "Long", 'J');
   964             break;
   965         case Type.DOUBLE:
   966             invokeValueOf(mv, "Double", 'D');
   967             break;
   968         case Type.ARRAY:
   969         case Type.METHOD:
   970             // Already boxed
   971             break;
   972         case Type.OBJECT:
   973             if(t.equals(OBJECT_TYPE)) {
   974                 mv.invokestatic(SCRIPTUTILS_TYPE_NAME, "unwrap", UNWRAP_METHOD_DESCRIPTOR, false);
   975             }
   976             break;
   977         default:
   978             // Not expecting anything else (e.g. VOID)
   979             assert false;
   980             break;
   981         }
   982     }
   984     private static void invokeValueOf(final InstructionAdapter mv, final String boxedType, final char unboxedType) {
   985         mv.invokestatic("java/lang/" + boxedType, "valueOf", "(" + unboxedType + ")Ljava/lang/" + boxedType + ";", false);
   986     }
   988     /**
   989      * Emit code to restore the previous Nashorn Context when needed.
   990      * @param mv the instruction adapter
   991      * @param currentGlobalVar index of the local variable holding the reference to the current global at method
   992      * entry.
   993      * @param globalsDifferVar index of the boolean local variable that is true if the global needs to be restored.
   994      */
   995     private static void emitFinally(final InstructionAdapter mv, final int currentGlobalVar, final int globalsDifferVar) {
   996         // Emit code to restore the previous Nashorn global if needed
   997         mv.visitVarInsn(ILOAD, globalsDifferVar);
   998         final Label skip = new Label();
   999         mv.ifeq(skip);
  1000         mv.visitVarInsn(ALOAD, currentGlobalVar);
  1001         invokeSetGlobal(mv);
  1002         mv.visitLabel(skip);
  1005     private static boolean isThrowableDeclared(final Class<?>[] exceptions) {
  1006         for (final Class<?> exception : exceptions) {
  1007             if (exception == Throwable.class) {
  1008                 return true;
  1011         return false;
  1014     private void generateSuperMethods() {
  1015         for(final MethodInfo mi: methodInfos) {
  1016             if(!Modifier.isAbstract(mi.method.getModifiers())) {
  1017                 generateSuperMethod(mi);
  1022     private void generateSuperMethod(final MethodInfo mi) {
  1023         final Method method = mi.method;
  1025         final String methodDesc = mi.type.toMethodDescriptorString();
  1026         final String name = mi.getName();
  1028         final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method),
  1029                 SUPER_PREFIX + name, methodDesc, null, getExceptionNames(method.getExceptionTypes())));
  1030         mv.visitCode();
  1032         emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc);
  1034         endMethod(mv);
  1037     // find the appropriate super type to use for invokespecial on the given interface
  1038     private Class<?> findInvokespecialOwnerFor(final Class<?> cl) {
  1039         assert Modifier.isInterface(cl.getModifiers()) : cl + " is not an interface";
  1041         if (cl.isAssignableFrom(superClass)) {
  1042             return superClass;
  1045         for (final Class<?> iface : interfaces) {
  1046              if (cl.isAssignableFrom(iface)) {
  1047                  return iface;
  1051         // we better that interface that extends the given interface!
  1052         throw new AssertionError("can't find the class/interface that extends " + cl);
  1055     private void emitSuperCall(final InstructionAdapter mv, final Class<?> owner, final String name, final String methodDesc) {
  1056         mv.visitVarInsn(ALOAD, 0);
  1057         int nextParam = 1;
  1058         final Type methodType = Type.getMethodType(methodDesc);
  1059         for(final Type t: methodType.getArgumentTypes()) {
  1060             mv.load(nextParam, t);
  1061             nextParam += t.getSize();
  1064         // default method - non-abstract, interface method
  1065         if (Modifier.isInterface(owner.getModifiers())) {
  1066             // we should call default method on the immediate "super" type - not on (possibly)
  1067             // the indirectly inherited interface class!
  1068             mv.invokespecial(Type.getInternalName(findInvokespecialOwnerFor(owner)), name, methodDesc, false);
  1069         } else {
  1070             mv.invokespecial(superClassName, name, methodDesc, false);
  1072         mv.areturn(methodType.getReturnType());
  1075     private void generateFinalizerMethods() {
  1076         final String finalizerDelegateName = nextName("access$");
  1077         generateFinalizerDelegate(finalizerDelegateName);
  1078         generateFinalizerOverride(finalizerDelegateName);
  1081     private void generateFinalizerDelegate(final String finalizerDelegateName) {
  1082         // Generate a delegate that will be invoked from the no-permission trampoline. Note it can be private, as we'll
  1083         // refer to it with a MethodHandle constant pool entry in the overridden finalize() method (see
  1084         // generateFinalizerOverride()).
  1085         final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PRIVATE | ACC_STATIC,
  1086                 finalizerDelegateName, Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE), null, null));
  1088         // Simply invoke super.finalize()
  1089         mv.visitVarInsn(ALOAD, 0);
  1090         mv.checkcast(Type.getType(generatedClassName));
  1091         mv.invokespecial(superClassName, "finalize", Type.getMethodDescriptor(Type.VOID_TYPE), false);
  1093         mv.visitInsn(RETURN);
  1094         endMethod(mv);
  1097     private void generateFinalizerOverride(final String finalizerDelegateName) {
  1098         final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(ACC_PUBLIC, "finalize",
  1099                 VOID_NOARG_METHOD_DESCRIPTOR, null, null));
  1100         // Overridden finalizer will take a MethodHandle to the finalizer delegating method, ...
  1101         mv.aconst(new Handle(Opcodes.H_INVOKESTATIC, generatedClassName, finalizerDelegateName,
  1102                 Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE)));
  1103         mv.visitVarInsn(ALOAD, 0);
  1104         // ...and invoke it through JavaAdapterServices.invokeNoPermissions
  1105         mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "invokeNoPermissions",
  1106                 Type.getMethodDescriptor(METHOD_HANDLE_TYPE, OBJECT_TYPE), false);
  1107         mv.visitInsn(RETURN);
  1108         endMethod(mv);
  1111     private static String[] getExceptionNames(final Class<?>[] exceptions) {
  1112         final String[] exceptionNames = new String[exceptions.length];
  1113         for (int i = 0; i < exceptions.length; ++i) {
  1114             exceptionNames[i] = Type.getInternalName(exceptions[i]);
  1116         return exceptionNames;
  1119     private static int getAccessModifiers(final Method method) {
  1120         return ACC_PUBLIC | (method.isVarArgs() ? ACC_VARARGS : 0);
  1123     /**
  1124      * Gathers methods that can be implemented or overridden from the specified type into this factory's
  1125      * {@link #methodInfos} set. It will add all non-final, non-static methods that are either public or protected from
  1126      * the type if the type itself is public. If the type is a class, the method will recursively invoke itself for its
  1127      * superclass and the interfaces it implements, and add further methods that were not directly declared on the
  1128      * class.
  1129      * @param type the type defining the methods.
  1130      */
  1131     private void gatherMethods(final Class<?> type) throws AdaptationException {
  1132         if (Modifier.isPublic(type.getModifiers())) {
  1133             final Method[] typeMethods = type.isInterface() ? type.getMethods() : type.getDeclaredMethods();
  1135             for (final Method typeMethod: typeMethods) {
  1136                 final String name = typeMethod.getName();
  1137                 if(name.startsWith(SUPER_PREFIX)) {
  1138                     continue;
  1140                 final int m = typeMethod.getModifiers();
  1141                 if (Modifier.isStatic(m)) {
  1142                     continue;
  1144                 if (Modifier.isPublic(m) || Modifier.isProtected(m)) {
  1145                     // Is it a "finalize()"?
  1146                     if(name.equals("finalize") && typeMethod.getParameterCount() == 0) {
  1147                         if(type != Object.class) {
  1148                             hasExplicitFinalizer = true;
  1149                             if(Modifier.isFinal(m)) {
  1150                                 // Must be able to override an explicit finalizer
  1151                                 throw new AdaptationException(Outcome.ERROR_FINAL_FINALIZER, type.getCanonicalName());
  1154                         continue;
  1157                     final MethodInfo mi = new MethodInfo(typeMethod);
  1158                     if (Modifier.isFinal(m) || isCallerSensitive(typeMethod)) {
  1159                         finalMethods.add(mi);
  1160                     } else if (!finalMethods.contains(mi) && methodInfos.add(mi)) {
  1161                         if (Modifier.isAbstract(m)) {
  1162                             abstractMethodNames.add(mi.getName());
  1164                         mi.setIsCanonical(this);
  1169         // If the type is a class, visit its superclasses and declared interfaces. If it's an interface, we're done.
  1170         // Needing to invoke the method recursively for a non-interface Class object is the consequence of needing to
  1171         // see all declared protected methods, and Class.getDeclaredMethods() doesn't provide those declared in a
  1172         // superclass. For interfaces, we used Class.getMethods(), as we're only interested in public ones there, and
  1173         // getMethods() does provide those declared in a superinterface.
  1174         if (!type.isInterface()) {
  1175             final Class<?> superType = type.getSuperclass();
  1176             if (superType != null) {
  1177                 gatherMethods(superType);
  1179             for (final Class<?> itf: type.getInterfaces()) {
  1180                 gatherMethods(itf);
  1185     private void gatherMethods(final List<Class<?>> classes) throws AdaptationException {
  1186         for(final Class<?> c: classes) {
  1187             gatherMethods(c);
  1191     private static final AccessControlContext GET_DECLARED_MEMBERS_ACC_CTXT = ClassAndLoader.createPermAccCtxt("accessDeclaredMembers");
  1193     /**
  1194      * Creates a collection of methods that are not final, but we still never allow them to be overridden in adapters,
  1195      * as explicitly declaring them automatically is a bad idea. Currently, this means {@code Object.finalize()} and
  1196      * {@code Object.clone()}.
  1197      * @return a collection of method infos representing those methods that we never override in adapter classes.
  1198      */
  1199     private static Collection<MethodInfo> getExcludedMethods() {
  1200         return AccessController.doPrivileged(new PrivilegedAction<Collection<MethodInfo>>() {
  1201             @Override
  1202             public Collection<MethodInfo> run() {
  1203                 try {
  1204                     return Arrays.asList(
  1205                             new MethodInfo(Object.class, "finalize"),
  1206                             new MethodInfo(Object.class, "clone"));
  1207                 } catch (final NoSuchMethodException e) {
  1208                     throw new AssertionError(e);
  1211         }, GET_DECLARED_MEMBERS_ACC_CTXT);
  1214     private String getCommonSuperClass(final String type1, final String type2) {
  1215         try {
  1216             final Class<?> c1 = Class.forName(type1.replace('/', '.'), false, commonLoader);
  1217             final Class<?> c2 = Class.forName(type2.replace('/', '.'), false, commonLoader);
  1218             if (c1.isAssignableFrom(c2)) {
  1219                 return type1;
  1221             if (c2.isAssignableFrom(c1)) {
  1222                 return type2;
  1224             if (c1.isInterface() || c2.isInterface()) {
  1225                 return OBJECT_TYPE_NAME;
  1227             return assignableSuperClass(c1, c2).getName().replace('.', '/');
  1228         } catch(final ClassNotFoundException e) {
  1229             throw new RuntimeException(e);
  1233     private static Class<?> assignableSuperClass(final Class<?> c1, final Class<?> c2) {
  1234         final Class<?> superClass = c1.getSuperclass();
  1235         return superClass.isAssignableFrom(c2) ? superClass : assignableSuperClass(superClass, c2);
  1238     private static boolean isCallerSensitive(final AccessibleObject e) {
  1239         return e.isAnnotationPresent(CallerSensitive.class);

mercurial