8141538: Make DynamicLinker specific to a Context in Nashorn
Reviewed-by: hannesw, sundar
This commit is contained in:
parent
87a85f53d6
commit
e3ea5caf72
@ -94,8 +94,8 @@ public final class Global extends Scope {
|
||||
// (__FILE__, __DIR__, __LINE__)
|
||||
private static final Object LAZY_SENTINEL = new Object();
|
||||
|
||||
private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
|
||||
private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
|
||||
private InvokeByName TO_STRING;
|
||||
private InvokeByName VALUE_OF;
|
||||
|
||||
/**
|
||||
* Optimistic builtin names that require switchpoint invalidation
|
||||
@ -1073,6 +1073,9 @@ public final class Global extends Scope {
|
||||
return;
|
||||
}
|
||||
|
||||
TO_STRING = new InvokeByName("toString", ScriptObject.class);
|
||||
VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
|
||||
|
||||
this.engine = eng;
|
||||
if (this.engine != null) {
|
||||
this.scontext = new ThreadLocal<>();
|
||||
@ -1357,18 +1360,27 @@ public final class Global extends Scope {
|
||||
return desc;
|
||||
}
|
||||
|
||||
private static <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
|
||||
private <T> T getLazilyCreatedValue(final Object key, final Callable<T> creator, final Map<Object, T> map) {
|
||||
final T obj = map.get(key);
|
||||
if (obj != null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
final Global oldGlobal = Context.getGlobal();
|
||||
final boolean differentGlobal = oldGlobal != this;
|
||||
try {
|
||||
if (differentGlobal) {
|
||||
Context.setGlobal(this);
|
||||
}
|
||||
final T newObj = creator.call();
|
||||
final T existingObj = map.putIfAbsent(key, newObj);
|
||||
return existingObj != null ? existingObj : newObj;
|
||||
} catch (final Exception exp) {
|
||||
throw new RuntimeException(exp);
|
||||
} finally {
|
||||
if (differentGlobal) {
|
||||
Context.setGlobal(oldGlobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import javax.script.ScriptEngine;
|
||||
import jdk.internal.dynalink.DynamicLinker;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
@ -89,6 +90,7 @@ import jdk.nashorn.internal.lookup.MethodHandleFactory;
|
||||
import jdk.nashorn.internal.objects.Global;
|
||||
import jdk.nashorn.internal.parser.Parser;
|
||||
import jdk.nashorn.internal.runtime.events.RuntimeEvent;
|
||||
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||
import jdk.nashorn.internal.runtime.logging.DebugLogger;
|
||||
import jdk.nashorn.internal.runtime.logging.Loggable;
|
||||
import jdk.nashorn.internal.runtime.logging.Logger;
|
||||
@ -512,6 +514,9 @@ public final class Context {
|
||||
/** Class loader to load classes compiled from scripts. */
|
||||
private final ScriptLoader scriptLoader;
|
||||
|
||||
/** Dynamic linker for linking call sites in script code loaded by this context */
|
||||
private final DynamicLinker dynamicLinker;
|
||||
|
||||
/** Current error manager. */
|
||||
private final ErrorManager errors;
|
||||
|
||||
@ -644,6 +649,7 @@ public final class Context {
|
||||
} else {
|
||||
this.appLoader = appLoader;
|
||||
}
|
||||
this.dynamicLinker = Bootstrap.createDynamicLinker(this.appLoader);
|
||||
|
||||
final int cacheSize = env._class_cache_size;
|
||||
if (cacheSize > 0) {
|
||||
@ -1295,6 +1301,26 @@ public final class Context {
|
||||
return getContext(getGlobal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Nashorn dynamic linker for the specified class. If the class is
|
||||
* a script class, the dynamic linker associated with its context is
|
||||
* returned. Otherwise the dynamic linker associated with the current
|
||||
* context is returned.
|
||||
* @param clazz the class for which we want to retrieve a dynamic linker.
|
||||
* @return the Nashorn dynamic linker for the specified class.
|
||||
*/
|
||||
public static DynamicLinker getDynamicLinker(final Class<?> clazz) {
|
||||
return fromClass(clazz).dynamicLinker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Nashorn dynamic linker associated with the current context.
|
||||
* @return the Nashorn dynamic linker for the current context.
|
||||
*/
|
||||
public static DynamicLinker getDynamicLinker() {
|
||||
return getContextTrusted().dynamicLinker;
|
||||
}
|
||||
|
||||
static Context getContextTrustedOrNull() {
|
||||
final Global global = Context.getGlobal();
|
||||
return global == null ? null : getContext(global);
|
||||
@ -1665,5 +1691,4 @@ public final class Context {
|
||||
public SwitchPoint getBuiltinSwitchPoint(final String name) {
|
||||
return builtinSwitchPoints.get(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
import jdk.nashorn.internal.lookup.MethodHandleFactory;
|
||||
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ECMAException;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.OptimisticReturnFilters;
|
||||
@ -81,14 +82,22 @@ public final class Bootstrap {
|
||||
* See for example octane.gbemu, run with --log=fields:warning to study
|
||||
* megamorphic behavior
|
||||
*/
|
||||
private static final int NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD = 16;
|
||||
private static final int UNSTABLE_RELINK_THRESHOLD_DEFAULT = 16;
|
||||
private static final int UNSTABLE_RELINK_THRESHOLD =
|
||||
Options.getIntProperty("nashorn.unstable.relink.threshold",
|
||||
UNSTABLE_RELINK_THRESHOLD_DEFAULT);
|
||||
|
||||
// do not create me!!
|
||||
private Bootstrap() {
|
||||
}
|
||||
|
||||
private static final DynamicLinker dynamicLinker;
|
||||
static {
|
||||
/**
|
||||
* Creates a Nashorn dynamic linker with the given app class loader.
|
||||
* @param appLoader the app class loader. It will be used to discover
|
||||
* additional language runtime linkers (if any).
|
||||
* @return a newly created dynamic linker.
|
||||
*/
|
||||
public static DynamicLinker createDynamicLinker(final ClassLoader appLoader) {
|
||||
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
|
||||
final NashornBeansLinker nashornBeansLinker = new NashornBeansLinker();
|
||||
factory.setPrioritizedLinkers(
|
||||
@ -116,15 +125,13 @@ public final class Bootstrap {
|
||||
}
|
||||
});
|
||||
factory.setInternalObjectsFilter(NashornBeansLinker.createHiddenObjectFilter());
|
||||
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD);
|
||||
if (relinkThreshold > -1) {
|
||||
factory.setUnstableRelinkThreshold(relinkThreshold);
|
||||
if (UNSTABLE_RELINK_THRESHOLD > -1) {
|
||||
factory.setUnstableRelinkThreshold(UNSTABLE_RELINK_THRESHOLD);
|
||||
}
|
||||
|
||||
// Linkers for any additional language runtimes deployed alongside Nashorn will be picked up by the factory.
|
||||
factory.setClassLoader(Bootstrap.class.getClassLoader());
|
||||
|
||||
dynamicLinker = factory.createLinker();
|
||||
factory.setClassLoader(appLoader);
|
||||
return factory.createLinker();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -202,7 +209,7 @@ public final class Bootstrap {
|
||||
* @return CallSite with MethodHandle to appropriate method or null if not found.
|
||||
*/
|
||||
public static CallSite bootstrap(final Lookup lookup, final String opDesc, final MethodType type, final int flags) {
|
||||
return dynamicLinker.link(LinkerCallSite.newLinkerCallSite(lookup, opDesc, type, flags));
|
||||
return Context.getDynamicLinker(lookup.lookupClass()).link(LinkerCallSite.newLinkerCallSite(lookup, opDesc, type, flags));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -461,7 +468,7 @@ public final class Bootstrap {
|
||||
* @return Nashorn's internal dynamic linker's services object.
|
||||
*/
|
||||
public static LinkerServices getLinkerServices() {
|
||||
return dynamicLinker.getLinkerServices();
|
||||
return Context.getDynamicLinker().getLinkerServices();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,7 @@
|
||||
*
|
||||
* @test
|
||||
* @option -Dnashorn.unstable.relink.threshold=1
|
||||
* @fork
|
||||
* @run
|
||||
*/
|
||||
|
||||
|
@ -32,9 +32,15 @@ import java.util.Map;
|
||||
import javax.script.Bindings;
|
||||
import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
import jdk.nashorn.internal.objects.Global;
|
||||
import jdk.nashorn.internal.objects.NativeArray;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.ErrorManager;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||
import jdk.nashorn.internal.runtime.options.Options;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
@ -44,6 +50,24 @@ import org.testng.annotations.Test;
|
||||
* @run testng jdk.nashorn.internal.runtime.test.JDK_8078414_Test
|
||||
*/
|
||||
public class JDK_8078414_Test {
|
||||
private static Context cx;
|
||||
private static Global oldGlobal;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
// We must have a Context for the DynamicLinker that Bootstrap.getLinkerServices() will use
|
||||
oldGlobal = Context.getGlobal();
|
||||
cx = new Context(new Options(""), new ErrorManager(), null);
|
||||
Context.setGlobal(cx.createGlobal());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
Context.setGlobal(oldGlobal);
|
||||
oldGlobal = null;
|
||||
cx = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanNotConvertArbitraryClassToMirror() {
|
||||
assertCanNotConvert(Double.class, Map.class);
|
||||
|
Loading…
x
Reference in New Issue
Block a user