8150219: ReferenceError in 1.8.0_72
authorhannesw
Mon, 20 Jun 2016 11:44:29 +0200
changeset 39076 2fb89709d552
parent 39075 c501f635c881
child 39077 c549268fe94c
8150219: ReferenceError in 1.8.0_72 Reviewed-by: attila, sundar
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngine.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
nashorn/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngine.java	Thu Jun 16 20:57:01 2016 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngine.java	Mon Jun 20 11:44:29 2016 +0200
@@ -318,6 +318,9 @@
         // Create new global instance mirror and associate with the Bindings.
         final ScriptObjectMirror mirror = createGlobalMirror();
         bindings.put(NASHORN_GLOBAL, mirror);
+        // Since we created this global explicitly for the non-default script context we set the
+        // current script context in global permanently so that invokes work as expected. See JDK-8150219
+        mirror.getHomeGlobal().setInitScriptContext(ctxt);
         return mirror.getHomeGlobal();
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Thu Jun 16 20:57:01 2016 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Mon Jun 20 11:44:29 2016 +0200
@@ -1087,6 +1087,8 @@
     private ThreadLocal<ScriptContext> scontext;
     // current ScriptEngine associated - can be null.
     private ScriptEngine engine;
+    // initial ScriptContext - usually null and only used for special case
+    private volatile ScriptContext initscontext;
 
     // ES6 global lexical scope.
     private final LexicalScope lexicalScope;
@@ -1112,9 +1114,22 @@
         return scontext.get();
     }
 
+    /**
+     * Set the initial script context
+     * @param ctxt initial script context
+     */
+    public void setInitScriptContext(final ScriptContext ctxt) {
+        this.initscontext = ctxt;
+    }
+
     private ScriptContext currentContext() {
         final ScriptContext sc = scontext != null? scontext.get() : null;
-        return (sc != null)? sc : (engine != null? engine.getContext() : null);
+        if (sc != null) {
+            return sc;
+        } else if (initscontext != null) {
+            return initscontext;
+        }
+        return engine != null? engine.getContext() : null;
     }
 
     @Override
--- a/nashorn/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java	Thu Jun 16 20:57:01 2016 +0000
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java	Mon Jun 20 11:44:29 2016 +0200
@@ -30,6 +30,8 @@
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 import javax.script.Bindings;
+import javax.script.Compilable;
+import javax.script.CompiledScript;
 import javax.script.Invocable;
 import javax.script.ScriptContext;
 import javax.script.ScriptEngine;
@@ -911,4 +913,27 @@
          Object value = ((Invocable)engine).invokeFunction("newfunc");
          assertTrue(((Number)value).intValue() == 42);
     }
+
+    // @bug 8150219 ReferenceError in 1.8.0_72
+    // When we create a Global for a non-default ScriptContext that needs one keep the
+    // ScriptContext associated with the Global so that invoke methods work as expected.
+    @Test
+    public void invokeFunctionWithCustomScriptContextTest() throws Exception {
+        final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
+
+        // create an engine and a ScriptContext, but don't set it as default
+        ScriptContext scriptContext = new SimpleScriptContext();
+
+        // Set some value in the context
+        scriptContext.setAttribute("myString", "foo", ScriptContext.ENGINE_SCOPE);
+
+        // Evaluate script with custom context and get back a function
+        final String script = "function (c) { return myString.indexOf(c); }";
+        CompiledScript compiledScript = ((Compilable)engine).compile(script);
+        Object func = compiledScript.eval(scriptContext);
+
+        // Invoked function should be able to see context it was evaluated with
+        Object result = ((Invocable) engine).invokeMethod(func, "call", func, "o", null);
+        assertTrue(((Number)result).intValue() == 1);
+    }
 }