8141538: Make DynamicLinker specific to a Context in Nashorn
Reviewed-by: hannesw, sundar
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Mon Nov 09 14:03:37 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Mon Nov 09 14:04:43 2015 +0100
@@ -94,8 +94,8 @@
// (__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 @@
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 @@
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);
+ }
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Mon Nov 09 14:03:37 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Mon Nov 09 14:04:43 2015 +0100
@@ -73,6 +73,7 @@
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.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 @@
/** 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 @@
} else {
this.appLoader = appLoader;
}
+ this.dynamicLinker = Bootstrap.createDynamicLinker(this.appLoader);
final int cacheSize = env._class_cache_size;
if (cacheSize > 0) {
@@ -1295,6 +1301,26 @@
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 SwitchPoint getBuiltinSwitchPoint(final String name) {
return builtinSwitchPoints.get(name);
}
-
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java Mon Nov 09 14:03:37 2015 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java Mon Nov 09 14:04:43 2015 +0100
@@ -49,6 +49,7 @@
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 @@
* 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 @@
}
});
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 @@
* @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 @@
* @return Nashorn's internal dynamic linker's services object.
*/
public static LinkerServices getLinkerServices() {
- return dynamicLinker.getLinkerServices();
+ return Context.getDynamicLinker().getLinkerServices();
}
/**
--- a/nashorn/test/script/basic/JDK-8011578.js Mon Nov 09 14:03:37 2015 +0100
+++ b/nashorn/test/script/basic/JDK-8011578.js Mon Nov 09 14:04:43 2015 +0100
@@ -26,6 +26,7 @@
*
* @test
* @option -Dnashorn.unstable.relink.threshold=1
+ * @fork
* @run
*/
--- a/nashorn/test/src/jdk/nashorn/internal/runtime/test/JDK_8078414_Test.java Mon Nov 09 14:03:37 2015 +0100
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/test/JDK_8078414_Test.java Mon Nov 09 14:04:43 2015 +0100
@@ -32,9 +32,15 @@
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 @@
* @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);