This commit is contained in:
Lana Steuck 2016-11-17 22:19:05 +00:00
commit 3295cea5b9
9 changed files with 184 additions and 62 deletions

View File

@ -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}">

View File

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

View File

@ -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);
}

View File

@ -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());
}
}
}
}

View File

@ -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.
*/

View File

@ -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);
}
}
}
}

View File

@ -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));
}

View File

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

View File

@ -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");
}
}