< 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 >