blob: 713a33caad9db6682214c24857c88b88b5daf05d [file] [log] [blame]
/*
* Copyright (c) 2014, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime.test;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import org.testng.annotations.Test;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import javax.script.SimpleScriptContext;
import static org.testng.Assert.assertEquals;
/**
* Top-level lexical binding tests.
*
* @test
* @run testng jdk.nashorn.internal.runtime.test.LexicalBindingTest
*/
@SuppressWarnings("javadoc")
public class LexicalBindingTest {
final static String LANGUAGE_ES6 = "--language=es6";
final static int NUMBER_OF_CONTEXTS = 20;
final static int MEGAMORPHIC_LOOP_COUNT = 20;
/**
* Test access to global var-declared variables for shared script classes with multiple globals.
*/
@Test
public static void megamorphicVarTest() throws ScriptException, InterruptedException {
final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
final ScriptEngine e = factory.getScriptEngine();
final ScriptContext[] contexts = new ScriptContext[NUMBER_OF_CONTEXTS];
final String sharedScript = "foo";
for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
final ScriptContext context = contexts[i] = new SimpleScriptContext();
final Bindings b = e.createBindings();
context.setBindings(b, ScriptContext.ENGINE_SCOPE);
assertEquals(e.eval("var foo = '" + i + "';", context), null);
}
for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
final ScriptContext context = contexts[i];
assertEquals(e.eval(sharedScript, context), String.valueOf(i));
}
}
/**
* Test access to global lexically declared variables for shared script classes with multiple globals.
*/
@Test
public static void megamorphicMultiGlobalLetTest() throws ScriptException, InterruptedException {
final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
final ScriptContext[] contexts = new ScriptContext[NUMBER_OF_CONTEXTS];
final String sharedScript = "foo";
for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
final ScriptContext context = contexts[i] = new SimpleScriptContext();
final Bindings b = e.createBindings();
context.setBindings(b, ScriptContext.ENGINE_SCOPE);
assertEquals(e.eval("let foo = '" + i + "';", context), null);
}
for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
final ScriptContext context = contexts[i];
assertEquals(e.eval(sharedScript, context), String.valueOf(i));
}
}
/**
* Test access to global lexically declared variables for shared script classes with single global.
*/
@Test
public static void megamorphicSingleGlobalLetTest() throws ScriptException, InterruptedException {
final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
final String sharedGetterScript = "foo";
final String sharedSetterScript = "foo = 1";
for (int i = 0; i < MEGAMORPHIC_LOOP_COUNT; i++) {
assertEquals(e.eval(sharedSetterScript), 1);
assertEquals(e.eval(sharedGetterScript), 1);
assertEquals(e.eval("delete foo; a" + i + " = 1; foo = " + i + ";"), i);
assertEquals(e.eval(sharedGetterScript), i);
}
assertEquals(e.eval("let foo = 'foo';"), null);
assertEquals(e.eval(sharedGetterScript), "foo");
assertEquals(e.eval(sharedSetterScript), 1);
assertEquals(e.eval(sharedGetterScript), 1);
assertEquals(e.eval("this.foo"), MEGAMORPHIC_LOOP_COUNT - 1);
}
/**
* Test access to global lexically declared variables for shared script classes with single global.
*/
@Test
public static void megamorphicInheritedGlobalLetTest() throws ScriptException, InterruptedException {
final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
final String sharedGetterScript = "foo";
final String sharedSetterScript = "foo = 1";
for (int i = 0; i < MEGAMORPHIC_LOOP_COUNT; i++) {
assertEquals(e.eval(sharedSetterScript), 1);
assertEquals(e.eval(sharedGetterScript), 1);
assertEquals(e.eval("delete foo; a" + i + " = 1; Object.prototype.foo = " + i + ";"), i);
assertEquals(e.eval(sharedGetterScript), i);
}
assertEquals(e.eval("let foo = 'foo';"), null);
assertEquals(e.eval(sharedGetterScript), "foo");
assertEquals(e.eval(sharedSetterScript), 1);
assertEquals(e.eval(sharedGetterScript), 1);
assertEquals(e.eval("this.foo"), MEGAMORPHIC_LOOP_COUNT - 1);
}
/**
* Test multi-threaded access to global lexically declared variables for shared script classes with multiple globals.
*/
@Test
public static void multiThreadedLetTest() throws ScriptException, InterruptedException {
final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
final Bindings b = e.createBindings();
final ScriptContext origContext = e.getContext();
final ScriptContext newCtxt = new SimpleScriptContext();
newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
final String sharedScript = "foo";
assertEquals(e.eval("let foo = 'original context';", origContext), null);
assertEquals(e.eval("let foo = 'new context';", newCtxt), null);
final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
t1.start();
t2.start();
t1.join();
t2.join();
assertEquals(e.eval("foo = 'newer context';", newCtxt), "newer context");
final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
t3.start();
t4.start();
t3.join();
t4.join();
assertEquals(e.eval(sharedScript), "original context");
assertEquals(e.eval(sharedScript, newCtxt), "newer context");
}
private static class ScriptRunner implements Runnable {
final ScriptEngine engine;
final ScriptContext context;
final String source;
final Object expected;
final int iterations;
ScriptRunner(final ScriptEngine engine, final ScriptContext context, final String source, final Object expected, final int iterations) {
this.engine = engine;
this.context = context;
this.source = source;
this.expected = expected;
this.iterations = iterations;
}
@Override
public void run() {
try {
for (int i = 0; i < iterations; i++) {
assertEquals(engine.eval(source, context), expected);
}
} catch (final ScriptException se) {
throw new RuntimeException(se);
}
}
}
}