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

Print this page




  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.List;
  60 import java.util.Set;
  61 import jdk.internal.org.objectweb.asm.ClassWriter;
  62 import jdk.internal.org.objectweb.asm.Handle;
  63 import jdk.internal.org.objectweb.asm.Label;
  64 import jdk.internal.org.objectweb.asm.Opcodes;
  65 import jdk.internal.org.objectweb.asm.Type;
  66 import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;

  67 import jdk.nashorn.internal.runtime.Context;
  68 import jdk.nashorn.internal.runtime.ScriptFunction;
  69 import jdk.nashorn.internal.runtime.ScriptObject;
  70 import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome;
  71 import sun.reflect.CallerSensitive;
  72 
  73 /**
  74  * Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}.
  75  * </p><p>
  76  * For every protected or public constructor in the extended class, the adapter class will have either one or two
  77  * public constructors (visibility of protected constructors in the extended class is promoted to public).
  78  * <li>
  79  * <li>For adapter classes with instance-level overrides, a constructor taking a trailing ScriptObject argument preceded
  80  * by original constructor arguments is always created on the adapter class. When such a constructor is invoked, the
  81  * passed ScriptObject's member functions are used to implement and/or override methods on the original class,
  82  * dispatched by name. A single JavaScript function will act as the implementation for all overloaded methods of the
  83  * same name. When methods on an adapter instance are invoked, the functions are invoked having the ScriptObject passed
  84  * in the instance constructor as their "this". Subsequent changes to the ScriptObject (reassignment or removal of its
  85  * functions) are not reflected in the adapter instance; the method implementations are bound to functions at
  86  * constructor invocation time.


 117  * </p><p>
 118  * It is possible to create two different adapter classes: those that can have class-level overrides, and those that can
 119  * have instance-level overrides. When {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked
 120  * with non-null {@code classOverrides} parameter, an adapter class is created that can have class-level overrides, and
 121  * the passed script object will be used as the implementations for its methods, just as in the above case of the
 122  * constructor taking a script object. Note that in the case of class-level overrides, a new adapter class is created on
 123  * every invocation, and the implementation object is bound to the class, not to any instance. All created instances
 124  * will share these functions. If it is required to have both class-level overrides and instance-level overrides, the
 125  * class-level override adapter class should be subclassed with an instance-override adapter. Since adapters delegate to
 126  * super class when an overriding method handle is not specified, this will behave as expected. It is not possible to
 127  * have both class-level and instance-level overrides in the same class for security reasons: adapter classes are
 128  * defined with a protection domain of their creator code, and an adapter class that has both class and instance level
 129  * overrides would need to have two potentially different protection domains: one for class-based behavior and one for
 130  * instance-based behavior; since Java classes can only belong to a single protection domain, this could not be
 131  * implemented securely.
 132  */
 133 final class JavaAdapterBytecodeGenerator {
 134     static final Type CONTEXT_TYPE       = Type.getType(Context.class);
 135     static final Type OBJECT_TYPE        = Type.getType(Object.class);
 136     static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);

 137 
 138     static final String CONTEXT_TYPE_NAME = CONTEXT_TYPE.getInternalName();
 139     static final String OBJECT_TYPE_NAME  = OBJECT_TYPE.getInternalName();
 140 
 141     static final String INIT = "<init>";
 142 
 143     static final String GLOBAL_FIELD_NAME = "global";
 144 
 145     static final String SCRIPT_OBJECT_TYPE_DESCRIPTOR = SCRIPT_OBJECT_TYPE.getDescriptor();

 146 
 147     static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, SCRIPT_OBJECT_TYPE);

 148     static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
 149 
 150     private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
 151     private static final Type STRING_TYPE = Type.getType(String.class);
 152     private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class);
 153     private static final Type METHOD_HANDLE_TYPE = Type.getType(MethodHandle.class);
 154     private static final String GET_HANDLE_OBJECT_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
 155             OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE);
 156     private static final String GET_HANDLE_FUNCTION_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
 157             SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE);
 158     private static final String GET_CLASS_INITIALIZER_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE);
 159     private static final Type RUNTIME_EXCEPTION_TYPE = Type.getType(RuntimeException.class);
 160     private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
 161     private static final Type UNSUPPORTED_OPERATION_TYPE = Type.getType(UnsupportedOperationException.class);
 162 
 163     private static final String SERVICES_CLASS_TYPE_NAME = Type.getInternalName(JavaAdapterServices.class);
 164     private static final String RUNTIME_EXCEPTION_TYPE_NAME = RUNTIME_EXCEPTION_TYPE.getInternalName();
 165     private static final String ERROR_TYPE_NAME = Type.getInternalName(Error.class);
 166     private static final String THROWABLE_TYPE_NAME = THROWABLE_TYPE.getInternalName();
 167     private static final String UNSUPPORTED_OPERATION_TYPE_NAME = UNSUPPORTED_OPERATION_TYPE.getInternalName();
 168 
 169     private static final String METHOD_HANDLE_TYPE_DESCRIPTOR = METHOD_HANDLE_TYPE.getDescriptor();
 170     private static final String GET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE);
 171     private static final String GET_CLASS_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Class.class));
 172 
 173     // Package used when the adapter can't be defined in the adaptee's package (either because it's sealed, or because
 174     // it's a java.* package.
 175     private static final String ADAPTER_PACKAGE_PREFIX = "jdk/nashorn/javaadapters/";
 176     // Class name suffix used to append to the adaptee class name, when it can be defined in the adaptee's package.
 177     private static final String ADAPTER_CLASS_NAME_SUFFIX = "$$NashornJavaAdapter";
 178     private static final String JAVA_PACKAGE_PREFIX = "java/";
 179     private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255;
 180 
 181     private static final String CLASS_INIT = "<clinit>";
 182 
 183     // Method name prefix for invoking super-methods
 184     static final String SUPER_PREFIX = "super$";
 185 
 186     /**
 187      * Collection of methods we never override: Object.clone(), Object.finalize().
 188      */
 189     private static final Collection<MethodInfo> EXCLUDED = getExcludedMethods();
 190 


 242         generateGlobalFields();
 243 
 244         gatherMethods(superClass);
 245         gatherMethods(interfaces);
 246         samName = abstractMethodNames.size() == 1 ? abstractMethodNames.iterator().next() : null;
 247         generateHandleFields();
 248         if(classOverride) {
 249             generateClassInit();
 250         }
 251         generateConstructors();
 252         generateMethods();
 253         generateSuperMethods();
 254         if (hasExplicitFinalizer) {
 255             generateFinalizerMethods();
 256         }
 257         // }
 258         cw.visitEnd();
 259     }
 260 
 261     private void generateGlobalFields() {
 262         cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, null).visitEnd();
 263         usedFieldNames.add(GLOBAL_FIELD_NAME);
 264     }
 265 
 266     JavaAdapterClassLoader createAdapterClassLoader() {
 267         return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray());
 268     }
 269 
 270     boolean isAutoConvertibleFromFunction() {
 271         return autoConvertibleFromFunction;
 272     }
 273 
 274     private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) {
 275         // The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're
 276         // just implementing interfaces or extending Object), then the first implemented interface or Object.
 277         final Class<?> namingType = superType == Object.class ? (interfaces.isEmpty()? Object.class : interfaces.get(0)) : superType;
 278         final Package pkg = namingType.getPackage();
 279         final String namingTypeName = Type.getInternalName(namingType);
 280         final StringBuilder buf = new StringBuilder();
 281         if (namingTypeName.startsWith(JAVA_PACKAGE_PREFIX) || pkg == null || pkg.isSealed()) {
 282             // Can't define new classes in java.* packages


 346             initGlobal = new Label();
 347             mv.goTo(initGlobal);
 348             mv.visitLabel(notAFunction);
 349         } else {
 350             initGlobal = null;
 351         }
 352         // Assign MethodHandle fields through invoking getHandle() for a ScriptObject
 353         for (final MethodInfo mi : methodInfos) {
 354             mv.dup();
 355             mv.aconst(mi.getName());
 356             mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
 357             mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false);
 358             mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
 359         }
 360 
 361         if(initGlobal != null) {
 362             mv.visitLabel(initGlobal);
 363         }
 364         // Assign "global = Context.getGlobal()"
 365         invokeGetGlobalWithNullCheck(mv);
 366         mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
 367 
 368         endInitMethod(mv);
 369     }
 370 
 371     private static void invokeGetGlobalWithNullCheck(final InstructionAdapter mv) {
 372         invokeGetGlobal(mv);
 373         mv.dup();
 374         mv.invokevirtual(OBJECT_TYPE_NAME, "getClass", GET_CLASS_METHOD_DESCRIPTOR, false); // check against null Context
 375         mv.pop();
 376     }
 377 
 378     private void generateConstructors() throws AdaptationException {
 379         boolean gotCtor = false;
 380         for (final Constructor<?> ctor: superClass.getDeclaredConstructors()) {
 381             final int modifier = ctor.getModifiers();
 382             if((modifier & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0 && !isCallerSensitive(ctor)) {
 383                 generateConstructors(ctor);
 384                 gotCtor = true;
 385             }
 386         }


 491             mv.visitVarInsn(ALOAD, 0);
 492             if (fromFunction && !mi.getName().equals(samName)) {
 493                 // Constructors initializing from a ScriptFunction only initialize methods with the SAM name.
 494                 // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overriden too. This
 495                 // is a deliberate design choice. All other method handles are initialized to null.
 496                 mv.visitInsn(ACONST_NULL);
 497             } else {
 498                 mv.visitVarInsn(ALOAD, offset);
 499                 if(!fromFunction) {
 500                     mv.aconst(mi.getName());
 501                 }
 502                 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
 503                 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor, false);
 504             }
 505             mv.putfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
 506         }
 507 
 508         // Assign "this.global = Context.getGlobal()"
 509         mv.visitVarInsn(ALOAD, 0);
 510         invokeGetGlobalWithNullCheck(mv);
 511         mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
 512 
 513         endInitMethod(mv);
 514     }
 515 
 516     private static void endInitMethod(final InstructionAdapter mv) {
 517         mv.visitInsn(RETURN);
 518         endMethod(mv);
 519     }
 520 
 521     private static void endMethod(final InstructionAdapter mv) {
 522         mv.visitMaxs(0, 0);
 523         mv.visitEnd();
 524     }
 525 
 526     private static void invokeGetGlobal(final InstructionAdapter mv) {
 527         mv.invokestatic(CONTEXT_TYPE_NAME, "getGlobal", GET_GLOBAL_METHOD_DESCRIPTOR, false);
 528     }
 529 
 530     private static void invokeSetGlobal(final InstructionAdapter mv) {
 531         mv.invokestatic(CONTEXT_TYPE_NAME, "setGlobal", SET_GLOBAL_METHOD_DESCRIPTOR, false);


 635         }
 636         // stack: [handle]
 637         jumpIfNonNullKeepOperand(mv, handleDefined);
 638 
 639         // No handle is available, fall back to default behavior
 640         if(Modifier.isAbstract(method.getModifiers())) {
 641             // If the super method is abstract, throw an exception
 642             mv.anew(UNSUPPORTED_OPERATION_TYPE);
 643             mv.dup();
 644             mv.invokespecial(UNSUPPORTED_OPERATION_TYPE_NAME, INIT, VOID_NOARG_METHOD_DESCRIPTOR, false);
 645             mv.athrow();
 646         } else {
 647             // If the super method is not abstract, delegate to it.
 648             emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc);
 649         }
 650 
 651         mv.visitLabel(handleDefined);
 652         // Load the creatingGlobal object
 653         if(classOverride) {
 654             // If class handle is defined, load the static defining global
 655             mv.getstatic(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
 656         } else {
 657             mv.visitVarInsn(ALOAD, 0);
 658             mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
 659         }
 660         // stack: [creatingGlobal, handle]
 661         final Label setupGlobal = new Label();
 662         mv.visitLabel(setupGlobal);
 663 
 664         // Determine the first index for a local variable
 665         int nextLocalVar = 1; // "this" is at 0
 666         for(final Type t: asmArgTypes) {
 667             nextLocalVar += t.getSize();
 668         }
 669         // Set our local variable indices
 670         final int currentGlobalVar  = nextLocalVar++;
 671         final int globalsDifferVar  = nextLocalVar++;
 672 
 673         mv.dup();
 674         // stack: [creatingGlobal, creatingGlobal, handle]
 675 
 676         // Emit code for switching to the creating global
 677         // ScriptObject currentGlobal = Context.getGlobal();
 678         invokeGetGlobal(mv);
 679         mv.dup();
 680 
 681         mv.visitVarInsn(ASTORE, currentGlobalVar);
 682         // stack: [currentGlobal, creatingGlobal, creatingGlobal, handle]
 683         // if(definingGlobal == currentGlobal) {
 684         final Label globalsDiffer = new Label();
 685         mv.ifacmpne(globalsDiffer);
 686         // stack: [creatingGlobal, handle]
 687         //     globalsDiffer = false
 688         mv.pop();
 689         // stack: [handle]
 690         mv.iconst(0); // false
 691         // stack: [false, handle]
 692         final Label invokeHandle = new Label();
 693         mv.goTo(invokeHandle);
 694         mv.visitLabel(globalsDiffer);
 695         // } else {
 696         //     Context.setGlobal(definingGlobal);
 697         // stack: [creatingGlobal, handle]


 727         if (!throwableDeclared) {
 728             // Add "throw new RuntimeException(Throwable)" handler for Throwable
 729             throwableHandler = new Label();
 730             mv.visitLabel(throwableHandler);
 731             mv.anew(RUNTIME_EXCEPTION_TYPE);
 732             mv.dupX1();
 733             mv.swap();
 734             mv.invokespecial(RUNTIME_EXCEPTION_TYPE_NAME, INIT, Type.getMethodDescriptor(Type.VOID_TYPE, THROWABLE_TYPE), false);
 735             // Fall through to rethrow handler
 736         } else {
 737             throwableHandler = null;
 738         }
 739         final Label rethrowHandler = new Label();
 740         mv.visitLabel(rethrowHandler);
 741         // Rethrow handler for RuntimeException, Error, and all declared exception types
 742         emitFinally(mv, currentGlobalVar, globalsDifferVar);
 743         mv.athrow();
 744         final Label methodEnd = new Label();
 745         mv.visitLabel(methodEnd);
 746 
 747         mv.visitLocalVariable("currentGlobal", SCRIPT_OBJECT_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd, currentGlobalVar);
 748         mv.visitLocalVariable("globalsDiffer", Type.INT_TYPE.getDescriptor(), null, setupGlobal, methodEnd, globalsDifferVar);
 749 
 750         if(throwableDeclared) {
 751             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, THROWABLE_TYPE_NAME);
 752             assert throwableHandler == null;
 753         } else {
 754             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME);
 755             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, ERROR_TYPE_NAME);
 756             for(final String excName: exceptionNames) {
 757                 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, excName);
 758             }
 759             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME);
 760         }
 761         endMethod(mv);
 762     }
 763 
 764     /**
 765      * Emits code for jumping to a label if the top stack operand is not null. The operand is kept on the stack if it
 766      * is not null (so is available to code at the jump address) and is popped if it is null.
 767      * @param mv the instruction adapter being used to emit code




  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.List;
  60 import java.util.Set;
  61 import jdk.internal.org.objectweb.asm.ClassWriter;
  62 import jdk.internal.org.objectweb.asm.Handle;
  63 import jdk.internal.org.objectweb.asm.Label;
  64 import jdk.internal.org.objectweb.asm.Opcodes;
  65 import jdk.internal.org.objectweb.asm.Type;
  66 import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
  67 import jdk.nashorn.internal.objects.Global;
  68 import jdk.nashorn.internal.runtime.Context;
  69 import jdk.nashorn.internal.runtime.ScriptFunction;
  70 import jdk.nashorn.internal.runtime.ScriptObject;
  71 import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome;
  72 import sun.reflect.CallerSensitive;
  73 
  74 /**
  75  * Generates bytecode for a Java adapter class. Used by the {@link JavaAdapterFactory}.
  76  * </p><p>
  77  * For every protected or public constructor in the extended class, the adapter class will have either one or two
  78  * public constructors (visibility of protected constructors in the extended class is promoted to public).
  79  * <li>
  80  * <li>For adapter classes with instance-level overrides, a constructor taking a trailing ScriptObject argument preceded
  81  * by original constructor arguments is always created on the adapter class. When such a constructor is invoked, the
  82  * passed ScriptObject's member functions are used to implement and/or override methods on the original class,
  83  * dispatched by name. A single JavaScript function will act as the implementation for all overloaded methods of the
  84  * same name. When methods on an adapter instance are invoked, the functions are invoked having the ScriptObject passed
  85  * in the instance constructor as their "this". Subsequent changes to the ScriptObject (reassignment or removal of its
  86  * functions) are not reflected in the adapter instance; the method implementations are bound to functions at
  87  * constructor invocation time.


 118  * </p><p>
 119  * It is possible to create two different adapter classes: those that can have class-level overrides, and those that can
 120  * have instance-level overrides. When {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked
 121  * with non-null {@code classOverrides} parameter, an adapter class is created that can have class-level overrides, and
 122  * the passed script object will be used as the implementations for its methods, just as in the above case of the
 123  * constructor taking a script object. Note that in the case of class-level overrides, a new adapter class is created on
 124  * every invocation, and the implementation object is bound to the class, not to any instance. All created instances
 125  * will share these functions. If it is required to have both class-level overrides and instance-level overrides, the
 126  * class-level override adapter class should be subclassed with an instance-override adapter. Since adapters delegate to
 127  * super class when an overriding method handle is not specified, this will behave as expected. It is not possible to
 128  * have both class-level and instance-level overrides in the same class for security reasons: adapter classes are
 129  * defined with a protection domain of their creator code, and an adapter class that has both class and instance level
 130  * overrides would need to have two potentially different protection domains: one for class-based behavior and one for
 131  * instance-based behavior; since Java classes can only belong to a single protection domain, this could not be
 132  * implemented securely.
 133  */
 134 final class JavaAdapterBytecodeGenerator {
 135     static final Type CONTEXT_TYPE       = Type.getType(Context.class);
 136     static final Type OBJECT_TYPE        = Type.getType(Object.class);
 137     static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
 138     static final Type GLOBAL_TYPE        = Type.getType(Global.class);
 139 
 140     static final String CONTEXT_TYPE_NAME = CONTEXT_TYPE.getInternalName();
 141     static final String OBJECT_TYPE_NAME  = OBJECT_TYPE.getInternalName();
 142 
 143     static final String INIT = "<init>";
 144 
 145     static final String GLOBAL_FIELD_NAME = "global";
 146 
 147     static final String SCRIPT_OBJECT_TYPE_DESCRIPTOR = SCRIPT_OBJECT_TYPE.getDescriptor();
 148     static final String GLOBAL_TYPE_DESCRIPTOR = GLOBAL_TYPE.getDescriptor();
 149 
 150     
 151     static final String SET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, GLOBAL_TYPE);
 152     static final String VOID_NOARG_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
 153 
 154     private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
 155     private static final Type STRING_TYPE = Type.getType(String.class);
 156     private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class);
 157     private static final Type METHOD_HANDLE_TYPE = Type.getType(MethodHandle.class);
 158     private static final String GET_HANDLE_OBJECT_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
 159             OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE);
 160     private static final String GET_HANDLE_FUNCTION_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
 161             SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE);
 162     private static final String GET_CLASS_INITIALIZER_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE);
 163     private static final Type RUNTIME_EXCEPTION_TYPE = Type.getType(RuntimeException.class);
 164     private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
 165     private static final Type UNSUPPORTED_OPERATION_TYPE = Type.getType(UnsupportedOperationException.class);
 166 
 167     private static final String SERVICES_CLASS_TYPE_NAME = Type.getInternalName(JavaAdapterServices.class);
 168     private static final String RUNTIME_EXCEPTION_TYPE_NAME = RUNTIME_EXCEPTION_TYPE.getInternalName();
 169     private static final String ERROR_TYPE_NAME = Type.getInternalName(Error.class);
 170     private static final String THROWABLE_TYPE_NAME = THROWABLE_TYPE.getInternalName();
 171     private static final String UNSUPPORTED_OPERATION_TYPE_NAME = UNSUPPORTED_OPERATION_TYPE.getInternalName();
 172 
 173     private static final String METHOD_HANDLE_TYPE_DESCRIPTOR = METHOD_HANDLE_TYPE.getDescriptor();
 174     private static final String GET_GLOBAL_METHOD_DESCRIPTOR = Type.getMethodDescriptor(GLOBAL_TYPE);
 175     private static final String GET_CLASS_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.getType(Class.class));
 176 
 177     // Package used when the adapter can't be defined in the adaptee's package (either because it's sealed, or because
 178     // it's a java.* package.
 179     private static final String ADAPTER_PACKAGE_PREFIX = "jdk/nashorn/javaadapters/";
 180     // Class name suffix used to append to the adaptee class name, when it can be defined in the adaptee's package.
 181     private static final String ADAPTER_CLASS_NAME_SUFFIX = "$$NashornJavaAdapter";
 182     private static final String JAVA_PACKAGE_PREFIX = "java/";
 183     private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255;
 184 
 185     private static final String CLASS_INIT = "<clinit>";
 186 
 187     // Method name prefix for invoking super-methods
 188     static final String SUPER_PREFIX = "super$";
 189 
 190     /**
 191      * Collection of methods we never override: Object.clone(), Object.finalize().
 192      */
 193     private static final Collection<MethodInfo> EXCLUDED = getExcludedMethods();
 194 


 246         generateGlobalFields();
 247 
 248         gatherMethods(superClass);
 249         gatherMethods(interfaces);
 250         samName = abstractMethodNames.size() == 1 ? abstractMethodNames.iterator().next() : null;
 251         generateHandleFields();
 252         if(classOverride) {
 253             generateClassInit();
 254         }
 255         generateConstructors();
 256         generateMethods();
 257         generateSuperMethods();
 258         if (hasExplicitFinalizer) {
 259             generateFinalizerMethods();
 260         }
 261         // }
 262         cw.visitEnd();
 263     }
 264 
 265     private void generateGlobalFields() {
 266         cw.visitField(ACC_PRIVATE | ACC_FINAL | (classOverride ? ACC_STATIC : 0), GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR, null, null).visitEnd();
 267         usedFieldNames.add(GLOBAL_FIELD_NAME);
 268     }
 269 
 270     JavaAdapterClassLoader createAdapterClassLoader() {
 271         return new JavaAdapterClassLoader(generatedClassName, cw.toByteArray());
 272     }
 273 
 274     boolean isAutoConvertibleFromFunction() {
 275         return autoConvertibleFromFunction;
 276     }
 277 
 278     private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) {
 279         // The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're
 280         // just implementing interfaces or extending Object), then the first implemented interface or Object.
 281         final Class<?> namingType = superType == Object.class ? (interfaces.isEmpty()? Object.class : interfaces.get(0)) : superType;
 282         final Package pkg = namingType.getPackage();
 283         final String namingTypeName = Type.getInternalName(namingType);
 284         final StringBuilder buf = new StringBuilder();
 285         if (namingTypeName.startsWith(JAVA_PACKAGE_PREFIX) || pkg == null || pkg.isSealed()) {
 286             // Can't define new classes in java.* packages


 350             initGlobal = new Label();
 351             mv.goTo(initGlobal);
 352             mv.visitLabel(notAFunction);
 353         } else {
 354             initGlobal = null;
 355         }
 356         // Assign MethodHandle fields through invoking getHandle() for a ScriptObject
 357         for (final MethodInfo mi : methodInfos) {
 358             mv.dup();
 359             mv.aconst(mi.getName());
 360             mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
 361             mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR, false);
 362             mv.putstatic(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
 363         }
 364 
 365         if(initGlobal != null) {
 366             mv.visitLabel(initGlobal);
 367         }
 368         // Assign "global = Context.getGlobal()"
 369         invokeGetGlobalWithNullCheck(mv);
 370         mv.putstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
 371 
 372         endInitMethod(mv);
 373     }
 374 
 375     private static void invokeGetGlobalWithNullCheck(final InstructionAdapter mv) {
 376         invokeGetGlobal(mv);
 377         mv.dup();
 378         mv.invokevirtual(OBJECT_TYPE_NAME, "getClass", GET_CLASS_METHOD_DESCRIPTOR, false); // check against null Context
 379         mv.pop();
 380     }
 381 
 382     private void generateConstructors() throws AdaptationException {
 383         boolean gotCtor = false;
 384         for (final Constructor<?> ctor: superClass.getDeclaredConstructors()) {
 385             final int modifier = ctor.getModifiers();
 386             if((modifier & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0 && !isCallerSensitive(ctor)) {
 387                 generateConstructors(ctor);
 388                 gotCtor = true;
 389             }
 390         }


 495             mv.visitVarInsn(ALOAD, 0);
 496             if (fromFunction && !mi.getName().equals(samName)) {
 497                 // Constructors initializing from a ScriptFunction only initialize methods with the SAM name.
 498                 // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overriden too. This
 499                 // is a deliberate design choice. All other method handles are initialized to null.
 500                 mv.visitInsn(ACONST_NULL);
 501             } else {
 502                 mv.visitVarInsn(ALOAD, offset);
 503                 if(!fromFunction) {
 504                     mv.aconst(mi.getName());
 505                 }
 506                 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
 507                 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor, false);
 508             }
 509             mv.putfield(generatedClassName, mi.methodHandleFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
 510         }
 511 
 512         // Assign "this.global = Context.getGlobal()"
 513         mv.visitVarInsn(ALOAD, 0);
 514         invokeGetGlobalWithNullCheck(mv);
 515         mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
 516 
 517         endInitMethod(mv);
 518     }
 519 
 520     private static void endInitMethod(final InstructionAdapter mv) {
 521         mv.visitInsn(RETURN);
 522         endMethod(mv);
 523     }
 524 
 525     private static void endMethod(final InstructionAdapter mv) {
 526         mv.visitMaxs(0, 0);
 527         mv.visitEnd();
 528     }
 529 
 530     private static void invokeGetGlobal(final InstructionAdapter mv) {
 531         mv.invokestatic(CONTEXT_TYPE_NAME, "getGlobal", GET_GLOBAL_METHOD_DESCRIPTOR, false);
 532     }
 533 
 534     private static void invokeSetGlobal(final InstructionAdapter mv) {
 535         mv.invokestatic(CONTEXT_TYPE_NAME, "setGlobal", SET_GLOBAL_METHOD_DESCRIPTOR, false);


 639         }
 640         // stack: [handle]
 641         jumpIfNonNullKeepOperand(mv, handleDefined);
 642 
 643         // No handle is available, fall back to default behavior
 644         if(Modifier.isAbstract(method.getModifiers())) {
 645             // If the super method is abstract, throw an exception
 646             mv.anew(UNSUPPORTED_OPERATION_TYPE);
 647             mv.dup();
 648             mv.invokespecial(UNSUPPORTED_OPERATION_TYPE_NAME, INIT, VOID_NOARG_METHOD_DESCRIPTOR, false);
 649             mv.athrow();
 650         } else {
 651             // If the super method is not abstract, delegate to it.
 652             emitSuperCall(mv, method.getDeclaringClass(), name, methodDesc);
 653         }
 654 
 655         mv.visitLabel(handleDefined);
 656         // Load the creatingGlobal object
 657         if(classOverride) {
 658             // If class handle is defined, load the static defining global
 659             mv.getstatic(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
 660         } else {
 661             mv.visitVarInsn(ALOAD, 0);
 662             mv.getfield(generatedClassName, GLOBAL_FIELD_NAME, GLOBAL_TYPE_DESCRIPTOR);
 663         }
 664         // stack: [creatingGlobal, handle]
 665         final Label setupGlobal = new Label();
 666         mv.visitLabel(setupGlobal);
 667 
 668         // Determine the first index for a local variable
 669         int nextLocalVar = 1; // "this" is at 0
 670         for(final Type t: asmArgTypes) {
 671             nextLocalVar += t.getSize();
 672         }
 673         // Set our local variable indices
 674         final int currentGlobalVar  = nextLocalVar++;
 675         final int globalsDifferVar  = nextLocalVar++;
 676 
 677         mv.dup();
 678         // stack: [creatingGlobal, creatingGlobal, handle]
 679 
 680         // Emit code for switching to the creating global
 681         // Global currentGlobal = Context.getGlobal();
 682         invokeGetGlobal(mv);
 683         mv.dup();
 684 
 685         mv.visitVarInsn(ASTORE, currentGlobalVar);
 686         // stack: [currentGlobal, creatingGlobal, creatingGlobal, handle]
 687         // if(definingGlobal == currentGlobal) {
 688         final Label globalsDiffer = new Label();
 689         mv.ifacmpne(globalsDiffer);
 690         // stack: [creatingGlobal, handle]
 691         //     globalsDiffer = false
 692         mv.pop();
 693         // stack: [handle]
 694         mv.iconst(0); // false
 695         // stack: [false, handle]
 696         final Label invokeHandle = new Label();
 697         mv.goTo(invokeHandle);
 698         mv.visitLabel(globalsDiffer);
 699         // } else {
 700         //     Context.setGlobal(definingGlobal);
 701         // stack: [creatingGlobal, handle]


 731         if (!throwableDeclared) {
 732             // Add "throw new RuntimeException(Throwable)" handler for Throwable
 733             throwableHandler = new Label();
 734             mv.visitLabel(throwableHandler);
 735             mv.anew(RUNTIME_EXCEPTION_TYPE);
 736             mv.dupX1();
 737             mv.swap();
 738             mv.invokespecial(RUNTIME_EXCEPTION_TYPE_NAME, INIT, Type.getMethodDescriptor(Type.VOID_TYPE, THROWABLE_TYPE), false);
 739             // Fall through to rethrow handler
 740         } else {
 741             throwableHandler = null;
 742         }
 743         final Label rethrowHandler = new Label();
 744         mv.visitLabel(rethrowHandler);
 745         // Rethrow handler for RuntimeException, Error, and all declared exception types
 746         emitFinally(mv, currentGlobalVar, globalsDifferVar);
 747         mv.athrow();
 748         final Label methodEnd = new Label();
 749         mv.visitLabel(methodEnd);
 750 
 751         mv.visitLocalVariable("currentGlobal", GLOBAL_TYPE_DESCRIPTOR, null, setupGlobal, methodEnd, currentGlobalVar);
 752         mv.visitLocalVariable("globalsDiffer", Type.INT_TYPE.getDescriptor(), null, setupGlobal, methodEnd, globalsDifferVar);
 753 
 754         if(throwableDeclared) {
 755             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, THROWABLE_TYPE_NAME);
 756             assert throwableHandler == null;
 757         } else {
 758             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, RUNTIME_EXCEPTION_TYPE_NAME);
 759             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, ERROR_TYPE_NAME);
 760             for(final String excName: exceptionNames) {
 761                 mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, rethrowHandler, excName);
 762             }
 763             mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME);
 764         }
 765         endMethod(mv);
 766     }
 767 
 768     /**
 769      * Emits code for jumping to a label if the top stack operand is not null. The operand is kept on the stack if it
 770      * is not null (so is available to code at the jump address) and is popped if it is null.
 771      * @param mv the instruction adapter being used to emit code