< prev index next >

src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java

Print this page

        

@@ -29,28 +29,17 @@
 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS;
-import static jdk.internal.org.objectweb.asm.Opcodes.AALOAD;
 import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
-import static jdk.internal.org.objectweb.asm.Opcodes.ARRAYLENGTH;
 import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE;
 import static jdk.internal.org.objectweb.asm.Opcodes.D2F;
-import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
-import static jdk.internal.org.objectweb.asm.Opcodes.GOTO;
 import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
-import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
-import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGE;
-import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
-import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
-import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
 import static jdk.internal.org.objectweb.asm.Opcodes.I2B;
 import static jdk.internal.org.objectweb.asm.Opcodes.I2S;
-import static jdk.internal.org.objectweb.asm.Opcodes.POP;
-import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
 import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup;
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome.ERROR_NO_ACCESSIBLE_CONSTRUCTOR;

@@ -64,31 +53,26 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.FieldVisitor;
-import jdk.internal.org.objectweb.asm.Handle;
-import jdk.internal.org.objectweb.asm.Label;
-import jdk.internal.org.objectweb.asm.MethodVisitor;
-import jdk.internal.org.objectweb.asm.Opcodes;
-import jdk.internal.org.objectweb.asm.Type;
 import jdk.internal.org.objectweb.asm.Handle;
 import jdk.internal.org.objectweb.asm.Label;
 import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.org.objectweb.asm.Type;
 import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
 import jdk.nashorn.api.scripting.ScriptUtils;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
-import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome;
 import jdk.internal.reflect.CallerSensitive;
 

@@ -137,11 +121,12 @@
  * reason we are passing the additional argument at the end of the argument list instead at the front is that the
  * source-level script expression <code>new X(a, b) { ... }</code> (which is a proprietary syntax extension Nashorn uses
  * to resemble Java anonymous classes) is actually equivalent to <code>new X(a, b, { ... })</code>.
  * </p><p>
  * It is possible to create two different adapter classes: those that can have class-level overrides, and those that can
- * have instance-level overrides. When {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject)} is invoked
+ * have instance-level overrides. When {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject, ProtectionDomain)}
+ * or {@link JavaAdapterFactory#getAdapterClassFor(Class[], ScriptObject, Lookup)} is invoked
  * with non-null {@code classOverrides} parameter, an adapter class is created that can have class-level overrides, and
  * the passed script object will be used as the implementations for its methods, just as in the above case of the
  * constructor taking a script object. Note that in the case of class-level overrides, a new adapter class is created on
  * every invocation, and the implementation object is bound to the class, not to any instance. All created instances
  * will share these functions. If it is required to have both class-level overrides and instance-level overrides, the

@@ -166,10 +151,11 @@
 
     // Types often used in generated bytecode
     private static final Type OBJECT_TYPE = Type.getType(Object.class);
     private static final Type SCRIPT_OBJECT_TYPE = Type.getType(ScriptObject.class);
     private static final Type SCRIPT_FUNCTION_TYPE = Type.getType(ScriptFunction.class);
+    private static final Type SCRIPT_OBJECT_MIRROR_TYPE = Type.getType(ScriptObjectMirror.class);
 
     // JavaAdapterServices methods used in generated bytecode
     private static final Call CHECK_FUNCTION = lookupServiceMethod("checkFunction", ScriptFunction.class, Object.class, String.class);
     private static final Call EXPORT_RETURN_VALUE = lookupServiceMethod("exportReturnValue", Object.class, Object.class);
     private static final Call GET_CALL_THIS = lookupServiceMethod("getCallThis", Object.class, ScriptFunction.class, Object.class);

@@ -180,10 +166,11 @@
     private static final Call NOT_AN_OBJECT = lookupServiceMethod("notAnObject", void.class, Object.class);
     private static final Call SET_GLOBAL = lookupServiceMethod("setGlobal", Runnable.class, ScriptObject.class);
     private static final Call TO_CHAR_PRIMITIVE = lookupServiceMethod("toCharPrimitive", char.class, Object.class);
     private static final Call UNSUPPORTED = lookupServiceMethod("unsupported", UnsupportedOperationException.class);
     private static final Call WRAP_THROWABLE = lookupServiceMethod("wrapThrowable", RuntimeException.class, Throwable.class);
+    private static final Call UNWRAP_MIRROR = lookupServiceMethod("unwrapMirror", ScriptObject.class, Object.class, boolean.class);
 
     // Other methods invoked by the generated bytecode
     private static final Call UNWRAP = staticCallNoLookup(ScriptUtils.class, "unwrap", Object.class, Object.class);
     private static final Call CHAR_VALUE_OF = staticCallNoLookup(Character.class, "valueOf", Character.class, char.class);
     private static final Call DOUBLE_VALUE_OF = staticCallNoLookup(Double.class, "valueOf", Double.class, double.class);

@@ -214,12 +201,11 @@
 
     // Some more frequently used method descriptors
     private static final String GET_METHOD_PROPERTY_METHOD_DESCRIPTOR = Type.getMethodDescriptor(OBJECT_TYPE, SCRIPT_OBJECT_TYPE);
     private static final String VOID_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE);
 
