LexicalBindingTest.java revision 1728:2e53f4d1445d
1/*
2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.runtime.test;
27
28import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
29import org.testng.annotations.Test;
30
31import javax.script.Bindings;
32import javax.script.ScriptContext;
33import javax.script.ScriptEngine;
34import javax.script.ScriptException;
35import javax.script.SimpleScriptContext;
36
37import static org.testng.Assert.assertEquals;
38
39/**
40 * Top-level lexical binding tests.
41 *
42 * @test
43 * @run testng jdk.nashorn.internal.runtime.test.LexicalBindingTest
44 */
45@SuppressWarnings("javadoc")
46public class LexicalBindingTest {
47
48    final static String LANGUAGE_ES6 = "--language=es6";
49    final static int NUMBER_OF_CONTEXTS = 40;
50    final static int MEGAMORPHIC_LOOP_COUNT = 40;
51
52    /**
53     * Test access to global var-declared variables for shared script classes with multiple globals.
54     */
55    @Test
56    public static void megamorphicVarTest() throws ScriptException, InterruptedException {
57        final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
58        final ScriptEngine e = factory.getScriptEngine();
59        final ScriptContext[] contexts = new ScriptContext[NUMBER_OF_CONTEXTS];
60        final String sharedScript1 = "foo";
61        final String sharedScript2 = "bar = foo; bar";
62
63
64        for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
65            final ScriptContext context = contexts[i] = new SimpleScriptContext();
66            final Bindings b = e.createBindings();
67            context.setBindings(b, ScriptContext.ENGINE_SCOPE);
68            assertEquals(e.eval("var foo = '" + i + "'; var bar;", context), null);
69        }
70
71        for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
72            final ScriptContext context = contexts[i];
73            assertEquals(e.eval(sharedScript1, context), String.valueOf(i));
74            assertEquals(e.eval(sharedScript2, context), String.valueOf(i));
75        }
76    }
77
78    /**
79     * Test access to global lexically declared variables for shared script classes with multiple globals.
80     */
81    @Test
82    public static void megamorphicMultiGlobalLetTest() throws ScriptException, InterruptedException {
83        final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
84        final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
85        final ScriptContext[] contexts = new ScriptContext[NUMBER_OF_CONTEXTS];
86        final String sharedScript1 = "foo";
87        final String sharedScript2 = "bar = foo; bar";
88
89
90        for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
91            final ScriptContext context = contexts[i] = new SimpleScriptContext();
92            final Bindings b = e.createBindings();
93            context.setBindings(b, ScriptContext.ENGINE_SCOPE);
94            assertEquals(e.eval("let foo = '" + i + "'; let bar; ", context), null);
95        }
96
97        for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) {
98            final ScriptContext context = contexts[i];
99            assertEquals(e.eval(sharedScript1, context), String.valueOf(i));
100            assertEquals(e.eval(sharedScript2, context), String.valueOf(i));
101        }
102    }
103
104
105    /**
106     * Test access to global lexically declared variables for shared script classes with single global.
107     */
108    @Test
109    public static void megamorphicSingleGlobalLetTest() throws ScriptException, InterruptedException {
110        final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
111        final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
112        final String sharedGetterScript = "foo";
113        final String sharedSetterScript = "foo = 1";
114
115        for (int i = 0; i < MEGAMORPHIC_LOOP_COUNT; i++) {
116            assertEquals(e.eval(sharedSetterScript), 1);
117            assertEquals(e.eval(sharedGetterScript), 1);
118            assertEquals(e.eval("delete foo; a" + i + " = 1; foo = " + i + ";"), i);
119            assertEquals(e.eval(sharedGetterScript), i);
120        }
121
122        assertEquals(e.eval("let foo = 'foo';"), null);
123        assertEquals(e.eval(sharedGetterScript), "foo");
124        assertEquals(e.eval(sharedSetterScript), 1);
125        assertEquals(e.eval(sharedGetterScript), 1);
126        assertEquals(e.eval("this.foo"), MEGAMORPHIC_LOOP_COUNT - 1);
127    }
128
129    /**
130     * Test access to global lexically declared variables for shared script classes with single global.
131     */
132    @Test
133    public static void megamorphicInheritedGlobalLetTest() throws ScriptException, InterruptedException {
134        final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
135        final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
136        final String sharedGetterScript = "foo";
137        final String sharedSetterScript = "foo = 1";
138
139        for (int i = 0; i < MEGAMORPHIC_LOOP_COUNT; i++) {
140            assertEquals(e.eval(sharedSetterScript), 1);
141            assertEquals(e.eval(sharedGetterScript), 1);
142            assertEquals(e.eval("delete foo; a" + i + " = 1; Object.prototype.foo = " + i + ";"), i);
143            assertEquals(e.eval(sharedGetterScript), i);
144        }
145
146        assertEquals(e.eval("let foo = 'foo';"), null);
147        assertEquals(e.eval(sharedGetterScript), "foo");
148        assertEquals(e.eval(sharedSetterScript), 1);
149        assertEquals(e.eval(sharedGetterScript), 1);
150        assertEquals(e.eval("this.foo"), MEGAMORPHIC_LOOP_COUNT - 1);
151    }
152
153    /**
154     * Test multi-threaded access to global lexically declared variables for shared script classes with multiple globals.
155     */
156    @Test
157    public static void multiThreadedLetTest() throws ScriptException, InterruptedException {
158        final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
159        final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
160        final Bindings b = e.createBindings();
161        final ScriptContext origContext = e.getContext();
162        final ScriptContext newCtxt = new SimpleScriptContext();
163        newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
164        final String sharedScript = "foo";
165
166        assertEquals(e.eval("let foo = 'original context';", origContext), null);
167        assertEquals(e.eval("let foo = 'new context';", newCtxt), null);
168
169        final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
170        final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
171        t1.start();
172        t2.start();
173        t1.join();
174        t2.join();
175
176        assertEquals(e.eval("foo = 'newer context';", newCtxt), "newer context");
177        final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
178        final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
179
180        t3.start();
181        t4.start();
182        t3.join();
183        t4.join();
184
185        assertEquals(e.eval(sharedScript), "original context");
186        assertEquals(e.eval(sharedScript, newCtxt), "newer context");
187    }
188
189    /**
190     * Make sure lexically defined variables are accessible in other scripts.
191     */
192    @Test
193    public void lexicalScopeTest() throws ScriptException {
194        final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
195        final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6);
196
197        e.eval("let x; const y = 'world';");
198
199        assertEquals(e.eval("x = 'hello'"), "hello");
200        assertEquals(e.eval("typeof x"), "string");
201        assertEquals(e.eval("typeof y"), "string");
202        assertEquals(e.eval("x"), "hello");
203        assertEquals(e.eval("y"), "world");
204        assertEquals(e.eval("typeof this.x"), "undefined");
205        assertEquals(e.eval("typeof this.y"), "undefined");
206        assertEquals(e.eval("this.x"), null);
207        assertEquals(e.eval("this.y"), null);
208    }
209
210    private static class ScriptRunner implements Runnable {
211
212        final ScriptEngine engine;
213        final ScriptContext context;
214        final String source;
215        final Object expected;
216        final int iterations;
217
218        ScriptRunner(final ScriptEngine engine, final ScriptContext context, final String source, final Object expected, final int iterations) {
219            this.engine = engine;
220            this.context = context;
221            this.source = source;
222            this.expected = expected;
223            this.iterations = iterations;
224        }
225
226        @Override
227        public void run() {
228            try {
229                for (int i = 0; i < iterations; i++) {
230                    assertEquals(engine.eval(source, context), expected);
231                }
232            } catch (final ScriptException se) {
233                throw new RuntimeException(se);
234            }
235        }
236    }
237}
238