Merge
This commit is contained in:
commit
3295cea5b9
@ -524,17 +524,19 @@ grant codeBase "file:/${basedir}/test/script/basic/JDK-8158467.js" {
|
||||
<!-- only to be invoked as dependency of "test" target -->
|
||||
<target name="-test-classes-all" depends="jar" unless="test.class">
|
||||
<fileset id="test.classes" dir="${build.test.classes.dir}">
|
||||
<include name="**/dynalink/test/*Test.class"/>
|
||||
<include name="**/dynalink/beans/test/*Test.class"/>
|
||||
<include name="**/dynalink/linker/support/test/*Test.class"/>
|
||||
<include name="**/dynalink/support/test/*Test.class"/>
|
||||
<include name="**/dynalink/test/*Test.class"/>
|
||||
<include name="**/api/javaaccess/test/*Test.class"/>
|
||||
<include name="**/api/scripting/test/*Test.class"/>
|
||||
<include name="**/api/tree/test/*Test.class"/>
|
||||
<include name="**/codegen/test/*Test.class"/>
|
||||
<include name="**/parser/test/*Test.class"/>
|
||||
<include name="**/runtime/test/*Test.class"/>
|
||||
<include name="**/runtime/doubleconv/test/*Test.class"/>
|
||||
<include name="**/runtime/regexp/test/*Test.class"/>
|
||||
<include name="**/runtime/regexp/joni/test/*Test.class"/>
|
||||
<include name="**/runtime/doubleconv/test/*Test.class"/>
|
||||
<include name="**/framework/*Test.class"/>
|
||||
</fileset>
|
||||
</target>
|
||||
@ -550,6 +552,7 @@ grant codeBase "file:/${basedir}/test/script/basic/JDK-8158467.js" {
|
||||
<target name="-test-nosecurity" unless="test.class">
|
||||
<fileset id="test.nosecurity.classes" dir="${build.test.classes.dir}">
|
||||
<include name="**/framework/ScriptTest.class"/>
|
||||
<include name="**/runtime/linker/test/*Test.class"/>
|
||||
</fileset>
|
||||
<testng outputdir="${build.nosecurity.test.results.dir}/${testResultsSubDir}" classfilesetref="test.nosecurity.classes"
|
||||
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
||||
|
@ -88,6 +88,7 @@ import java.lang.invoke.MethodType;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import jdk.dynalink.internal.AccessControlContextFactory;
|
||||
@ -149,6 +150,11 @@ final class ClassString {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClassString[" + Arrays.toString(classes) + "]";
|
||||
}
|
||||
|
||||
boolean isVisibleFrom(final ClassLoader classLoader) {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -163,7 +163,7 @@ final class PackagesHelper {
|
||||
if (fm != null) {
|
||||
listPackage(StandardLocation.PLATFORM_CLASS_PATH, pkg, props);
|
||||
if (this.modulePathSet) {
|
||||
for (Set<Location> locs : fm.listModuleLocations(StandardLocation.MODULE_PATH)) {
|
||||
for (Set<Location> locs : fm.listLocationsForModules(StandardLocation.MODULE_PATH)) {
|
||||
for (Location loc : locs) {
|
||||
listPackage(loc, pkg, props);
|
||||
}
|
||||
|
@ -31,24 +31,13 @@ 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;
|
||||
@ -66,6 +55,7 @@ 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;
|
||||
@ -73,20 +63,14 @@ 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;
|
||||
@ -139,7 +123,8 @@ import jdk.internal.reflect.CallerSensitive;
|
||||
* 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
|
||||
@ -168,6 +153,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
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);
|
||||
@ -182,6 +168,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
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);
|
||||
@ -216,8 +203,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
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
|
||||
@ -265,7 +251,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
* @throws AdaptationException if the adapter can not be generated for some reason.
|
||||
*/
|
||||
JavaAdapterBytecodeGenerator(final Class<?> superClass, final List<Class<?>> interfaces,
|
||||
final ClassLoader commonLoader, final boolean classOverride) throws AdaptationException {
|
||||
final ClassLoader commonLoader, final boolean classOverride) throws AdaptationException {
|
||||
assert superClass != null && !superClass.isInterface();
|
||||
assert interfaces != null;
|
||||
|
||||
@ -369,7 +355,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
// If the class is a SAM, allow having ScriptFunction passed as class overrides
|
||||
mv.dup();
|
||||
mv.instanceOf(SCRIPT_FUNCTION_TYPE);
|
||||
mv.dup();
|
||||
mv.dup();
|
||||
mv.putstatic(generatedClassName, IS_FUNCTION_FIELD_NAME, BOOLEAN_TYPE_DESCRIPTOR);
|
||||
final Label notFunction = new Label();
|
||||
mv.ifeq(notFunction);
|
||||
@ -389,9 +375,9 @@ final class JavaAdapterBytecodeGenerator {
|
||||
private void emitInitCallThis(final InstructionAdapter mv) {
|
||||
loadField(mv, GLOBAL_FIELD_NAME, SCRIPT_OBJECT_TYPE_DESCRIPTOR);
|
||||
GET_CALL_THIS.invoke(mv);
|
||||
if(classOverride) {
|
||||
if(classOverride) {
|
||||
mv.putstatic(generatedClassName, CALL_THIS_FIELD_NAME, OBJECT_TYPE_DESCRIPTOR);
|
||||
} else {
|
||||
} else {
|
||||
// It is presumed ALOAD 0 was already executed
|
||||
mv.putfield(generatedClassName, CALL_THIS_FIELD_NAME, OBJECT_TYPE_DESCRIPTOR);
|
||||
}
|
||||
@ -427,10 +413,10 @@ final class JavaAdapterBytecodeGenerator {
|
||||
|
||||
if (samName == null) {
|
||||
return false;
|
||||
}
|
||||
// If all our abstract methods have a single name, generate an additional constructor, one that takes a
|
||||
// ScriptFunction as its first parameter and assigns it as the implementation for all abstract methods.
|
||||
generateOverridingConstructor(ctor, true);
|
||||
}
|
||||
// If all our abstract methods have a single name, generate an additional constructor, one that takes a
|
||||
// ScriptFunction as its first parameter and assigns it as the implementation for all abstract methods.
|
||||
generateOverridingConstructor(ctor, true);
|
||||
// If the original type only has a single abstract method name, as well as a default ctor, then it can
|
||||
// be automatically converted from JS function.
|
||||
return ctor.getParameterTypes().length == 0;
|
||||
@ -456,14 +442,9 @@ final class JavaAdapterBytecodeGenerator {
|
||||
* 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.
|
||||
@ -524,14 +505,59 @@ final class JavaAdapterBytecodeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -678,7 +704,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
// stack: [callThis, delegate]
|
||||
mv.goTo(callCallee);
|
||||
mv.visitLabel(notFunction);
|
||||
} else {
|
||||
} else {
|
||||
// If it's not a SAM method, and the delegate is a function,
|
||||
// it'll fall back to default behavior
|
||||
mv.ifne(defaultBehavior);
|
||||
@ -818,7 +844,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
if (isVarArgCall) {
|
||||
// Variable arity calls are always (Object callee, Object this, Object[] params)
|
||||
callParamTypes = new Class<?>[] { Object.class, Object.class, Object[].class };
|
||||
} else {
|
||||
} else {
|
||||
// Adjust invocation type signature for conversions we instituted in
|
||||
// convertParam; also, byte and short get passed as ints.
|
||||
final Class<?>[] origParamTypes = type.parameterArray();
|
||||
@ -868,13 +894,13 @@ final class JavaAdapterBytecodeGenerator {
|
||||
|
||||
|
||||
private void loadField(final InstructionAdapter mv, final String name, final String desc) {
|
||||
if(classOverride) {
|
||||
if(classOverride) {
|
||||
mv.getstatic(generatedClassName, name, desc);
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.getfield(generatedClassName, name, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void convertReturnValue(final InstructionAdapter mv, final Class<?> origReturnType) {
|
||||
if (origReturnType == void.class) {
|
||||
@ -948,6 +974,7 @@ final class JavaAdapterBytecodeGenerator {
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit code to restore the previous Nashorn Context when needed.
|
||||
* @param mv the instruction adapter
|
||||
@ -999,9 +1026,9 @@ final class JavaAdapterBytecodeGenerator {
|
||||
}
|
||||
|
||||
for (final Class<?> iface : interfaces) {
|
||||
if (cl.isAssignableFrom(iface)) {
|
||||
return iface;
|
||||
}
|
||||
if (cl.isAssignableFrom(iface)) {
|
||||
return iface;
|
||||
}
|
||||
}
|
||||
|
||||
// we better that interface that extends the given interface!
|
||||
@ -1122,8 +1149,8 @@ final class JavaAdapterBytecodeGenerator {
|
||||
if (Modifier.isFinal(m) || isCallerSensitive(typeMethod)) {
|
||||
finalMethods.add(mi);
|
||||
} else if (!finalMethods.contains(mi) && methodInfos.add(mi) && Modifier.isAbstract(m)) {
|
||||
abstractMethodNames.add(mi.getName());
|
||||
}
|
||||
abstractMethodNames.add(mi.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ public final class JavaAdapterFactory {
|
||||
/**
|
||||
* For a given class, create its adapter class and associated info.
|
||||
*
|
||||
* @param type the class for which the adapter is created
|
||||
* @param types the class and interfaces for which the adapter is created
|
||||
*
|
||||
* @return the adapter info for the class.
|
||||
*/
|
||||
|
@ -39,6 +39,7 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.AccessController;
|
||||
import java.security.CodeSigner;
|
||||
import java.security.CodeSource;
|
||||
@ -51,6 +52,7 @@ import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
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.internal.objects.Global;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ECMAException;
|
||||
@ -175,6 +177,23 @@ public final class JavaAdapterServices {
|
||||
return sobj.getMap().findProperty("toString") != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ScriptObject or Global field value from a ScriptObjectMirror using reflection.
|
||||
*
|
||||
* @param mirror the mirror object
|
||||
* @param getGlobal true if we want the global object, false to return the script object
|
||||
* @return the script object or global object
|
||||
*/
|
||||
public static ScriptObject unwrapMirror(final Object mirror, final boolean getGlobal) {
|
||||
assert mirror instanceof ScriptObjectMirror;
|
||||
try {
|
||||
final Field field = getGlobal ? MirrorFieldHolder.GLOBAL_FIELD : MirrorFieldHolder.SOBJ_FIELD;
|
||||
return (ScriptObject) field.get(mirror);
|
||||
} catch (final IllegalAccessException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate to {@link Bootstrap#bootstrap(Lookup, String, MethodType, int)}.
|
||||
* @param lookup MethodHandle lookup.
|
||||
@ -291,4 +310,24 @@ public final class JavaAdapterServices {
|
||||
.asCollector(Object[].class, type.parameterCount())
|
||||
.asType(type));
|
||||
}
|
||||
|
||||
// Initialization on demand holder for accessible ScriptObjectMirror fields
|
||||
private static class MirrorFieldHolder {
|
||||
|
||||
private static final Field SOBJ_FIELD = getMirrorField("sobj");
|
||||
private static final Field GLOBAL_FIELD = getMirrorField("global");
|
||||
|
||||
private static Field getMirrorField(final String fieldName) {
|
||||
try {
|
||||
final Field field = ScriptObjectMirror.class.getDeclaredField(fieldName);
|
||||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
|
||||
field.setAccessible(true);
|
||||
return null;
|
||||
});
|
||||
return field;
|
||||
} catch (final NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,12 +157,17 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
|
||||
*/
|
||||
private static GuardedInvocation getSamTypeConverter(final Class<?> sourceType, final Class<?> targetType, final Supplier<MethodHandles.Lookup> lookupSupplier) throws Exception {
|
||||
// If source type is more generic than ScriptFunction class, we'll need to use a guard
|
||||
final boolean isSourceTypeGeneric = sourceType.isAssignableFrom(ScriptFunction.class);
|
||||
final boolean isSourceTypeGeneric = sourceType.isAssignableFrom(ScriptObject.class);
|
||||
|
||||
if ((isSourceTypeGeneric || ScriptFunction.class.isAssignableFrom(sourceType)) && isAutoConvertibleFromFunction(targetType)) {
|
||||
final MethodHandle ctor = JavaAdapterFactory.getConstructor(ScriptFunction.class, targetType, getCurrentLookup(lookupSupplier));
|
||||
final Class<?> paramType = isSourceTypeGeneric ? Object.class : ScriptFunction.class;
|
||||
// Using Object.class as constructor source type means we're getting an overloaded constructor handle,
|
||||
// which is safe but slower than a single constructor handle. If the actual argument is a ScriptFunction it
|
||||
// would be nice if we could change the formal parameter to ScriptFunction.class and add a guard for it
|
||||
// in the main invocation.
|
||||
final MethodHandle ctor = JavaAdapterFactory.getConstructor(paramType, targetType, getCurrentLookup(lookupSupplier));
|
||||
assert ctor != null; // if isAutoConvertibleFromFunction() returned true, then ctor must exist.
|
||||
return new GuardedInvocation(ctor, isSourceTypeGeneric ? IS_SCRIPT_FUNCTION : null);
|
||||
return new GuardedInvocation(ctor, isSourceTypeGeneric ? IS_FUNCTION : null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -315,7 +320,7 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
|
||||
}
|
||||
|
||||
private static final MethodHandle IS_SCRIPT_OBJECT = Guards.isInstance(ScriptObject.class, MH.type(Boolean.TYPE, Object.class));
|
||||
private static final MethodHandle IS_SCRIPT_FUNCTION = Guards.isInstance(ScriptFunction.class, MH.type(Boolean.TYPE, Object.class));
|
||||
private static final MethodHandle IS_FUNCTION = findOwnMH("isFunction", boolean.class, Object.class);
|
||||
private static final MethodHandle IS_NATIVE_ARRAY = Guards.isOfClass(NativeArray.class, MH.type(Boolean.TYPE, Object.class));
|
||||
|
||||
private static final MethodHandle IS_NASHORN_OR_UNDEFINED_TYPE = findOwnMH("isNashornTypeOrUndefined", Boolean.TYPE, Object.class);
|
||||
@ -348,6 +353,11 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
|
||||
return obj instanceof ScriptObject? ScriptUtils.wrap((ScriptObject)obj) : obj;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean isFunction(final Object obj) {
|
||||
return obj instanceof ScriptFunction || obj instanceof ScriptObjectMirror && ((ScriptObjectMirror) obj).isFunction();
|
||||
}
|
||||
|
||||
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||
return MH.findStatic(MethodHandles.lookup(), NashornLinker.class, name, MH.type(rtype, types));
|
||||
}
|
||||
|
@ -130,7 +130,8 @@ ifneq ($(FAILURE_HANDLER_DIR), )
|
||||
-timeoutHandlerDir:$(FAILURE_HANDLER_DIR_MIXED)/jtregFailureHandler.jar \
|
||||
-observerDir:$(FAILURE_HANDLER_DIR_MIXED)/jtregFailureHandler.jar \
|
||||
-timeoutHandler:jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler \
|
||||
-observer:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver
|
||||
-observer:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver \
|
||||
-timeoutHandlerTimeout:0
|
||||
ifeq ($(UNAME_S), CYGWIN)
|
||||
JTREG_FAILURE_HANDLER_OPTIONS += -J-Djava.library.path="$(FAILURE_HANDLER_DIR_MIXED)"
|
||||
endif
|
||||
|
@ -29,11 +29,14 @@ import java.util.Deque;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptException;
|
||||
import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.api.scripting.NashornScriptEngine;
|
||||
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
@ -277,4 +280,37 @@ public class JavaAdapterTest {
|
||||
Assert.assertEquals(tla.getQueue().peek(), "Queue");
|
||||
Assert.assertEquals(tla.getDequeue().peek(), "Dequeue");
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testMirrorAdapter() throws ScriptException {
|
||||
final NashornScriptEngine e = (NashornScriptEngine) createEngine();
|
||||
e.setBindings(e.createBindings(), ScriptContext.GLOBAL_SCOPE); // Null by default
|
||||
|
||||
// Referencing functions from across scopes causes them to be wrapped in ScriptObjectMirrors
|
||||
e.eval("function convertObjectFromEngineScope(){ return new java.util.concurrent.Callable(o).call(); }", e.getBindings(ScriptContext.ENGINE_SCOPE));
|
||||
e.eval("function convertObjectFromGlobalScope(){ return new java.util.concurrent.Callable(o).call(); }", e.getBindings(ScriptContext.GLOBAL_SCOPE));
|
||||
e.eval("function convertFuncFromEngineScope(){ return new java.util.concurrent.Callable(g).call(); }", e.getBindings(ScriptContext.ENGINE_SCOPE));
|
||||
e.eval("function convertFuncFromGlobalScope(){ return new java.util.concurrent.Callable(g).call(); }", e.getBindings(ScriptContext.GLOBAL_SCOPE));
|
||||
e.eval("function convertParamFromEngineScope(){ return Java.type('jdk.nashorn.internal.runtime.linker.test.JavaAdapterTest').m(f);}", e.getBindings(ScriptContext.ENGINE_SCOPE));
|
||||
e.eval("function convertParamFromGlobalScope(){ return Java.type('jdk.nashorn.internal.runtime.linker.test.JavaAdapterTest').m(f);}", e.getBindings(ScriptContext.GLOBAL_SCOPE));
|
||||
|
||||
e.eval("var o = { call: function () { return 'ok from o'; } }", e.getBindings(ScriptContext.ENGINE_SCOPE));
|
||||
e.eval("function g() { return 'ok from g'; }", e.getBindings(ScriptContext.ENGINE_SCOPE));
|
||||
e.eval("function f(a) { return a.toUpperCase(); }", e.getBindings(ScriptContext.ENGINE_SCOPE));
|
||||
|
||||
try {
|
||||
Assert.assertEquals(e.invokeFunction("convertObjectFromEngineScope"), "ok from o");
|
||||
Assert.assertEquals(e.invokeFunction("convertObjectFromGlobalScope"), "ok from o");
|
||||
Assert.assertEquals(e.invokeFunction("convertFuncFromEngineScope"), "ok from g");
|
||||
Assert.assertEquals(e.invokeFunction("convertFuncFromGlobalScope"), "ok from g");
|
||||
Assert.assertEquals(e.invokeFunction("convertParamFromEngineScope"), "OK");
|
||||
Assert.assertEquals(e.invokeFunction("convertParamFromGlobalScope"), "OK");
|
||||
} catch (final NoSuchMethodException x) {
|
||||
throw new RuntimeException(x);
|
||||
}
|
||||
}
|
||||
|
||||
public static String m(final Function<String, String> f){
|
||||
return f.apply("ok");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user