-    static final String ADAPTER_PACKAGE_INTERNAL = "jdk/nashorn/javaadapters/";
-    static final String ADAPTER_PACKAGE = "jdk.nashorn.javaadapters";
+    private static final String ADAPTER_PACKAGE_INTERNAL = "jdk/nashorn/javaadapters/";
     private static final int MAX_GENERATED_TYPE_NAME_LENGTH = 255;
 
     // Method name prefix for invoking super-methods
     static final String SUPER_PREFIX = "super$";
 

@@ -454,18 +440,13 @@
     /**
      * Generates a constructor for the instance adapter class. This constructor will take the same arguments as the supertype
      * constructor passed as the argument here, and delegate to it. However, it will take an additional argument of
      * either ScriptObject or ScriptFunction type (based on the value of the "fromFunction" parameter), and initialize
      * all the method handle fields of the adapter instance with functions from the script object (or the script
-     * function itself, if that's what's passed). There is one method handle field in the adapter class for every method
-     * that can be implemented or overridden; the name of every field is same as the name of the method, with a number
-     * suffix that makes it unique in case of overloaded methods. The generated constructor will invoke
-     * {@link #getHandle(ScriptFunction, MethodType, boolean)} or {@link #getHandle(Object, String, MethodType,
-     * boolean)} to obtain the method handles; these methods make sure to add the necessary conversions and arity
-     * adjustments so that the resulting method handles can be invoked from generated methods using {@code invokeExact}.
-     * The constructor that takes a script function will only initialize the methods with the same name as the single
-     * abstract method. The constructor will also store the Nashorn global that was current at the constructor
+     * function itself, if that's what's passed). Additionally, it will create another constructor with an additional
+     * Object type parameter that can be used for ScriptObjectMirror objects.
+     * The constructor will also store the Nashorn global that was current at the constructor
      * invocation time in a field named "global". The generated constructor will be public, regardless of whether the
      * supertype constructor was public or protected. The generated constructor will not be variable arity, even if the
      * supertype constructor was.
      * @param ctor the supertype constructor that is serving as the base for the generated constructor.
      * @param fromFunction true if we're generating a constructor that initializes SAM types from a single

@@ -522,18 +503,63 @@
                     Type.getMethodDescriptor(originalCtorType.getReturnType(), newArgTypes), null, null));
             generateOverridingConstructorWithObjectParam(mv2, originalCtorType.getDescriptor());
         }
     }
 
-    // Object additional param accepting constructor - generated to handle null and undefined value
-    // for script adapters. This is effectively to throw TypeError on such script adapters. See
-    // JavaAdapterServices.getHandle as well.
+    // Object additional param accepting constructor for handling ScriptObjectMirror objects, which are
+    // unwrapped to work as ScriptObjects or ScriptFunctions. This also handles null and undefined values for
+    // script adapters by throwing TypeError on such script adapters.
     private void generateOverridingConstructorWithObjectParam(final InstructionAdapter mv, final String ctorDescriptor) {
         mv.visitCode();
         final int extraArgOffset = emitSuperConstructorCall(mv, ctorDescriptor);
+
+        // Check for ScriptObjectMirror
+        mv.visitVarInsn(ALOAD, extraArgOffset);
+        mv.instanceOf(SCRIPT_OBJECT_MIRROR_TYPE);
+        final Label notMirror = new Label();
+        mv.ifeq(notMirror);
+
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitVarInsn(ALOAD, extraArgOffset);
+        mv.iconst(0);
+        UNWRAP_MIRROR.invoke(mv);
+        mv.putfield(generatedClassName, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
+
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitVarInsn(ALOAD, extraArgOffset);
+        mv.iconst(1);
+        UNWRAP_MIRROR.invoke(mv);
+        mv.putfield(generatedClassName, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
+
+        final Label done = new Label();
+
+        if (samName != null) {
+            mv.visitVarInsn(ALOAD, 0);
+            mv.getfield(generatedClassName, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
+            mv.instanceOf(SCRIPT_FUNCTION_TYPE);
+            mv.ifeq(done);
+
+            // Assign "isFunction = true"
+            mv.visitVarInsn(ALOAD, 0);
+            mv.iconst(1);
+            mv.putfield(generatedClassName, IS_FUNCTION_FIELD_NAME, BOOLEAN_TYPE_DESCRIPTOR);
+
+            mv.visitVarInsn(ALOAD, 0);
+            mv.dup();
+            mv.getfield(generatedClassName, DELEGATE_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
+            mv.checkcast(SCRIPT_FUNCTION_TYPE);
+            emitInitCallThis(mv);
+            mv.goTo(done);
+        }
+
+        mv.visitLabel(notMirror);
+
+        // Throw error if not a ScriptObject
         mv.visitVarInsn(ALOAD, extraArgOffset);
         NOT_AN_OBJECT.invoke(mv);
+
+        mv.visitLabel(done);
         endInitMethod(mv);
     }
 
     private static void endInitMethod(final InstructionAdapter mv) {
         mv.visitInsn(RETURN);

@@ -946,10 +972,11 @@
                 ++len;
             }
         }
         return len;
     }
+
     /**
      * Emit code to restore the previous Nashorn Context when needed.
      * @param mv the instruction adapter
      * @param globalRestoringRunnableVar index of the local variable holding the reference to the global restoring Runnable
      */
< prev index next >