diff options
Diffstat (limited to 'js/src/jit-test/tests/modules')
67 files changed, 1941 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/modules/add-to-namespace-import.js b/js/src/jit-test/tests/modules/add-to-namespace-import.js new file mode 100644 index 000000000..b5a6626bf --- /dev/null +++ b/js/src/jit-test/tests/modules/add-to-namespace-import.js @@ -0,0 +1,3 @@ +// |jit-test| module; error: TypeError +import * as ns from "module1.js"; +ns.b = 2; diff --git a/js/src/jit-test/tests/modules/ambiguous-import.js b/js/src/jit-test/tests/modules/ambiguous-import.js new file mode 100644 index 000000000..6a91f9537 --- /dev/null +++ b/js/src/jit-test/tests/modules/ambiguous-import.js @@ -0,0 +1,2 @@ +// |jit-test| module; error: SyntaxError +import { a } from "ambiguous.js"; diff --git a/js/src/jit-test/tests/modules/ambiguous-indirect-export.js b/js/src/jit-test/tests/modules/ambiguous-indirect-export.js new file mode 100644 index 000000000..17949955e --- /dev/null +++ b/js/src/jit-test/tests/modules/ambiguous-indirect-export.js @@ -0,0 +1,2 @@ +// |jit-test| module; error: SyntaxError +export { a } from "ambiguous.js"; diff --git a/js/src/jit-test/tests/modules/ambiguous-star-export.js b/js/src/jit-test/tests/modules/ambiguous-star-export.js new file mode 100644 index 000000000..b8c91445c --- /dev/null +++ b/js/src/jit-test/tests/modules/ambiguous-star-export.js @@ -0,0 +1,41 @@ +// Test ambigious export * statements. + +"use strict"; + +load(libdir + "asserts.js"); +load(libdir + "dummyModuleResolveHook.js"); + +function checkModuleEval(source, result) { + let m = parseModule(source); + m.declarationInstantiation(); + assertEq(m.evaluation(), result); +} + +function checkModuleSyntaxError(source) { + let m = parseModule(source); + assertThrowsInstanceOf(() => m.declarationInstantiation(), SyntaxError); +} + +let a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;"); +let b = moduleRepo['b'] = parseModule("export var b = 3; export var c = 4;"); +let c = moduleRepo['c'] = parseModule("export * from 'a'; export * from 'b';"); +c.declarationInstantiation(); +c.evaluation(); + +// Check importing/exporting non-ambiguous name works. +checkModuleEval("import { a } from 'c'; a;", 1); +checkModuleEval("export { a } from 'c';", undefined); + +// Check importing/exporting ambiguous name is a syntax error. +checkModuleSyntaxError("import { b } from 'c';"); +checkModuleSyntaxError("export { b } from 'c';"); + +// Check that namespace objects include only non-ambiguous names. +let m = parseModule("import * as ns from 'c'; ns;"); +m.declarationInstantiation(); +let ns = m.evaluation(); +let names = Object.keys(ns); +assertEq(names.length, 2); +assertEq('a' in ns, true); +assertEq('b' in ns, false); +assertEq('c' in ns, true); diff --git a/js/src/jit-test/tests/modules/assign-to-import.js b/js/src/jit-test/tests/modules/assign-to-import.js new file mode 100644 index 000000000..42abd66c5 --- /dev/null +++ b/js/src/jit-test/tests/modules/assign-to-import.js @@ -0,0 +1,3 @@ +// |jit-test| module; error: TypeError +import { a } from "module1.js"; +a = 2; diff --git a/js/src/jit-test/tests/modules/assign-to-namespace-import.js b/js/src/jit-test/tests/modules/assign-to-namespace-import.js new file mode 100644 index 000000000..faa55b619 --- /dev/null +++ b/js/src/jit-test/tests/modules/assign-to-namespace-import.js @@ -0,0 +1,3 @@ +// |jit-test| module; error: TypeError +import * as ns from "module1.js"; +ns.a = 2; diff --git a/js/src/jit-test/tests/modules/assign-to-namespace.js b/js/src/jit-test/tests/modules/assign-to-namespace.js new file mode 100644 index 000000000..396ec1b52 --- /dev/null +++ b/js/src/jit-test/tests/modules/assign-to-namespace.js @@ -0,0 +1,3 @@ +// |jit-test| module; error: TypeError +import * as ns from "module1.js"; +ns = 2; diff --git a/js/src/jit-test/tests/modules/bug-1168666.js b/js/src/jit-test/tests/modules/bug-1168666.js new file mode 100644 index 000000000..32aea2983 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1168666.js @@ -0,0 +1,2 @@ +// |jit-test| error: SyntaxError +export * diff --git a/js/src/jit-test/tests/modules/bug-1217593.js b/js/src/jit-test/tests/modules/bug-1217593.js new file mode 100644 index 000000000..ebf210b38 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1217593.js @@ -0,0 +1,6 @@ +enableOsiPointRegisterChecks(); +function f() { + return this; +} +f(); +f(); diff --git a/js/src/jit-test/tests/modules/bug-1219044.js b/js/src/jit-test/tests/modules/bug-1219044.js new file mode 100644 index 000000000..82cfeebb0 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1219044.js @@ -0,0 +1,5 @@ +if (!('oomTest' in this)) + quit(); + +oomTest(() => parseModule('import v from "mod";')); +fullcompartmentchecks(true); diff --git a/js/src/jit-test/tests/modules/bug-1219408.js b/js/src/jit-test/tests/modules/bug-1219408.js new file mode 100644 index 000000000..85d709289 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1219408.js @@ -0,0 +1,2 @@ +// |jit-test| error: Error +parseModule("").evaluation(); diff --git a/js/src/jit-test/tests/modules/bug-1225346.js b/js/src/jit-test/tests/modules/bug-1225346.js new file mode 100644 index 000000000..6d8908e98 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1225346.js @@ -0,0 +1,2 @@ +// |jit-test| error: Error: expected filename string, got number +parseModule("", 3); diff --git a/js/src/jit-test/tests/modules/bug-1233117.js b/js/src/jit-test/tests/modules/bug-1233117.js new file mode 100644 index 000000000..f313e1c4a --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1233117.js @@ -0,0 +1,2 @@ +// |jit-test| module +eval("1"); diff --git a/js/src/jit-test/tests/modules/bug-1233179.js b/js/src/jit-test/tests/modules/bug-1233179.js new file mode 100644 index 000000000..fefe51951 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1233179.js @@ -0,0 +1,6 @@ +let c = parseModule(` + function a(x) { return x; } + function b(x) { return i<40; } + function d(x) { return x + 3; } +`); +getLcovInfo(); diff --git a/js/src/jit-test/tests/modules/bug-1233915.js b/js/src/jit-test/tests/modules/bug-1233915.js new file mode 100644 index 000000000..98370ab6f --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1233915.js @@ -0,0 +1,10 @@ +g = newGlobal(); +g.parent = this; +g.eval("(" + function() { + Debugger(parent) + .onExceptionUnwind = function(frame) + frame.eval("") +} + ")()"); +m = parseModule(` s1 `); +m.declarationInstantiation(); +m.evaluation(); diff --git a/js/src/jit-test/tests/modules/bug-1236875.js b/js/src/jit-test/tests/modules/bug-1236875.js new file mode 100644 index 000000000..41751f947 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1236875.js @@ -0,0 +1,2 @@ +let m = parseModule(`{ function x() {} }`); +m.declarationInstantiation(); diff --git a/js/src/jit-test/tests/modules/bug-1245518.js b/js/src/jit-test/tests/modules/bug-1245518.js new file mode 100644 index 000000000..3ba79645b --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1245518.js @@ -0,0 +1,15 @@ +evalInFrame = function(global) { + dbgGlobal = newGlobal(); + dbg = new dbgGlobal.Debugger(); + return function(upCount, code) { + dbg.addDebuggee(global); + frame = dbg.getNewestFrame().older; + frame.eval(code); + } +}(this); +m = parseModule(` + function g() this.hours = 0; + evalInFrame.call(0, 0, "g()") +`); +m.declarationInstantiation(); +m.evaluation(); diff --git a/js/src/jit-test/tests/modules/bug-1247934.js b/js/src/jit-test/tests/modules/bug-1247934.js new file mode 100644 index 000000000..82746ac61 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1247934.js @@ -0,0 +1,11 @@ +// |jit-test| --unboxed-arrays + +let moduleRepo = {}; +setModuleResolveHook(function(module, specifier) { + return moduleRepo[specifier]; +}); +setJitCompilerOption("ion.warmup.trigger", 50); +s = ""; +for (i = 0; i < 1024; i++) s += "export let e" + i + "\n"; +moduleRepo['a'] = parseModule(s); +parseModule("import * as ns from 'a'").declarationInstantiation(); diff --git a/js/src/jit-test/tests/modules/bug-1251090.js b/js/src/jit-test/tests/modules/bug-1251090.js new file mode 100644 index 000000000..5c98f20c0 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1251090.js @@ -0,0 +1,3 @@ +// |jit-test| error: Error +offThreadCompileScript(""); +finishOffThreadModule(); diff --git a/js/src/jit-test/tests/modules/bug-1258097.js b/js/src/jit-test/tests/modules/bug-1258097.js new file mode 100644 index 000000000..c7f877043 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1258097.js @@ -0,0 +1,3 @@ +// |jit-test| module; error:SyntaxError +import x from 'y'; +function x() {} diff --git a/js/src/jit-test/tests/modules/bug-1283448.js b/js/src/jit-test/tests/modules/bug-1283448.js new file mode 100644 index 000000000..9ee6217ab --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1283448.js @@ -0,0 +1,10 @@ +// |jit-test| error: TypeError + +let moduleRepo = {}; +setModuleResolveHook(function(module, specifier) { + return moduleRepo[specifier]; +}); +let a = moduleRepo['a'] = parseModule("var x = 1; export { x };"); +let b = moduleRepo['b'] = parseModule("import { x as y } from 'a';"); +a.__proto__ = {15: 1337}; +b.declarationInstantiation(); diff --git a/js/src/jit-test/tests/modules/bug-1284486.js b/js/src/jit-test/tests/modules/bug-1284486.js new file mode 100644 index 000000000..9a3244ec3 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1284486.js @@ -0,0 +1,23 @@ +// |jit-test| error: InternalError + +// This tests that attempting to perform ModuleDeclarationInstantation a second +// time after a failure throws an error. Doing this would be a bug in the module +// loader, which is expected to throw away modules if there is an error +// instantiating them. +// +// The first attempt fails becuase module 'a' is not available. The second +// attempt fails because of the previous failure (it would otherwise succeed as +// 'a' is now available). + +let moduleRepo = {}; +setModuleResolveHook(function(module, specifier) { + return moduleRepo[specifier]; +}); +try { + let b = moduleRepo['b'] = parseModule("export var b = 3; export var c = 4;"); + let c = moduleRepo['c'] = parseModule("export * from 'a'; export * from 'b';"); + c.declarationInstantiation(); +} catch (exc) {} +let a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;"); +let d = moduleRepo['d'] = parseModule("import { a } from 'c'; a;"); +d.declarationInstantiation(); diff --git a/js/src/jit-test/tests/modules/bug-1287406.js b/js/src/jit-test/tests/modules/bug-1287406.js new file mode 100644 index 000000000..8eef16388 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1287406.js @@ -0,0 +1 @@ +parseModule("export default () => 1"); diff --git a/js/src/jit-test/tests/modules/bug-1287410.js b/js/src/jit-test/tests/modules/bug-1287410.js new file mode 100644 index 000000000..8a891372a --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1287410.js @@ -0,0 +1,22 @@ +// |jit-test| error: InternalError + +let moduleRepo = {}; +setModuleResolveHook(function(module, specifier) { + if (specifier in moduleRepo) + return moduleRepo[specifier]; + throw "Module '" + specifier + "' not found"; +}); +let a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;"); +let b = moduleRepo['b'] = parseModule("export var b = 3; export var c = 4;"); +let c = moduleRepo['c'] = parseModule("export * from 'a'; export * from 'b';"); +c.declarationInstantiation(); + +// Module 'a' is replaced with another module that has not been instantiated. +// This should not happen and would be a bug in the module loader. +a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;"); + +let d = moduleRepo['d'] = parseModule("import { a } from 'c'; a;"); + +// Attempting to instantiate 'd' throws an error because depdency 'a' of +// instantiated module 'c' is not instantiated. +d.declarationInstantiation(); diff --git a/js/src/jit-test/tests/modules/bug1105608.js b/js/src/jit-test/tests/modules/bug1105608.js new file mode 100644 index 000000000..98e6aded0 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1105608.js @@ -0,0 +1,9 @@ +// export-from should throw SyntaxError until it's implemented. + +var caught = false; +try { + eval("export { a } from 'b';"); +} catch (e) { + caught = true; +} +assertEq(caught, true); diff --git a/js/src/jit-test/tests/modules/bug1169850.js b/js/src/jit-test/tests/modules/bug1169850.js new file mode 100644 index 000000000..3f6fbeef9 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1169850.js @@ -0,0 +1,9 @@ +// export-default should throw SyntaxError until it's implemented. + +var caught = false; +try { + eval("export default 1;"); +} catch (e) { + caught = true; +} +assertEq(caught, true); diff --git a/js/src/jit-test/tests/modules/bug1198673.js b/js/src/jit-test/tests/modules/bug1198673.js new file mode 100644 index 000000000..509adb8e5 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1198673.js @@ -0,0 +1,2 @@ +// |jit-test| error: expected string to compile +parseModule((1)); diff --git a/js/src/jit-test/tests/modules/bug1204857.js b/js/src/jit-test/tests/modules/bug1204857.js new file mode 100644 index 000000000..451da2e28 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1204857.js @@ -0,0 +1,2 @@ +// |jit-test| error: SyntaxError: unexpected garbage after module +parseModule(("}")); diff --git a/js/src/jit-test/tests/modules/bug1210391.js b/js/src/jit-test/tests/modules/bug1210391.js new file mode 100644 index 000000000..78874a3c1 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1210391.js @@ -0,0 +1,8 @@ +load(libdir + "dummyModuleResolveHook.js"); +let a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;"); +let b = moduleRepo['b'] = parseModule("export var b = 3; export var c = 4;"); +let c = moduleRepo['c'] = parseModule("export * from 'a'; export * from 'b';"); +let d = moduleRepo['d'] = parseModule("import { a } from 'c'; a;"); +d.declarationInstantiation(); +d.evaluation(); + diff --git a/js/src/jit-test/tests/modules/cyclic-function-import.js b/js/src/jit-test/tests/modules/cyclic-function-import.js new file mode 100644 index 000000000..a7d61e9bd --- /dev/null +++ b/js/src/jit-test/tests/modules/cyclic-function-import.js @@ -0,0 +1,7 @@ +// |jit-test| module + +import { isOdd } from "isOdd.js" +import { isEven } from "isEven.js" + +assertEq(isEven(4), true); +assertEq(isOdd(5), true); diff --git a/js/src/jit-test/tests/modules/cyclic-import.js b/js/src/jit-test/tests/modules/cyclic-import.js new file mode 100644 index 000000000..3ca7bf123 --- /dev/null +++ b/js/src/jit-test/tests/modules/cyclic-import.js @@ -0,0 +1,3 @@ +// |jit-test| module; error: ReferenceError + +import { a } from "cyclicImport1.js"; diff --git a/js/src/jit-test/tests/modules/debugger-frames.js b/js/src/jit-test/tests/modules/debugger-frames.js new file mode 100644 index 000000000..ba7a1471c --- /dev/null +++ b/js/src/jit-test/tests/modules/debugger-frames.js @@ -0,0 +1,89 @@ +// Test debugger access to frames and environments work as expected inside a module. + +load(libdir + "asserts.js"); + +function assertArrayEq(actual, expected) +{ + var eq = actual.length == expected.length; + if (eq) { + for (var i = 0; i < actual.length; i++) { + if (actual[i] !== expected[i]) { + eq = false; + break; + } + } + } + if (!eq) { + print("Assertion failed: got " + JSON.stringify(actual) + + ", expected " + JSON.stringify(expected)); + quit(3); + } +} + +var g2 = newGlobal(); + +var dbg = Debugger(g2); +dbg.onDebuggerStatement = function (frame) { + // The current frame is a module frame. + assertEq(frame.type, 'module'); + assertEq(frame.this, undefined); + + // The frame's environement is a module environment. + let env = frame.environment; + assertEq(env.type, 'declarative'); + assertEq(env.callee, null); + + // Top level module definitions and imports are visible. + assertArrayEq(env.names().sort(), ['a', 'b', 'c', 'x', 'y', 'z']); + assertArrayEq(['a', 'b', 'c'].map(env.getVariable, env), [1, 2, 3]); + assertArrayEq(['x', 'y', 'z'].map(env.getVariable, env), [4, 5, 6]); + + // Cannot set imports or const bindings. + assertThrowsInstanceOf(() => env.setVariable('a', 10), TypeError); + assertThrowsInstanceOf(() => env.setVariable('b', 11), TypeError); + assertThrowsInstanceOf(() => env.setVariable('c', 12), TypeError); + env.setVariable('x', 7); + env.setVariable('y', 8); + assertThrowsInstanceOf(() => env.setVariable('z', 9), TypeError); + assertArrayEq(['a', 'b', 'c'].map(env.getVariable, env), [1, 2, 3]); + assertArrayEq(['x', 'y', 'z'].map(env.getVariable, env), [7, 8, 6]); + + // The global lexical is the next thing after the module on the scope chain, + // followed by the global. + assertEq(env.parent.type, 'declarative'); + assertEq(env.parent.parent.type, 'object'); + assertEq(env.parent.parent.parent, null); +}; + +f = g2.eval( +` + let moduleRepo = {}; + setModuleResolveHook(function(module, specifier) { + if (specifier in moduleRepo) + return moduleRepo[specifier]; + throw "Module '" + specifier + "' not found"; + }); + + // Set up a module to import from. + a = moduleRepo['a'] = parseModule( + \` + export var a = 1; + export let b = 2; + export const c = 3; + export function f(x) { return x + 1; } + \`); + a.declarationInstantiation(); + a.evaluation(); + + let m = parseModule( + \` + import { a, b, c } from 'a'; + var x = 4; + let y = 5; + const z = 6; + + debugger; + \`); + m.declarationInstantiation(); + m.evaluation(); +`); diff --git a/js/src/jit-test/tests/modules/debugger-vars-function.js b/js/src/jit-test/tests/modules/debugger-vars-function.js new file mode 100644 index 000000000..75dc02374 --- /dev/null +++ b/js/src/jit-test/tests/modules/debugger-vars-function.js @@ -0,0 +1,37 @@ +// Test debugger access to aliased and unaliased bindings work correctly. + +load(libdir + "asserts.js"); + +var g = newGlobal(); +var dbg = Debugger(g); +dbg.onDebuggerStatement = function (frame) { + let env = frame.environment.parent; + assertEq(env.getVariable('a'), 1); + assertEq(env.getVariable('b'), 2); + assertEq(env.getVariable('c'), 3); + assertEq(env.getVariable('d'), 4); + assertEq(env.getVariable('e'), 5); +}; + +g.eval( +` + let moduleRepo = {}; + setModuleResolveHook(function(module, specifier) { + if (specifier in moduleRepo) + return moduleRepo[specifier]; + throw "Module '" + specifier + "' not found"; + }); + + let m = parseModule( + \` + var a = 1; + let b = 2; + export var c = 3; + export let d = 4; + let e = 5; + function f() { debugger; return e; } + \`); + m.declarationInstantiation(); + m.evaluation(); +`); + diff --git a/js/src/jit-test/tests/modules/debugger-vars-toplevel.js b/js/src/jit-test/tests/modules/debugger-vars-toplevel.js new file mode 100644 index 000000000..8be8f4079 --- /dev/null +++ b/js/src/jit-test/tests/modules/debugger-vars-toplevel.js @@ -0,0 +1,38 @@ +// Test debugger access to aliased and unaliased bindings work correctly. + +load(libdir + "asserts.js"); + +var g = newGlobal(); +var dbg = Debugger(g); +dbg.onDebuggerStatement = function (frame) { + let env = frame.environment; + assertEq(env.getVariable('a'), 1); + assertEq(env.getVariable('b'), 2); + assertEq(env.getVariable('c'), 3); + assertEq(env.getVariable('d'), 4); + assertEq(env.getVariable('e'), 5); +}; + +g.eval( +` + let moduleRepo = {}; + setModuleResolveHook(function(module, specifier) { + if (specifier in moduleRepo) + return moduleRepo[specifier]; + throw "Module '" + specifier + "' not found"; + }); + + let m = parseModule( + \` + var a = 1; + let b = 2; + export var c = 3; + export let d = 4; + let e = 5; + function f() { return e; } + debugger; + \`); + m.declarationInstantiation(); + m.evaluation(); +`); + diff --git a/js/src/jit-test/tests/modules/delete-import.js b/js/src/jit-test/tests/modules/delete-import.js new file mode 100644 index 000000000..b76c028f6 --- /dev/null +++ b/js/src/jit-test/tests/modules/delete-import.js @@ -0,0 +1,3 @@ +// |jit-test| module; error: SyntaxError +import { a } from "module1.js"; +delete a; diff --git a/js/src/jit-test/tests/modules/delete-namespace-import.js b/js/src/jit-test/tests/modules/delete-namespace-import.js new file mode 100644 index 000000000..4b5f2d1c9 --- /dev/null +++ b/js/src/jit-test/tests/modules/delete-namespace-import.js @@ -0,0 +1,3 @@ +// |jit-test| module; error: TypeError +import * as ns from "module1.js"; +delete ns.a; diff --git a/js/src/jit-test/tests/modules/delete-namespace.js b/js/src/jit-test/tests/modules/delete-namespace.js new file mode 100644 index 000000000..ef23e2afc --- /dev/null +++ b/js/src/jit-test/tests/modules/delete-namespace.js @@ -0,0 +1,3 @@ +// |jit-test| module; error: SyntaxError +import * as ns from "module1.js"; +delete ns; diff --git a/js/src/jit-test/tests/modules/duplicate-exports.js b/js/src/jit-test/tests/modules/duplicate-exports.js new file mode 100644 index 000000000..7e45ac6f3 --- /dev/null +++ b/js/src/jit-test/tests/modules/duplicate-exports.js @@ -0,0 +1,32 @@ +// Test errors due to duplicate exports +load(libdir + "asserts.js"); + +function testSyntaxError(source) { + assertThrowsInstanceOf(function () { + parseModule(source); + }, SyntaxError); +} + +// SyntexError due to duplicate exports +testSyntaxError("export var v; export var v;"); +testSyntaxError("export var x, y, z; export var y;"); +testSyntaxError("export let v; var w; export {w as v};"); +testSyntaxError("export const v; var w; export {w as v};"); +testSyntaxError("export var v; let w; export {w as v};"); +testSyntaxError("export var v; const w; export {w as v};"); +testSyntaxError("export default 1; export default 2;"); +testSyntaxError("export default 1; export default function() {};"); +testSyntaxError("export default 1; export default function foo() {};"); +testSyntaxError("var v; export {v}; export {v};"); +testSyntaxError("var v, x; export {v}; export {x as v};"); +testSyntaxError("export default 1; export default export class { constructor() {} };"); +testSyntaxError("export default 1; export default export class foo { constructor() {} };"); + +// SyntaxError due to redeclared binding +testSyntaxError("export let v; export let v;"); +testSyntaxError("export let x, y, z; export let y;"); +testSyntaxError("export const v = 0; export const v = 0;"); +testSyntaxError("export const x = 0, y = 0, z = 0; export const y = 0;"); +testSyntaxError("export var v; export let v;"); +testSyntaxError("export var v; export const v = 0;"); +testSyntaxError("export let v; export const v;"); diff --git a/js/src/jit-test/tests/modules/duplicate-imports.js b/js/src/jit-test/tests/modules/duplicate-imports.js new file mode 100644 index 000000000..fa87ba8eb --- /dev/null +++ b/js/src/jit-test/tests/modules/duplicate-imports.js @@ -0,0 +1,27 @@ +// Test errors due to duplicate lexically declared names. + +load(libdir + "asserts.js"); + +function testNoError(source) { + parseModule(source); +} + +function testSyntaxError(source) { + assertThrowsInstanceOf(() => parseModule(source), SyntaxError); +} + +testNoError("import { a } from 'm';"); +testNoError("import { a as b } from 'm';"); +testNoError("import * as a from 'm';"); +testNoError("import a from 'm';"); + +testSyntaxError("import { a } from 'm'; let a = 1;"); +testSyntaxError("let a = 1; import { a } from 'm';"); +testSyntaxError("import { a } from 'm'; var a = 1;"); +testSyntaxError("var a = 1; import { a } from 'm';"); +testSyntaxError("import { a, b } from 'm'; const b = 1;"); +testSyntaxError("import { a } from 'm'; import { a } from 'm2';"); +testSyntaxError("import { a } from 'm'; import { b as a } from 'm2';"); +testSyntaxError("import { a } from 'm'; import * as a from 'm2';"); +testSyntaxError("import { a } from 'm'; import a from 'm2';"); + diff --git a/js/src/jit-test/tests/modules/eval-module-oom.js b/js/src/jit-test/tests/modules/eval-module-oom.js new file mode 100644 index 000000000..a1bd9db2a --- /dev/null +++ b/js/src/jit-test/tests/modules/eval-module-oom.js @@ -0,0 +1,26 @@ +// OOM tests for module parsing. + +if (!('oomTest' in this)) + quit(); + +load(libdir + "dummyModuleResolveHook.js"); + +const sa = +`export default 20; + export let a = 22; + export function f(x, y) { return x + y } +`; + +const sb = +`import x from "a"; + import { a as y } from "a"; + import * as ns from "a"; + ns.f(x, y); +`; + +oomTest(() => { + let a = moduleRepo['a'] = parseModule(sa); + let b = moduleRepo['b'] = parseModule(sb); + b.declarationInstantiation(); + assertEq(b.evaluation(), 42); +}); diff --git a/js/src/jit-test/tests/modules/export-declaration.js b/js/src/jit-test/tests/modules/export-declaration.js new file mode 100644 index 000000000..3c4a9b735 --- /dev/null +++ b/js/src/jit-test/tests/modules/export-declaration.js @@ -0,0 +1,440 @@ +load(libdir + "match.js"); +load(libdir + "asserts.js"); + +var { Pattern, MatchError } = Match; + +program = (elts) => Pattern({ + type: "Program", + body: elts +}) +exportDeclaration = (declaration, specifiers, source, isDefault) => Pattern({ + type: "ExportDeclaration", + declaration: declaration, + specifiers: specifiers, + source: source, + isDefault: isDefault +}); +exportSpecifier = (id, name) => Pattern({ + type: "ExportSpecifier", + id: id, + name: name +}); +exportBatchSpecifier = () => Pattern({ + type: "ExportBatchSpecifier" +}); +blockStatement = (body) => Pattern({ + type: "BlockStatement", + body: body +}); +functionDeclaration = (id, params, body) => Pattern({ + type: "FunctionDeclaration", + id: id, + params: params, + defaults: [], + body: body, + rest: null, + generator: false +}); +classDeclaration = (name) => Pattern({ + type: "ClassStatement", + id: name +}); +variableDeclaration = (decls) => Pattern({ + type: "VariableDeclaration", + kind: "var", + declarations: decls +}); +constDeclaration = (decls) => Pattern({ + type: "VariableDeclaration", + kind: "const", + declarations: decls +}); +letDeclaration = (decls) => Pattern({ + type: "VariableDeclaration", + kind: "let", + declarations: decls +}); +ident = (name) => Pattern({ + type: "Identifier", + name: name +}); +lit = (val) => Pattern({ + type: "Literal", + value: val +}); + +function parseAsModule(source) +{ + return Reflect.parse(source, {target: "module"}); +} + +program([ + exportDeclaration( + null, + [], + null, + false + ) +]).assert(parseAsModule("export {}")); + +program([ + letDeclaration([ + { + id: ident("a"), + init: lit(1) + } + ]), + exportDeclaration( + null, + [ + exportSpecifier( + ident("a"), + ident("a") + ) + ], + null, + false + ) +]).assert(parseAsModule("let a = 1; export { a }")); + +program([ + letDeclaration([ + { + id: ident("a"), + init: lit(1) + } + ]), + exportDeclaration( + null, + [ + exportSpecifier( + ident("a"), + ident("b") + ) + ], + null, + false + ) +]).assert(parseAsModule("let a = 1; export { a as b }")); + +program([ + letDeclaration([ + { + id: ident("as"), + init: lit(1) + } + ]), + exportDeclaration( + null, + [ + exportSpecifier( + ident("as"), + ident("as") + ) + ], + null, + false + ) +]).assert(parseAsModule("let as = 1; export { as as as }")); + +program([ + letDeclaration([ + { + id: ident("a"), + init: lit(1) + } + ]), + exportDeclaration( + null, + [ + exportSpecifier( + ident("a"), + ident("true") + ) + ], + null, + false + ) +]).assert(parseAsModule("let a = 1; export { a as true }")); + +program([ + letDeclaration([ + { + id: ident("a"), + init: lit(1) + }, + { + id: ident("b"), + init: lit(2) + } + ]), + exportDeclaration( + null, + [ + exportSpecifier( + ident("a"), + ident("a") + ), + exportSpecifier( + ident("b"), + ident("b") + ), + ], + null, + false + ) +]).assert(parseAsModule("let a = 1, b = 2; export { a, b }")); + +program([ + letDeclaration([ + { + id: ident("a"), + init: lit(1) + }, + { + id: ident("c"), + init: lit(2) + } + ]), + exportDeclaration( + null, + [ + exportSpecifier( + ident("a"), + ident("b") + ), + exportSpecifier( + ident("c"), + ident("d") + ), + ], + null, + false + ) +]).assert(parseAsModule("let a = 1, c = 2; export { a as b, c as d }")); + +program([ + exportDeclaration( + null, + [ + exportSpecifier( + ident("a"), + ident("a") + ) + ], + lit("b"), + false + ) +]).assert(parseAsModule("export { a } from 'b'")); + +program([ + exportDeclaration( + null, + [ + exportBatchSpecifier() + ], + lit("a"), + false + ) +]).assert(parseAsModule("export * from 'a'")); + +program([ + exportDeclaration( + functionDeclaration( + ident("f"), + [], + blockStatement([]) + ), + null, + null, + false + ) +]).assert(parseAsModule("export function f() {}")); + +program([ + exportDeclaration( + classDeclaration( + ident("Foo") + ), + null, + null, + false + ) +]).assert(parseAsModule("export class Foo { constructor() {} }")); + +program([ + exportDeclaration( + variableDeclaration([ + { + id: ident("a"), + init: lit(1) + }, { + id: ident("b"), + init: lit(2) + } + ]), + null, + null, + false + ) +]).assert(parseAsModule("export var a = 1, b = 2;")); + +program([ + exportDeclaration( + constDeclaration([ + { + id: ident("a"), + init: lit(1) + }, { + id: ident("b"), + init: lit(2) + } + ]), + null, + null, + false + ) +]).assert(parseAsModule("export const a = 1, b = 2;")); + +program([ + exportDeclaration( + letDeclaration([ + { + id: ident("a"), + init: lit(1) + }, { + id: ident("b"), + init: lit(2) + } + ]), + null, + null, + false + ) +]).assert(parseAsModule("export let a = 1, b = 2;")); + +program([ + exportDeclaration( + functionDeclaration( + ident("*default*"), + [], + blockStatement([]) + ), + null, + null, + true + ) +]).assert(parseAsModule("export default function() {}")); + +program([ + exportDeclaration( + functionDeclaration( + ident("foo"), + [], + blockStatement([]) + ), + null, + null, + true + ) +]).assert(parseAsModule("export default function foo() {}")); + +program([ + exportDeclaration( + classDeclaration( + ident("*default*") + ), + null, + null, + true + ) +]).assert(parseAsModule("export default class { constructor() {} }")); + +program([ + exportDeclaration( + classDeclaration( + ident("Foo") + ), + null, + null, + true + ) +]).assert(parseAsModule("export default class Foo { constructor() {} }")); + +program([ + exportDeclaration( + lit(1234), + null, + null, + true + ) +]).assert(parseAsModule("export default 1234")); + +assertThrowsInstanceOf(function () { + parseAsModule("export default 1234 5678"); +}, SyntaxError); + +var loc = parseAsModule("export { a as b } from 'c'", { + loc: true +}).body[0].loc; + +assertEq(loc.start.line, 1); +assertEq(loc.start.column, 0); +assertEq(loc.start.line, 1); +assertEq(loc.end.column, 26); + +assertThrowsInstanceOf(function () { + parseAsModule("function f() { export a }"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + parseAsModule("if (true) export a"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export {"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export {} from"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export {,} from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export { true as a } from 'b'"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + parseAsModule("export { a } from 'b' f();"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + parseAsModule("export *"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + parseAsModule("export * from 'b' f();"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export {}\nfrom ()"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("function() {}"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("class() { constructor() {} }"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export x"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export foo = 5"); +}, SyntaxError); diff --git a/js/src/jit-test/tests/modules/export-entries.js b/js/src/jit-test/tests/modules/export-entries.js new file mode 100644 index 000000000..ea0d6fd3b --- /dev/null +++ b/js/src/jit-test/tests/modules/export-entries.js @@ -0,0 +1,121 @@ +// Test localExportEntries property + +function testArrayContents(actual, expected) { + assertEq(actual.length, expected.length); + for (var i = 0; i < actual.length; i++) { + for (var property in expected[i]) { + assertEq(actual[i][property], expected[i][property]); + } + } +} + +function testLocalExportEntries(source, expected) { + var module = parseModule(source); + testArrayContents(module.localExportEntries, expected); +} + +testLocalExportEntries( + 'export var v;', + [{exportName: 'v', moduleRequest: null, importName: null, localName: 'v'}]); + +testLocalExportEntries( + 'export var v = 0;', + [{exportName: 'v', moduleRequest: null, importName: null, localName: 'v'}]); + +testLocalExportEntries( + 'export let x = 1;', + [{exportName: 'x', moduleRequest: null, importName: null, localName: 'x'}]); + +testLocalExportEntries( + 'export const x = 1;', + [{exportName: 'x', moduleRequest: null, importName: null, localName: 'x'}]); + +testLocalExportEntries( + 'export class foo { constructor() {} };', + [{exportName: 'foo', moduleRequest: null, importName: null, localName: 'foo'}]); + +testLocalExportEntries( + 'export default function f() {};', + [{exportName: 'default', moduleRequest: null, importName: null, localName: 'f'}]); + +testLocalExportEntries( + 'export default function() {};', + [{exportName: 'default', moduleRequest: null, importName: null, localName: '*default*'}]); + +testLocalExportEntries( + 'export default 42;', + [{exportName: 'default', moduleRequest: null, importName: null, localName: '*default*'}]); + +testLocalExportEntries( + 'let x = 1; export {x};', + [{exportName: 'x', moduleRequest: null, importName: null, localName: 'x'}]); + +testLocalExportEntries( + 'let v = 1; export {v as x};', + [{exportName: 'x', moduleRequest: null, importName: null, localName: 'v'}]); + +testLocalExportEntries( + 'export {x} from "mod";', + []); + +testLocalExportEntries( + 'export {v as x} from "mod";', + []); + +testLocalExportEntries( + 'export * from "mod";', + []); + +// Test indirectExportEntries property + +function testIndirectExportEntries(source, expected) { + var module = parseModule(source); + testArrayContents(module.indirectExportEntries, expected); +} + +testIndirectExportEntries( + 'export default function f() {};', + []); + +testIndirectExportEntries( + 'let x = 1; export {x};', + []); + +testIndirectExportEntries( + 'export {x} from "mod";', + [{exportName: 'x', moduleRequest: 'mod', importName: 'x', localName: null}]); + +testIndirectExportEntries( + 'export {v as x} from "mod";', + [{exportName: 'x', moduleRequest: 'mod', importName: 'v', localName: null}]); + +testIndirectExportEntries( + 'export * from "mod";', + []); + +testIndirectExportEntries( + 'import {v as x} from "mod"; export {x as y};', + [{exportName: 'y', moduleRequest: 'mod', importName: 'v', localName: null}]); + +// Test starExportEntries property + +function testStarExportEntries(source, expected) { + var module = parseModule(source); + testArrayContents(module.starExportEntries, expected); +} + +testStarExportEntries( + 'export default function f() {};', + []); + +testStarExportEntries( + 'let x = 1; export {x};', + []); + +testStarExportEntries( + 'export {x} from "mod";', + []); + +testStarExportEntries( + 'export * from "mod";', + [{exportName: null, moduleRequest: 'mod', importName: '*', localName: null}]); diff --git a/js/src/jit-test/tests/modules/global-scope.js b/js/src/jit-test/tests/modules/global-scope.js new file mode 100644 index 000000000..90a9f7026 --- /dev/null +++ b/js/src/jit-test/tests/modules/global-scope.js @@ -0,0 +1,32 @@ +// Test interaction with global object and global lexical scope. + +function parseAndEvaluate(source) { + let m = parseModule(source); + m.declarationInstantiation(); + return m.evaluation(); +} + +var x = 1; +assertEq(parseAndEvaluate("let r = x; x = 2; r"), 1); +assertEq(x, 2); + +let y = 3; +assertEq(parseAndEvaluate("let r = y; y = 4; r"), 3); +assertEq(y, 4); + +if (helperThreadCount() == 0) + quit(); + +function offThreadParseAndEvaluate(source) { + offThreadCompileModule(source); + let m = finishOffThreadModule(); + print("compiled"); + m.declarationInstantiation(); + return m.evaluation(); +} + +assertEq(offThreadParseAndEvaluate("let r = x; x = 5; r"), 2); +assertEq(x, 5); + +assertEq(offThreadParseAndEvaluate("let r = y; y = 6; r"), 4); +assertEq(y, 6); diff --git a/js/src/jit-test/tests/modules/import-declaration.js b/js/src/jit-test/tests/modules/import-declaration.js new file mode 100644 index 000000000..fd0881e4d --- /dev/null +++ b/js/src/jit-test/tests/modules/import-declaration.js @@ -0,0 +1,343 @@ +load(libdir + "match.js"); +load(libdir + "asserts.js"); + +var { Pattern, MatchError } = Match; + +program = (elts) => Pattern({ + type: "Program", + body: elts +}) +importDeclaration = (specifiers, source) => Pattern({ + type: "ImportDeclaration", + specifiers: specifiers, + source: source +}); +importSpecifier = (id, name) => Pattern({ + type: "ImportSpecifier", + id: id, + name: name +}); +ident = (name) => Pattern({ + type: "Identifier", + name: name +}) +lit = (val) => Pattern({ + type: "Literal", + value: val +}) + +function parseAsModule(source) +{ + return Reflect.parse(source, {target: "module"}); +} + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("a") + ) + ], + lit("b") + ) +]).assert(parseAsModule("import a from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("*"), + ident("a") + ) + ], + lit("b") + ) +]).assert(parseAsModule("import * as a from 'b'")); + +program([ + importDeclaration( + [], + lit("a") + ) +]).assert(parseAsModule("import {} from 'a'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("a") + ) + ], + lit("b") + ) +]).assert(parseAsModule("import { a } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("a") + ) + ], + lit("b") + ) +]).assert(parseAsModule("import { a, } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("b") + ) + ], + lit("c") + ) +]).assert(parseAsModule("import { a as b } from 'c'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("as"), + ident("as") + ) + ], + lit("a") + ) +]).assert(parseAsModule("import { as as as } from 'a'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("a") + ), + importSpecifier( + ident("*"), + ident("b") + ) + ], + lit("c") + ) +]).assert(parseAsModule("import a, * as b from 'c'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("d") + ) + ], + lit("a") + ) +]).assert(parseAsModule("import d, {} from 'a'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("d") + ), + importSpecifier( + ident("a"), + ident("a") + ) + ], + lit("b") + ) +]).assert(parseAsModule("import d, { a } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("d") + ), + importSpecifier( + ident("a"), + ident("b") + ) + ], + lit("c") + ) +]).assert(parseAsModule("import d, { a as b } from 'c'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("d") + ), + importSpecifier( + ident("a"), + ident("a") + ), + importSpecifier( + ident("b"), + ident("b") + ), + ], + lit("c") + ) +]).assert(parseAsModule("import d, { a, b } from 'c'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("d") + ), + importSpecifier( + ident("a"), + ident("b") + ), + importSpecifier( + ident("c"), + ident("f") + ), + ], + lit("e") + ) +]).assert(parseAsModule("import d, { a as b, c as f } from 'e'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("true"), + ident("a") + ) + ], + lit("b") + ) +]).assert(parseAsModule("import { true as a } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("a") + ), + importSpecifier( + ident("b"), + ident("b") + ), + ], + lit("c") + ) +]).assert(parseAsModule("import { a, b } from 'c'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("b") + ), + importSpecifier( + ident("c"), + ident("d") + ), + ], + lit("e") + ) +]).assert(parseAsModule("import { a as b, c as d } from 'e'")); + +program([ + importDeclaration( + [], + lit("a") + ) +]).assert(parseAsModule("import 'a'")); + +var loc = parseAsModule("import { a as b } from 'c'", { + loc: true +}).body[0].loc; + +assertEq(loc.start.line, 1); +assertEq(loc.start.column, 0); +assertEq(loc.start.line, 1); +assertEq(loc.end.column, 26); + +assertThrowsInstanceOf(function () { + parseAsModule("function f() { import a from 'b' }"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + parseAsModule("if (true) import a from 'b'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import {"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import {}"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import {} from"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import {,} from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import { a as true } from 'b'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import { true } from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import a,"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import a, b from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import * as a,"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import * as a, {} from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import as a from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import * a from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import * as from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import , {} from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import d, from 'a'"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("import * as true from 'b'"); +}, SyntaxError); diff --git a/js/src/jit-test/tests/modules/import-default-class.js b/js/src/jit-test/tests/modules/import-default-class.js new file mode 100644 index 000000000..ff87649ac --- /dev/null +++ b/js/src/jit-test/tests/modules/import-default-class.js @@ -0,0 +1,5 @@ +// |jit-test| module + +import c from "defaultClass.js"; +let o = new c(); +assertEq(o.triple(14), 42); diff --git a/js/src/jit-test/tests/modules/import-default-function.js b/js/src/jit-test/tests/modules/import-default-function.js new file mode 100644 index 000000000..95e962448 --- /dev/null +++ b/js/src/jit-test/tests/modules/import-default-function.js @@ -0,0 +1,4 @@ +// |jit-test| module + +import f from "defaultFunction.js"; +assertEq(f(21), 42); diff --git a/js/src/jit-test/tests/modules/import-entries.js b/js/src/jit-test/tests/modules/import-entries.js new file mode 100644 index 000000000..da186b52e --- /dev/null +++ b/js/src/jit-test/tests/modules/import-entries.js @@ -0,0 +1,33 @@ +// Test importEntries property + +function testImportEntries(source, expected) { + var module = parseModule(source); + var actual = module.importEntries; + assertEq(actual.length, expected.length); + for (var i = 0; i < actual.length; i++) { + for (var property in expected[i]) { + assertEq(actual[i][property], expected[i][property]); + } + } +} + +testImportEntries('', []); + +testImportEntries('import v from "mod";', + [{moduleRequest: 'mod', importName: 'default', localName: 'v'}]); + +testImportEntries('import * as ns from "mod";', + [{moduleRequest: 'mod', importName: '*', localName: 'ns'}]); + +testImportEntries('import {x} from "mod";', + [{moduleRequest: 'mod', importName: 'x', localName: 'x'}]); + +testImportEntries('import {x as v} from "mod";', + [{moduleRequest: 'mod', importName: 'x', localName: 'v'}]); + +testImportEntries('import "mod";', + []); + +testImportEntries('import {x} from "a"; import {y} from "b";', + [{moduleRequest: 'a', importName: 'x', localName: 'x'}, + {moduleRequest: 'b', importName: 'y', localName: 'y'}]); diff --git a/js/src/jit-test/tests/modules/import-in-lazy-function.js b/js/src/jit-test/tests/modules/import-in-lazy-function.js new file mode 100644 index 000000000..cddacb142 --- /dev/null +++ b/js/src/jit-test/tests/modules/import-in-lazy-function.js @@ -0,0 +1,11 @@ +// |jit-test| module + +// Test that accessing imports in lazily parsed functions works. + +import { a } from "module1.js"; + +function add1(x) { + return x + a; +} + +assertEq(add1(2), 3); diff --git a/js/src/jit-test/tests/modules/import-namespace.js b/js/src/jit-test/tests/modules/import-namespace.js new file mode 100644 index 000000000..f44d4568a --- /dev/null +++ b/js/src/jit-test/tests/modules/import-namespace.js @@ -0,0 +1,105 @@ +// Test importing module namespaces + +"use strict"; + +load(libdir + "asserts.js"); +load(libdir + "iteration.js"); +load(libdir + "dummyModuleResolveHook.js"); + +function parseAndEvaluate(source) { + let m = parseModule(source); + m.declarationInstantiation(); + return m.evaluation(); +} + +function testHasNames(names, expected) { + assertEq(names.length, expected.length); + expected.forEach(function(name) { + assertEq(names.includes(name), true); + }); +} + +let a = moduleRepo['a'] = parseModule( + `export var a = 1; + export var b = 2;` +); + +let b = moduleRepo['b'] = parseModule( + `import * as ns from 'a'; + export { ns }; + export var x = ns.a + ns.b;` +); + +b.declarationInstantiation(); +b.evaluation(); +testHasNames(getModuleEnvironmentNames(b), ["ns", "x"]); +let ns = getModuleEnvironmentValue(b, "ns"); +testHasNames(Object.keys(ns), ["a", "b"]); +assertEq(getModuleEnvironmentValue(b, "x"), 3); + +// Test module namespace internal methods as defined in 9.4.6 +assertEq(Object.getPrototypeOf(ns), null); +assertThrowsInstanceOf(() => Object.setPrototypeOf(ns, null), TypeError); +assertThrowsInstanceOf(function() { ns.foo = 1; }, TypeError); +assertEq(Object.isExtensible(ns), false); +Object.preventExtensions(ns); +let desc = Object.getOwnPropertyDescriptor(ns, "a"); +assertEq(desc.value, 1); +assertEq(desc.writable, true); +assertEq(desc.enumerable, true); +assertEq(desc.configurable, false); +assertEq(typeof desc.get, "undefined"); +assertEq(typeof desc.set, "undefined"); +assertThrowsInstanceOf(function() { ns.a = 1; }, TypeError); +delete ns.foo; +assertThrowsInstanceOf(function() { delete ns.a; }, TypeError); + +// Test @@toStringTag property +desc = Object.getOwnPropertyDescriptor(ns, Symbol.toStringTag); +assertEq(desc.value, "Module"); +assertEq(desc.writable, false); +assertEq(desc.enumerable, false); +assertEq(desc.configurable, true); +assertEq(typeof desc.get, "undefined"); +assertEq(typeof desc.set, "undefined"); +assertEq(Object.prototype.toString.call(ns), "[object Module]"); + +// Test @@iterator method. +let iteratorFun = ns[Symbol.iterator]; +assertEq(iteratorFun.name, "[Symbol.iterator]"); + +let iterator = ns[Symbol.iterator](); +assertEq(iterator[Symbol.iterator](), iterator); +assertIteratorNext(iterator, "a"); +assertIteratorNext(iterator, "b"); +assertIteratorDone(iterator); + +// The iterator's next method can only be called on the object it was originally +// associated with. +iterator = ns[Symbol.iterator](); +let iterator2 = ns[Symbol.iterator](); +assertThrowsInstanceOf(() => iterator.next.call({}), TypeError); +assertThrowsInstanceOf(() => iterator.next.call(iterator2), TypeError); +assertEq(iterator.next.call(iterator).value, "a"); +assertEq(iterator2.next.call(iterator2).value, "a"); + +// Test cyclic namespace import and access in module evaluation. +let c = moduleRepo['c'] = + parseModule("export let c = 1; import * as ns from 'd'; let d = ns.d;"); +let d = moduleRepo['d'] = + parseModule("export let d = 2; import * as ns from 'c'; let c = ns.c;"); +c.declarationInstantiation(); +d.declarationInstantiation(); +assertThrowsInstanceOf(() => c.evaluation(), ReferenceError); + +// Test cyclic namespace import. +let e = moduleRepo['e'] = + parseModule("export let e = 1; import * as ns from 'f'; export function f() { return ns.f }"); +let f = moduleRepo['f'] = + parseModule("export let f = 2; import * as ns from 'e'; export function e() { return ns.e }"); +e.declarationInstantiation(); +f.declarationInstantiation(); +e.evaluation(); +f.evaluation(); +assertEq(e.namespace.f(), 2); +assertEq(f.namespace.e(), 1); diff --git a/js/src/jit-test/tests/modules/import-not-found.js b/js/src/jit-test/tests/modules/import-not-found.js new file mode 100644 index 000000000..05e6e1e8d --- /dev/null +++ b/js/src/jit-test/tests/modules/import-not-found.js @@ -0,0 +1,2 @@ +// |jit-test| module; error: SyntaxError +import { foo } from "module1.js"; diff --git a/js/src/jit-test/tests/modules/let-tdz.js b/js/src/jit-test/tests/modules/let-tdz.js new file mode 100644 index 000000000..b42679434 --- /dev/null +++ b/js/src/jit-test/tests/modules/let-tdz.js @@ -0,0 +1,3 @@ +// |jit-test| module; error:ReferenceError +foo = 1; +let foo; diff --git a/js/src/jit-test/tests/modules/many-exports.js b/js/src/jit-test/tests/modules/many-exports.js new file mode 100644 index 000000000..8e32d34fc --- /dev/null +++ b/js/src/jit-test/tests/modules/many-exports.js @@ -0,0 +1,19 @@ +// Test many exports. + +load(libdir + "dummyModuleResolveHook.js"); + +const count = 1024; + +let s = ""; +for (let i = 0; i < count; i++) + s += "export let e" + i + " = " + (i * i) + ";\n"; +let a = moduleRepo['a'] = parseModule(s); + +let b = moduleRepo['b'] = parseModule("import * as ns from 'a'"); + +b.declarationInstantiation(); +b.evaluation(); + +let ns = a.namespace; +for (let i = 0; i < count; i++) + assertEq(ns["e" + i], i * i); diff --git a/js/src/jit-test/tests/modules/many-imports.js b/js/src/jit-test/tests/modules/many-imports.js new file mode 100644 index 000000000..14ed6b810 --- /dev/null +++ b/js/src/jit-test/tests/modules/many-imports.js @@ -0,0 +1,17 @@ +// Test importing an import many times. + +load(libdir + "dummyModuleResolveHook.js"); + +const count = 1024; + +let a = moduleRepo['a'] = parseModule("export let a = 1;"); + +let s = ""; +for (let i = 0; i < count; i++) { + s += "import { a as i" + i + " } from 'a';\n"; + s += "assertEq(i" + i + ", 1);\n"; +} +let b = moduleRepo['b'] = parseModule(s); + +b.declarationInstantiation(); +b.evaluation(); diff --git a/js/src/jit-test/tests/modules/many-namespace-imports.js b/js/src/jit-test/tests/modules/many-namespace-imports.js new file mode 100644 index 000000000..bfcac8eef --- /dev/null +++ b/js/src/jit-test/tests/modules/many-namespace-imports.js @@ -0,0 +1,17 @@ +// Test importing a namespace many times. + +load(libdir + "dummyModuleResolveHook.js"); + +const count = 1024; + +let a = moduleRepo['a'] = parseModule("export let a = 1;"); + +let s = ""; +for (let i = 0; i < count; i++) { + s += "import * as ns" + i + " from 'a';\n"; + s += "assertEq(ns" + i + ".a, 1);\n"; +} +let b = moduleRepo['b'] = parseModule(s); + +b.declarationInstantiation(); +b.evaluation(); diff --git a/js/src/jit-test/tests/modules/missing-indirect-export.js b/js/src/jit-test/tests/modules/missing-indirect-export.js new file mode 100644 index 000000000..207e49ba0 --- /dev/null +++ b/js/src/jit-test/tests/modules/missing-indirect-export.js @@ -0,0 +1,2 @@ +// |jit-test| module; error: SyntaxError +export { foo } from "module1.js"; diff --git a/js/src/jit-test/tests/modules/module-declaration-instantiation.js b/js/src/jit-test/tests/modules/module-declaration-instantiation.js new file mode 100644 index 000000000..de820ae5b --- /dev/null +++ b/js/src/jit-test/tests/modules/module-declaration-instantiation.js @@ -0,0 +1,39 @@ +// Exercise ModuleDeclarationInstantiation() operation. + +load(libdir + "dummyModuleResolveHook.js"); + +function testModuleEnvironment(module, expected) { + var actual = getModuleEnvironmentNames(module).sort(); + assertEq(actual.length, expected.length); + for (var i = 0; i < actual.length; i++) { + assertEq(actual[i], expected[i]); + } +} + +// Check the environment of an empty module. +let m = parseModule(""); +m.declarationInstantiation(); +testModuleEnvironment(m, []); + +let a = moduleRepo['a'] = parseModule("var x = 1; export { x };"); +let b = moduleRepo['b'] = parseModule("import { x as y } from 'a';"); + +a.declarationInstantiation(); +b.declarationInstantiation(); + +testModuleEnvironment(a, ['x']); +testModuleEnvironment(b, ['y']); + +// Function bindings are initialized as well as instantiated. +let c = parseModule(`function a(x) { return x; } + function b(x) { return x + 1; } + function c(x) { return x + 2; } + function d(x) { return x + 3; }`); +const names = ['a', 'b', 'c', 'd']; +testModuleEnvironment(c, names); +names.forEach((n) => assertEq(typeof getModuleEnvironmentValue(c, n), "undefined")); +c.declarationInstantiation(); +for (let i = 0; i < names.length; i++) { + let f = getModuleEnvironmentValue(c, names[i]); + assertEq(f(21), 21 + i); +} diff --git a/js/src/jit-test/tests/modules/module-environment.js b/js/src/jit-test/tests/modules/module-environment.js new file mode 100644 index 000000000..9b869f617 --- /dev/null +++ b/js/src/jit-test/tests/modules/module-environment.js @@ -0,0 +1,34 @@ +// Test top-level module environment + +function testInitialEnvironment(source, expected) { + let module = parseModule(source); + let names = getModuleEnvironmentNames(module); + assertEq(names.length, expected.length); + expected.forEach(function(name) { + assertEq(names.includes(name), true); + }); +} + +// Non-exported bindings: only top-level functions are present in the +// environment. +testInitialEnvironment('', []); +testInitialEnvironment('var x = 1;', []); +testInitialEnvironment('let x = 1;', []); +testInitialEnvironment("if (true) { let x = 1; }", []); +testInitialEnvironment("if (true) { var x = 1; }", []); +testInitialEnvironment('function x() {}', ['x']); +testInitialEnvironment("class x { constructor() {} }", []); + +// Exported bindings must be present in the environment. +testInitialEnvironment('export var x = 1;', ['x']); +testInitialEnvironment('export let x = 1;', ['x']); +testInitialEnvironment('export default function x() {};', ['x']); +testInitialEnvironment('export default 1;', ['*default*']); +testInitialEnvironment('export default function() {};', ['*default*']); +testInitialEnvironment("export class x { constructor() {} }", ['x']); +testInitialEnvironment('export default class x { constructor() {} };', ['x']); +testInitialEnvironment('export default class { constructor() {} };', ['*default*']); + +// Imports: namespace imports are present. +testInitialEnvironment('import { x } from "m";', []); +testInitialEnvironment('import * as x from "m";', ['x']); diff --git a/js/src/jit-test/tests/modules/module-evaluation.js b/js/src/jit-test/tests/modules/module-evaluation.js new file mode 100644 index 000000000..eec13c040 --- /dev/null +++ b/js/src/jit-test/tests/modules/module-evaluation.js @@ -0,0 +1,94 @@ +// Exercise ModuleEvaluation() concrete method. + +load(libdir + "asserts.js"); +load(libdir + "dummyModuleResolveHook.js"); + +function parseAndEvaluate(source) { + let m = parseModule(source); + m.declarationInstantiation(); + return m.evaluation(); +} + +// Check the evaluation of an empty module succeeds. +assertEq(typeof parseAndEvaluate(""), "undefined"); + +// Check evaluation returns evaluation result the first time, then undefined. +let m = parseModule("1"); +m.declarationInstantiation(); +assertEq(m.evaluation(), 1); +assertEq(typeof m.evaluation(), "undefined"); + +// Check top level variables are initialized by evaluation. +m = parseModule("export var x = 2 + 2;"); +assertEq(typeof getModuleEnvironmentValue(m, "x"), "undefined"); +m.declarationInstantiation(); +m.evaluation(); +assertEq(getModuleEnvironmentValue(m, "x"), 4); + +m = parseModule("export let x = 2 * 3;"); +m.declarationInstantiation(); +m.evaluation(); +assertEq(getModuleEnvironmentValue(m, "x"), 6); + +// Set up a module to import from. +let a = moduleRepo['a'] = +parseModule(`var x = 1; + export { x }; + export default 2; + export function f(x) { return x + 1; }`); + +// Check we can evaluate top level definitions. +parseAndEvaluate("var foo = 1;"); +parseAndEvaluate("let foo = 1;"); +parseAndEvaluate("const foo = 1"); +parseAndEvaluate("function foo() {}"); +parseAndEvaluate("class foo { constructor() {} }"); + +// Check we can evaluate all module-related syntax. +parseAndEvaluate("export var foo = 1;"); +parseAndEvaluate("export let foo = 1;"); +parseAndEvaluate("export const foo = 1;"); +parseAndEvaluate("var x = 1; export { x };"); +parseAndEvaluate("export default 1"); +parseAndEvaluate("export default function() {};"); +parseAndEvaluate("export default function foo() {};"); +parseAndEvaluate("import a from 'a';"); +parseAndEvaluate("import { x } from 'a';"); +parseAndEvaluate("import * as ns from 'a';"); +parseAndEvaluate("export * from 'a'"); +parseAndEvaluate("export default class { constructor() {} };"); +parseAndEvaluate("export default class foo { constructor() {} };"); + +// Test default import +m = parseModule("import a from 'a'; a;") +m.declarationInstantiation(); +assertEq(m.evaluation(), 2); + +// Test named import +m = parseModule("import { x as y } from 'a'; y;") +m.declarationInstantiation(); +assertEq(m.evaluation(), 1); + +// Call exported function +m = parseModule("import { f } from 'a'; f(3);") +m.declarationInstantiation(); +assertEq(m.evaluation(), 4); + +// Test importing an indirect export +moduleRepo['b'] = parseModule("export { x as z } from 'a';"); +assertEq(parseAndEvaluate("import { z } from 'b'; z"), 1); + +// Test cyclic dependencies +moduleRepo['c1'] = parseModule("export var x = 1; export {y} from 'c2'"); +moduleRepo['c2'] = parseModule("export var y = 2; export {x} from 'c1'"); +assertDeepEq(parseAndEvaluate(`import { x as x1, y as y1 } from 'c1'; + import { x as x2, y as y2 } from 'c2'; + [x1, y1, x2, y2]`), + [1, 2, 1, 2]); + +// Import access in functions +m = parseModule("import { x } from 'a'; function f() { return x; }") +m.declarationInstantiation(); +m.evaluation(); +let f = getModuleEnvironmentValue(m, "f"); +assertEq(f(), 1); diff --git a/js/src/jit-test/tests/modules/module-this.js b/js/src/jit-test/tests/modules/module-this.js new file mode 100644 index 000000000..10a3241aa --- /dev/null +++ b/js/src/jit-test/tests/modules/module-this.js @@ -0,0 +1,15 @@ +// Test 'this' is undefined in modules. + +function parseAndEvaluate(source) { + let m = parseModule(source); + m.declarationInstantiation(); + return m.evaluation(); +} + +assertEq(typeof(parseAndEvaluate("this")), "undefined"); + +let m = parseModule("export function getThis() { return this; }"); +m.declarationInstantiation(); +m.evaluation(); +let f = getModuleEnvironmentValue(m, "getThis"); +assertEq(typeof(f()), "undefined"); diff --git a/js/src/jit-test/tests/modules/namespace-import-compilation-2.js b/js/src/jit-test/tests/modules/namespace-import-compilation-2.js new file mode 100644 index 000000000..ae322246d --- /dev/null +++ b/js/src/jit-test/tests/modules/namespace-import-compilation-2.js @@ -0,0 +1,17 @@ +// |jit-test| module + +import * as ns from 'module1.js'; + +let other = ns; + +const iterations = 2000; + +let x = 0; +for (let i = 0; i < iterations; i++) { + if (i == iterations / 2) + other = 1; + x += other.a; +} + +assertEq(other.a, undefined); +assertEq(x, NaN); diff --git a/js/src/jit-test/tests/modules/namespace-import-compilation.js b/js/src/jit-test/tests/modules/namespace-import-compilation.js new file mode 100644 index 000000000..42595b709 --- /dev/null +++ b/js/src/jit-test/tests/modules/namespace-import-compilation.js @@ -0,0 +1,17 @@ +// |jit-test| module + +import * as ns from 'module1.js'; + +let other = ns; + +const iterations = 10000; + +let x = 0; +for (let i = 0; i < iterations; i++) { + if (i == iterations / 2) + other = { a: 0 }; + x += other.a; +} + +assertEq(other.a, 0); +assertEq(x, iterations / 2); diff --git a/js/src/jit-test/tests/modules/off-thread-compile.js b/js/src/jit-test/tests/modules/off-thread-compile.js new file mode 100644 index 000000000..8d17d4a74 --- /dev/null +++ b/js/src/jit-test/tests/modules/off-thread-compile.js @@ -0,0 +1,16 @@ +// Test off thread module compilation. + +if (helperThreadCount() == 0) + quit(); + +load(libdir + "asserts.js"); +load(libdir + "dummyModuleResolveHook.js"); + +function offThreadParseAndEvaluate(source) { + offThreadCompileModule(source); + let m = finishOffThreadModule(); + m.declarationInstantiation(); + return m.evaluation(); +} + +offThreadParseAndEvaluate("export let x = 2 * 3;"); diff --git a/js/src/jit-test/tests/modules/recursive-star-export.js b/js/src/jit-test/tests/modules/recursive-star-export.js new file mode 100644 index 000000000..0313321c5 --- /dev/null +++ b/js/src/jit-test/tests/modules/recursive-star-export.js @@ -0,0 +1,2 @@ +// |jit-test| module; +import * as ns from "recursiveStarExport.js"; diff --git a/js/src/jit-test/tests/modules/requested-modules.js b/js/src/jit-test/tests/modules/requested-modules.js new file mode 100644 index 000000000..ee572d12e --- /dev/null +++ b/js/src/jit-test/tests/modules/requested-modules.js @@ -0,0 +1,30 @@ +// Test requestedModules property + +function testRequestedModules(source, expected) { + var module = parseModule(source); + var actual = module.requestedModules; + assertEq(actual.length, expected.length); + for (var i = 0; i < actual.length; i++) { + assertEq(actual[i], expected[i]); + } +} + +testRequestedModules("", []); + +testRequestedModules("import a from 'foo'", + ['foo']); + +testRequestedModules("import a from 'foo'; import b from 'bar'", + ['foo', 'bar']); + +testRequestedModules("import a from 'foo'; import b from 'bar'; import c from 'foo'", + ['foo', 'bar']); + +testRequestedModules("export {} from 'foo'", + ['foo']); + +testRequestedModules("export * from 'bar'", + ['bar']); + +testRequestedModules("import a from 'foo'; export {} from 'bar'; export * from 'baz'", + ['foo', 'bar', 'baz']); diff --git a/js/src/jit-test/tests/modules/shell-parse.js b/js/src/jit-test/tests/modules/shell-parse.js new file mode 100644 index 000000000..d01f10aaa --- /dev/null +++ b/js/src/jit-test/tests/modules/shell-parse.js @@ -0,0 +1,30 @@ +// Exercise shell parseModule function. + +function testEvalError(source) { + // Test |source| throws when passed to eval. + var caught = false; + try { + eval(source); + } catch (e) { + caught = true; + } + assertEq(caught, true); +} + +function testModuleSource(source) { + // Test |source| parses as a module, but throws when passed to eval. + testEvalError(source); + parseModule(source); +} + +parseModule(""); +parseModule("const foo = 1;"); +parseModule("var foo = 1;"); +parseModule("let foo = 1; var bar = 2; const baz = 3"); + +testModuleSource("import * as ns from 'bar';"); +testModuleSource("export { a } from 'b';"); +testModuleSource("export * from 'b';"); +testModuleSource("export const foo = 1;"); +testModuleSource("export default function() {};"); +testModuleSource("export default 1;"); diff --git a/js/src/jit-test/tests/modules/simple-imports.js b/js/src/jit-test/tests/modules/simple-imports.js new file mode 100644 index 000000000..a0c894ef6 --- /dev/null +++ b/js/src/jit-test/tests/modules/simple-imports.js @@ -0,0 +1,11 @@ +// |jit-test| module + +import { a } from "module1.js"; +import { b } from "module2.js"; +import { c } from "module3.js"; +import d from "module4.js"; + +assertEq(a, 1); +assertEq(b, 2); +assertEq(c, 3); +assertEq(d, 4); diff --git a/js/src/jit-test/tests/modules/unbound-export.js b/js/src/jit-test/tests/modules/unbound-export.js new file mode 100644 index 000000000..f70405d56 --- /dev/null +++ b/js/src/jit-test/tests/modules/unbound-export.js @@ -0,0 +1,2 @@ +// |jit-test| module; error: SyntaxError: local binding for export 'b' not found +export { b }; |