diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/jit-test/tests/modules | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
146 files changed, 4251 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 0000000000..b5a6626bfc --- /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 0000000000..6a91f9537b --- /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 0000000000..17949955ea --- /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 0000000000..f90673bd9f --- /dev/null +++ b/js/src/jit-test/tests/modules/ambiguous-star-export.js @@ -0,0 +1,43 @@ +// Test ambigious export * statements. + +"use strict"; + +load(libdir + "asserts.js"); + +function checkModuleEval(source) { + let m = parseModule(source); + moduleLink(m); + moduleEvaluate(m); + return m; +} + +function checkModuleSyntaxError(source) { + let m = parseModule(source); + assertThrowsInstanceOf(() => moduleLink(m), SyntaxError); +} + +let a = registerModule('a', parseModule("export var a = 1; export var b = 2;")); +let b = registerModule('b', parseModule("export var b = 3; export var c = 4;")); +let c = registerModule('c', parseModule("export * from 'a'; export * from 'b';")); +moduleLink(c); +moduleEvaluate(c); + +// Check importing/exporting non-ambiguous name works. +let d = checkModuleEval("import { a } from 'c';"); +assertEq(getModuleEnvironmentValue(d, "a"), 1); +checkModuleEval("export { a } from 'c';"); + +// 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';"); +moduleLink(m); +moduleEvaluate(m); +let ns = c.namespace; +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 0000000000..42abd66c50 --- /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 0000000000..faa55b6198 --- /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 0000000000..396ec1b525 --- /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/async-eval-state.js b/js/src/jit-test/tests/modules/async-eval-state.js new file mode 100644 index 0000000000..b3c524d961 --- /dev/null +++ b/js/src/jit-test/tests/modules/async-eval-state.js @@ -0,0 +1,207 @@ +// Test module fields related to asynchronous evaluation. + +// Hardcoded values of ModuleStatus. Keep these in sync if the code changes. +const StatusUnlinked = 0; +const StatusLinked = 2; +const StatusEvaluating = 3; +const StatusEvaluatingAsync = 4; +const StatusEvaluated = 5; + +{ + let m = parseModule(''); + assertEq(m.status, StatusUnlinked); + + moduleLink(m); + assertEq(m.isAsyncEvaluating, false); + assertEq(m.status, StatusLinked); + + moduleEvaluate(m); + assertEq(m.isAsyncEvaluating, false); + assertEq(m.status, StatusEvaluated); +} + +{ + let m = parseModule('await 1;'); + + moduleLink(m); + assertEq(m.isAsyncEvaluating, false); + + moduleEvaluate(m); + assertEq(m.isAsyncEvaluating, true); + assertEq(m.status, StatusEvaluatingAsync); + assertEq(m.asyncEvaluatingPostOrder, 1); + + drainJobQueue(); + assertEq(m.isAsyncEvaluating, true); + assertEq(m.status, StatusEvaluated); + assertEq(m.asyncEvaluatingPostOrder, undefined); +} + +{ + let m = parseModule('await 1; throw 2;'); + + moduleLink(m); + moduleEvaluate(m).catch(() => 0); + assertEq(m.isAsyncEvaluating, true); + assertEq(m.status, StatusEvaluatingAsync); + assertEq(m.asyncEvaluatingPostOrder, 1); + + drainJobQueue(); + assertEq(m.isAsyncEvaluating, true); + assertEq(m.status, StatusEvaluated); + assertEq(m.evaluationError, 2); + assertEq(m.asyncEvaluatingPostOrder, undefined); +} + +{ + let m = parseModule('throw 1; await 2;'); + moduleLink(m); + moduleEvaluate(m).catch(() => 0); + assertEq(m.isAsyncEvaluating, true); + assertEq(m.status, StatusEvaluatingAsync); + assertEq(m.asyncEvaluatingPostOrder, 1); + + drainJobQueue(); + assertEq(m.isAsyncEvaluating, true); + assertEq(m.status, StatusEvaluated); + assertEq(m.evaluationError, 1); + assertEq(m.asyncEvaluatingPostOrder, undefined); +} + +{ + clearModules(); + let a = registerModule('a', parseModule('')); + let b = registerModule('b', parseModule('import {} from "a"; await 1;')); + + moduleLink(b); + moduleEvaluate(b); + assertEq(a.isAsyncEvaluating, false); + assertEq(a.status, StatusEvaluated); + assertEq(b.isAsyncEvaluating, true); + assertEq(b.status, StatusEvaluatingAsync); + assertEq(b.asyncEvaluatingPostOrder, 1); + + drainJobQueue(); + assertEq(a.isAsyncEvaluating, false); + assertEq(a.status, StatusEvaluated); + assertEq(b.isAsyncEvaluating, true); + assertEq(b.status, StatusEvaluated); + assertEq(b.asyncEvaluatingPostOrder, undefined); +} + +{ + clearModules(); + let a = registerModule('a', parseModule('await 1;')); + let b = registerModule('b', parseModule('import {} from "a";')); + + moduleLink(b); + moduleEvaluate(b); + assertEq(a.isAsyncEvaluating, true); + assertEq(a.status, StatusEvaluatingAsync); + assertEq(a.asyncEvaluatingPostOrder, 1); + assertEq(b.isAsyncEvaluating, true); + assertEq(b.status, StatusEvaluatingAsync); + assertEq(b.asyncEvaluatingPostOrder, 2); + + drainJobQueue(); + assertEq(a.isAsyncEvaluating, true); + assertEq(a.status, StatusEvaluated); + assertEq(a.asyncEvaluatingPostOrder, undefined); + assertEq(b.isAsyncEvaluating, true); + assertEq(b.status, StatusEvaluated); + assertEq(b.asyncEvaluatingPostOrder, undefined); +} + +{ + clearModules(); + let resolve; + var promise = new Promise(r => { resolve = r; }); + let a = registerModule('a', parseModule('await promise;')); + let b = registerModule('b', parseModule('await 2;')); + let c = registerModule('c', parseModule('import {} from "a"; import {} from "b";')); + + moduleLink(c); + moduleEvaluate(c); + assertEq(a.isAsyncEvaluating, true); + assertEq(a.status, StatusEvaluatingAsync); + assertEq(a.asyncEvaluatingPostOrder, 1); + assertEq(b.isAsyncEvaluating, true); + assertEq(b.status, StatusEvaluatingAsync); + assertEq(b.asyncEvaluatingPostOrder, 2); + assertEq(c.isAsyncEvaluating, true); + assertEq(c.status, StatusEvaluatingAsync); + assertEq(c.asyncEvaluatingPostOrder, 3); + + resolve(1); + drainJobQueue(); + assertEq(a.isAsyncEvaluating, true); + assertEq(a.status, StatusEvaluated); + assertEq(a.asyncEvaluatingPostOrder, undefined); + assertEq(b.isAsyncEvaluating, true); + assertEq(b.status, StatusEvaluated); + assertEq(b.asyncEvaluatingPostOrder, undefined); + assertEq(c.isAsyncEvaluating, true); + assertEq(c.status, StatusEvaluated); + assertEq(c.asyncEvaluatingPostOrder, undefined); +} + +{ + clearModules(); + let a = registerModule('a', parseModule('throw 1;')); + let b = registerModule('b', parseModule('import {} from "a"; await 2;')); + + moduleLink(b); + moduleEvaluate(b).catch(() => 0); + assertEq(a.status, StatusEvaluated); + assertEq(a.isAsyncEvaluating, false); + assertEq(a.evaluationError, 1); + assertEq(b.status, StatusEvaluated); + assertEq(b.isAsyncEvaluating, false); + assertEq(b.evaluationError, 1); +} + +{ + clearModules(); + let a = registerModule('a', parseModule('throw 1; await 2;')); + let b = registerModule('b', parseModule('import {} from "a";')); + + moduleLink(b); + moduleEvaluate(b).catch(() => 0); + assertEq(a.isAsyncEvaluating, true); + assertEq(a.status, StatusEvaluatingAsync); + assertEq(b.isAsyncEvaluating, true); + assertEq(b.status, StatusEvaluatingAsync); + + drainJobQueue(); + assertEq(a.isAsyncEvaluating, true); + assertEq(a.status, StatusEvaluated); + assertEq(a.evaluationError, 1); + assertEq(a.asyncEvaluatingPostOrder, undefined); + assertEq(b.isAsyncEvaluating, true); + assertEq(b.status, StatusEvaluated); + assertEq(b.evaluationError, 1); + assertEq(b.asyncEvaluatingPostOrder, undefined); +} + +{ + clearModules(); + let a = registerModule('a', parseModule('await 1; throw 2;')); + let b = registerModule('b', parseModule('import {} from "a";')); + + moduleLink(b); + moduleEvaluate(b).catch(() => 0); + assertEq(a.isAsyncEvaluating, true); + assertEq(a.status, StatusEvaluatingAsync); + assertEq(b.isAsyncEvaluating, true); + assertEq(b.status, StatusEvaluatingAsync); + + drainJobQueue(); + assertEq(a.isAsyncEvaluating, true); + assertEq(a.status, StatusEvaluated); + assertEq(a.evaluationError, 2); + assertEq(a.asyncEvaluatingPostOrder, undefined); + assertEq(b.isAsyncEvaluating, true); + assertEq(b.status, StatusEvaluated); + assertEq(b.evaluationError, 2); + assertEq(b.asyncEvaluatingPostOrder, undefined); +} diff --git a/js/src/jit-test/tests/modules/bad-namespace-created.js b/js/src/jit-test/tests/modules/bad-namespace-created.js new file mode 100644 index 0000000000..49fcc0c50f --- /dev/null +++ b/js/src/jit-test/tests/modules/bad-namespace-created.js @@ -0,0 +1,15 @@ +// Prior to https://github.com/tc39/ecma262/pull/916 it was possible for a +// module namespace object to be successfully created that was later found to be +// erroneous. Test that this is no longer the case. + +"use strict"; + +load(libdir + "asserts.js"); + +let a = registerModule('A', parseModule('import "B"; export {x} from "C"')); +registerModule('B', parseModule('import * as a from "A"')); +registerModule('C', parseModule('export * from "D"; export * from "E"')); +registerModule('D', parseModule('export let x')); +registerModule('E', parseModule('export let x')); + +assertThrowsInstanceOf(() => moduleLink(a), SyntaxError); 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 0000000000..32aea2983b --- /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 0000000000..ebf210b38e --- /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 0000000000..3917d7ca9c --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1219044.js @@ -0,0 +1,4 @@ +// |jit-test| skip-if: !('oomTest' in this) + +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 0000000000..1dcc5426b7 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1219408.js @@ -0,0 +1,2 @@ +// |jit-test| error: Error +moduleEvaluate(parseModule("")); 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 0000000000..6d8908e981 --- /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 0000000000..b84a84155a --- /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 0000000000..80e742b319 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1233179.js @@ -0,0 +1,8 @@ +// |jit-test| --code-coverage + +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 0000000000..4de08e50c9 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1233915.js @@ -0,0 +1,11 @@ +g = newGlobal({newCompartment: true}); +g.parent = this; +g.eval("(" + function() { + Debugger(parent) + .onExceptionUnwind = function(frame) { + return frame.eval(""); + }; +} + ")()"); +m = parseModule(` s1 `); +moduleLink(m); +moduleEvaluate(m); 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 0000000000..82ded01600 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1236875.js @@ -0,0 +1,2 @@ +let m = parseModule(`{ function x() {} }`); +moduleLink(m); 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 0000000000..857451cabd --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1245518.js @@ -0,0 +1,15 @@ +evalInFrame = function(global) { + dbgGlobal = newGlobal({newCompartment: true}); + dbg = new dbgGlobal.Debugger(); + return function(upCount, code) { + dbg.addDebuggee(global); + frame = dbg.getNewestFrame().older; + frame.eval(code); + } +}(this); +m = parseModule(` + function g() { return this.hours = 0; } + evalInFrame.call(0, 0, "g()") +`); +moduleLink(m); +moduleEvaluate(m); 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 0000000000..547f36faf6 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1247934.js @@ -0,0 +1,5 @@ +setJitCompilerOption("ion.warmup.trigger", 50); +s = ""; +for (i = 0; i < 1024; i++) s += "export let e" + i + "\n"; +registerModule('a', parseModule(s)); +moduleLink(parseModule("import * as ns from 'a'")); 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 0000000000..c7f8770436 --- /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 0000000000..def4d8cc6e --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1283448.js @@ -0,0 +1,4 @@ +let a = registerModule('a', parseModule("var x = 1; export { x };")); +let b = registerModule('b', parseModule("import { x as y } from 'a';")); +a.__proto__ = {15: 1337}; +moduleLink(b); diff --git a/js/src/jit-test/tests/modules/bug-1284486-2.js b/js/src/jit-test/tests/modules/bug-1284486-2.js new file mode 100644 index 0000000000..710f6e02eb --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1284486-2.js @@ -0,0 +1,34 @@ +// This tests that attempting to perform ModuleDeclarationInstantation a +// second time after a failure still fails. (It no longer stores and rethrows +// the same error; the spec changed in that regard and the implementation was +// updated in bug 1420420). +// +// The attempts fails becuase module 'a' is not available. +// +// This test exercises the path where the previously instantiated module is +// re-instantiated directly. + +let b = registerModule('b', parseModule("export var b = 3; export var c = 4;")); +let c = registerModule('c', parseModule("export * from 'a'; export * from 'b';")); + +let e1; +let threw = false; +try { + moduleLink(c); +} catch (exc) { + threw = true; + e1 = exc; +} +assertEq(threw, true); +assertEq(typeof e1 === "undefined", false); + +threw = false; +let e2; +try { + moduleLink(c); +} catch (exc) { + threw = true; + e2 = exc; +} +assertEq(threw, true); +assertEq(e1.toString(), e2.toString()); 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 0000000000..ba8aff1d07 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1284486.js @@ -0,0 +1,33 @@ +// This tests that module instantiation can succeed when executed a second +// time after a failure. +// +// The first attempt fails becuase module 'a' is not available. The second +// attempt succeeds as 'a' is now available. +// +// This test exercises the path where the previously instantiated module is +// encountered as an import. + +let b = registerModule('b', parseModule("export var b = 3; export var c = 4;")); +let c = registerModule('c', parseModule("export * from 'a'; export * from 'b';")); + +let e1; +let threw = false; +try { + moduleLink(c); +} catch (exc) { + threw = true; + e1 = exc; +} +assertEq(threw, true); +assertEq(typeof e1 === "undefined", false); + +let a = registerModule('a', parseModule("export var a = 1; export var b = 2;")); +let d = registerModule('d', parseModule("import { a } from 'c'; a;")); + +threw = false; +try { + moduleLink(d); +} catch (exc) { + threw = true; +} +assertEq(threw, false); 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 0000000000..8eef163886 --- /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 0000000000..cc9487746c --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1287410.js @@ -0,0 +1,17 @@ +// |jit-test| error: InternalError + +let a = registerModule('a', parseModule("export var a = 1; export var b = 2;")); +let b = registerModule('b', parseModule("export var b = 3; export var c = 4;")); +let c = registerModule('c', parseModule("export * from 'a'; export * from 'b';")); +moduleLink(c); + +// 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 = registerModule('a', parseModule("export var a = 1; export var b = 2;")); + +let d = registerModule('d', parseModule("import { a } from 'c'; a;")); + +// Attempting to instantiate 'd' throws an error because depdency 'a' of +// instantiated module 'c' is not instantiated. +moduleLink(d); +moduleEvaluate(d); diff --git a/js/src/jit-test/tests/modules/bug-1320993.js b/js/src/jit-test/tests/modules/bug-1320993.js new file mode 100644 index 0000000000..bece5731a3 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1320993.js @@ -0,0 +1,2 @@ +parseModule("export default (class {})"); +parseModule("export default (class A {})"); diff --git a/js/src/jit-test/tests/modules/bug-1372258.js b/js/src/jit-test/tests/modules/bug-1372258.js new file mode 100644 index 0000000000..a55979457f --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1372258.js @@ -0,0 +1,26 @@ +// |jit-test| skip-if: helperThreadCount() === 0 + +// Overwrite built-in parseModule with off-thread module parser. +function parseModule(source) { + offThreadCompileModuleToStencil(source); + var stencil = finishOffThreadStencil(); + return instantiateModuleStencil(stencil); +} + +// Test case derived from: js/src/jit-test/tests/modules/many-imports.js + +// Test importing an import many times. + +const count = 1024; + +let a = registerModule('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 = registerModule('b', parseModule(s)); + +moduleLink(b); +moduleEvaluate(b); diff --git a/js/src/jit-test/tests/modules/bug-1402535.js b/js/src/jit-test/tests/modules/bug-1402535.js new file mode 100644 index 0000000000..f8cf878260 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1402535.js @@ -0,0 +1,6 @@ +// |jit-test| skip-if: !('stackTest' in this) + +stackTest(function() { + let m = parseModule(``); + moduleLink(m); +}); diff --git a/js/src/jit-test/tests/modules/bug-1402649.js b/js/src/jit-test/tests/modules/bug-1402649.js new file mode 100644 index 0000000000..559a91a98f --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1402649.js @@ -0,0 +1,14 @@ +// |jit-test| skip-if: !('oomTest' in this) + +loadFile(` +function parseAndEvaluate(source) { + let m = parseModule(source); + moduleLink(m); +} +parseAndEvaluate("async function a() { await 2 + 3; }") +`); +function loadFile(lfVarx) { + oomTest(function() { + eval(lfVarx); + }); +} diff --git a/js/src/jit-test/tests/modules/bug-1406452.js b/js/src/jit-test/tests/modules/bug-1406452.js new file mode 100644 index 0000000000..e7293bc222 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1406452.js @@ -0,0 +1,5 @@ +// |jit-test| error: Error +let m = parseModule(`for (var x of iterator) {}`); +moduleLink(m); +try { moduleEvaluate(m); } catch (e) {} +getModuleEnvironmentValue(m, "r"); diff --git a/js/src/jit-test/tests/modules/bug-1420420-2.js b/js/src/jit-test/tests/modules/bug-1420420-2.js new file mode 100644 index 0000000000..1c1666295d --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1420420-2.js @@ -0,0 +1,17 @@ +// Test re-instantiation module after failure. + +load(libdir + "asserts.js"); + +registerModule("good", parseModule(`export let x`)); + +registerModule("y1", parseModule(`export let y`)); +registerModule("y2", parseModule(`export let y`)); +registerModule("bad", parseModule(`export* from "y1"; export* from "y2";`)); + +registerModule("a", parseModule(`import* as ns from "good"; import {y} from "bad";`)); + +let b = registerModule("b", parseModule(`import "a";`)); +let c = registerModule("c", parseModule(`import "a";`)); + +assertThrowsInstanceOf(() => moduleLink(b), SyntaxError); +assertThrowsInstanceOf(() => moduleLink(c), SyntaxError); diff --git a/js/src/jit-test/tests/modules/bug-1420420-3.js b/js/src/jit-test/tests/modules/bug-1420420-3.js new file mode 100644 index 0000000000..508afa41b1 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1420420-3.js @@ -0,0 +1,7 @@ +// |jit-test| skip-if: !('stackTest' in this) + +let a = parseModule(`throw new Error`); +moduleLink(a); +stackTest(function() { + moduleEvaluate(a); +}); diff --git a/js/src/jit-test/tests/modules/bug-1420420-4.js b/js/src/jit-test/tests/modules/bug-1420420-4.js new file mode 100644 index 0000000000..6181183ce3 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1420420-4.js @@ -0,0 +1,18 @@ +load(libdir + "asserts.js"); + +registerModule("a", parseModule(`throw undefined`)); + +let b = registerModule("b", parseModule(`import "a";`)); +let c = registerModule("c", parseModule(`import "a";`)); + +moduleLink(b); +moduleLink(c); + +(async () => { + let count = 0; + try { await moduleEvaluate(b) } catch (e) { count++; } + try { await moduleEvaluate(c) } catch (e) { count++; } + assertEq(count, 2); +})(); + +drainJobQueue(); diff --git a/js/src/jit-test/tests/modules/bug-1420420.js b/js/src/jit-test/tests/modules/bug-1420420.js new file mode 100644 index 0000000000..e8bbcb81c8 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1420420.js @@ -0,0 +1,17 @@ +// Test re-instantiation module after failure. + +load(libdir + "asserts.js"); + +registerModule("good", parseModule(`export let x`)); + +registerModule("y1", parseModule(`export let y`)); +registerModule("y2", parseModule(`export let y`)); +registerModule("bad", parseModule(`export* from "y1"; export* from "y2";`)); + +registerModule("a", parseModule(`import {x} from "good"; import {y} from "bad";`)); + +let b = registerModule("b", parseModule(`import "a";`)); +let c = registerModule("c", parseModule(`import "a";`)); + +assertThrowsInstanceOf(() => moduleLink(b), SyntaxError); +assertThrowsInstanceOf(() => moduleLink(c), SyntaxError); diff --git a/js/src/jit-test/tests/modules/bug-1435327.js b/js/src/jit-test/tests/modules/bug-1435327.js new file mode 100644 index 0000000000..bb9f18a220 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1435327.js @@ -0,0 +1,27 @@ +// |jit-test| skip-if: !('oomTest' in this) + +lfLogBuffer = ` + let c = registerModule('c', parseModule("")); + let d = registerModule('d', parseModule("import { a } from 'c'; a;")); + moduleLink(d); +`; +lfLogBuffer = lfLogBuffer.split('\n'); +var lfCodeBuffer = ""; +while (true) { + var line = lfLogBuffer.shift(); + if (line == null) { + break; + } else { + lfCodeBuffer += line + "\n"; + } +} +if (lfCodeBuffer) loadFile(lfCodeBuffer); +function loadFile(lfVarx) { + try { + oomTest(function() { + let m = parseModule(lfVarx); + moduleLink(m); + moduleEvaluate(m); + }); + } catch (lfVare) {} +} diff --git a/js/src/jit-test/tests/modules/bug-1439416-2.js b/js/src/jit-test/tests/modules/bug-1439416-2.js new file mode 100644 index 0000000000..b9202c112c --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1439416-2.js @@ -0,0 +1,10 @@ +function parseAsModule(source) { + return Reflect.parse(source, { + target: "module", + line: 0x7FFFFFFF + 1, + }); +} +parseAsModule(` + import {a} from ""; + export {a}; +`); diff --git a/js/src/jit-test/tests/modules/bug-1439416.js b/js/src/jit-test/tests/modules/bug-1439416.js new file mode 100644 index 0000000000..9dfe55b49a --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1439416.js @@ -0,0 +1,10 @@ +// Test that zero-based line numbers supplied by Reflect.parse don't cause +// assertions. + +function parseAsModule(source) { + return Reflect.parse(source, { + target: "module", + line: 0 + }); +} +parseAsModule("import d from 'a'"); diff --git a/js/src/jit-test/tests/modules/bug-1443555.js b/js/src/jit-test/tests/modules/bug-1443555.js new file mode 100644 index 0000000000..b67002d52d --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1443555.js @@ -0,0 +1,29 @@ +// |jit-test| error: TypeError + +"use strict"; + +setJitCompilerOption("baseline.warmup.trigger", 0); + +let mainSrc = ` +import A from "A"; + +const a = A; + +function requestAnimationFrame(f) { Promise.resolve().then(f); }; + +requestAnimationFrame(loopy); +a = 2; +function loopy() { + A; +} +`; + +let ASrc = ` +export default 1; +`; + +registerModule('A', parseModule(ASrc)); + +let m = parseModule(mainSrc); +moduleLink(m) +moduleEvaluate(m); diff --git a/js/src/jit-test/tests/modules/bug-1462286.js b/js/src/jit-test/tests/modules/bug-1462286.js new file mode 100644 index 0000000000..ffffc5ee6a --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1462286.js @@ -0,0 +1,8 @@ +let a = registerModule('a', parseModule(` + export var { ... get } = { x: "foo" }; +`)); + +let m = parseModule("import { get } from 'a'; export { get };"); +moduleLink(m); +moduleEvaluate(m) +assertEq(getModuleEnvironmentValue(m, "get").x, "foo"); diff --git a/js/src/jit-test/tests/modules/bug-1462326.js b/js/src/jit-test/tests/modules/bug-1462326.js new file mode 100644 index 0000000000..172b9246fa --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1462326.js @@ -0,0 +1,6 @@ +// |jit-test| error: Error + +let m = parseModule(` + import A from "A"; +`); +moduleLink(m); diff --git a/js/src/jit-test/tests/modules/bug-1466487.js b/js/src/jit-test/tests/modules/bug-1466487.js new file mode 100644 index 0000000000..50d7f18325 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1466487.js @@ -0,0 +1,7 @@ +// |jit-test| skip-if: helperThreadCount() === 0 + +evalInWorker(` + let m = parseModule("import.meta;"); + moduleLink(m); + moduleEvaluate(m); +`); diff --git a/js/src/jit-test/tests/modules/bug-1476921.js b/js/src/jit-test/tests/modules/bug-1476921.js new file mode 100644 index 0000000000..005099319f --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1476921.js @@ -0,0 +1,31 @@ +// |jit-test| +"use strict"; + +load(libdir + "asserts.js"); + +class UniqueError extends Error {} + +let a = registerModule('a', parseModule(` + throw new UniqueError(); +`)); + +let b = registerModule('b', parseModule(` + import * as ns0 from "a"; +`)); + +moduleLink(a); +moduleEvaluate(a) + .then(r => { + // We should not reach here, as we expect an error to be thrown. + assertEq(false, true); + }) + .catch(e => assertEq(e instanceof UniqueError, true)); +moduleLink(b); +moduleEvaluate(b) + .then(r => { + // We should not reach here, as we expect an error to be thrown. + assertEq(false, true); + }) + .catch(e => assertEq(e instanceof UniqueError, true)); + +drainJobQueue(); diff --git a/js/src/jit-test/tests/modules/bug-1498980.js b/js/src/jit-test/tests/modules/bug-1498980.js new file mode 100644 index 0000000000..f05dca6af5 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1498980.js @@ -0,0 +1,29 @@ +// |jit-test| +dbgGlobal = newGlobal({newCompartment: true}); +dbg = new dbgGlobal.Debugger; +dbg.addDebuggee(this); + +function f() { + dbg.getNewestFrame().older.eval(""); +} + +function execModule(source) { + m = parseModule(source); + moduleLink(m); + return moduleEvaluate(m); +} + +execModule("f();").then(() => { + gc(); + + execModule("throw 'foo'") + .then(r => { + // We should not reach here. + assertEq(false, true); + }) + .catch(e => { + assertEq(e, 'foo'); + }); +}) + +drainJobQueue(); diff --git a/js/src/jit-test/tests/modules/bug-1501154.js b/js/src/jit-test/tests/modules/bug-1501154.js new file mode 100644 index 0000000000..48a506db2b --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1501154.js @@ -0,0 +1,25 @@ +// Test using an empty string as a module specifier fails. +let result = null; +let error = null; +let promise = import(""); +promise.then((ns) => { + result = ns; +}).catch((e) => { + error = e; +}); + +drainJobQueue(); +assertEq(result, null); +assertEq(error instanceof Error, true); + +// Test reading a directory as a file fails. +result = null; +error = null; +try { + result = os.file.readFile("."); +} catch (e) { + error = e; +} + +assertEq(result, null); +assertEq(error instanceof Error, true); diff --git a/js/src/jit-test/tests/modules/bug-1501157.js b/js/src/jit-test/tests/modules/bug-1501157.js new file mode 100644 index 0000000000..db681c5000 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1501157.js @@ -0,0 +1,2 @@ +// |jit-test| skip-if: helperThreadCount() === 0 +offThreadCompileToStencil('import("")', {}); diff --git a/js/src/jit-test/tests/modules/bug-1502669.js b/js/src/jit-test/tests/modules/bug-1502669.js new file mode 100644 index 0000000000..4ac6e262cf --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1502669.js @@ -0,0 +1,5 @@ +// |jit-test| error: ReferenceError +var g = newGlobal({newCompartment: true}); +g.parent = this; +g.eval("new Debugger(parent).onExceptionUnwind = function () { hits++; };"); +import('')(); diff --git a/js/src/jit-test/tests/modules/bug-1503009.js b/js/src/jit-test/tests/modules/bug-1503009.js new file mode 100644 index 0000000000..f8dd8d384b --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1503009.js @@ -0,0 +1 @@ +new Function("if (0) import('')")(); diff --git a/js/src/jit-test/tests/modules/bug-1510598.js b/js/src/jit-test/tests/modules/bug-1510598.js new file mode 100644 index 0000000000..0701474f1a --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1510598.js @@ -0,0 +1,9 @@ +g = newGlobal({newCompartment: true}); +g.parent = this; +g.eval(`new Debugger(parent).onExceptionUnwind = () => null;`); +let exc = "fail"; +// Module evaluation throws so we fire the onExceptionUnwind hook. +import("javascript: throw 'foo'").catch(e => { exc = e; }); +drainJobQueue(); +assertEq(exc, undefined); + diff --git a/js/src/jit-test/tests/modules/bug-1519140.js b/js/src/jit-test/tests/modules/bug-1519140.js new file mode 100644 index 0000000000..29871bd1a4 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1519140.js @@ -0,0 +1,3 @@ +// |jit-test| --more-compartments; +fullcompartmentchecks(true); +newGlobal().eval(`import("javascript:")`).catch(() => {}); diff --git a/js/src/jit-test/tests/modules/bug-1604792.js b/js/src/jit-test/tests/modules/bug-1604792.js new file mode 100644 index 0000000000..d5f4561616 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1604792.js @@ -0,0 +1,7 @@ +var lfLogBuffer = ` + eval("function f(){}; f();"); +`; + +let lfMod = parseModule(lfLogBuffer); +moduleLink(lfMod); +moduleEvaluate(lfMod); diff --git a/js/src/jit-test/tests/modules/bug-1657066.js b/js/src/jit-test/tests/modules/bug-1657066.js new file mode 100644 index 0000000000..22c828ca68 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1657066.js @@ -0,0 +1,3 @@ +let g = newGlobal({newCompartment: true}); +new Debugger(g).onExceptionUnwind = () => null; +g.eval(`import("javascript: throw 1")`).catch(() => 0); diff --git a/js/src/jit-test/tests/modules/bug-1680878.js b/js/src/jit-test/tests/modules/bug-1680878.js new file mode 100644 index 0000000000..02975bb61b --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1680878.js @@ -0,0 +1,7 @@ +// |jit-test| error: TypeError + +r = parseModule(` + for await (var x of this) {} +`); +moduleLink(r); +moduleEvaluate(r); diff --git a/js/src/jit-test/tests/modules/bug-1681256.js b/js/src/jit-test/tests/modules/bug-1681256.js new file mode 100644 index 0000000000..f4485abd46 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1681256.js @@ -0,0 +1,20 @@ +// |jit-test| --more-compartments; +let lfCode = ` + var g = newGlobal(); + g.debuggeeGlobal = this; + g.eval("(" + function () { + dbg = new Debugger(debuggeeGlobal); + dbg.onExceptionUnwind = function (frame, exc) {}; + } + ")();"); +`; +loadFile(lfCode); +// use "await" so the module is marked as TLA +loadFile(lfCode + " await ''"); +async function loadFile(lfVarx) { + try { + try { evaluate(lfVarx); } catch(exc) {} + let lfMod = parseModule(lfVarx); + lfMomoduleLink(d); + await lfMomoduleEvaluate(d); + } catch (lfVare) {} +} diff --git a/js/src/jit-test/tests/modules/bug-1711342.js b/js/src/jit-test/tests/modules/bug-1711342.js new file mode 100644 index 0000000000..a0c6277902 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1711342.js @@ -0,0 +1,6 @@ +Object.defineProperty(__proto__, "then", { + get: function () { + x + } +}); +import("javascript:null"); diff --git a/js/src/jit-test/tests/modules/bug-1764239.js b/js/src/jit-test/tests/modules/bug-1764239.js new file mode 100644 index 0000000000..2beb2a8959 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1764239.js @@ -0,0 +1,13 @@ +let module1 = registerModule('module1', parseModule( + `import {} from "module2"; + import {} from "module3";`)); + +let module2 = registerModule('module2', parseModule( + `await 1;`)); + +let module3 = registerModule('module3', parseModule( + `throw 1;`)); + +moduleLink(module1); +moduleEvaluate(module1).catch(() => 0); +drainJobQueue(); diff --git a/js/src/jit-test/tests/modules/bug-1771090.js b/js/src/jit-test/tests/modules/bug-1771090.js new file mode 100644 index 0000000000..cb5a5a2bc6 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1771090.js @@ -0,0 +1,9 @@ +// |jit-test| skip-if: !('oomAfterAllocations' in this) + +asyncFunc1("geval0\n await ''") +async function asyncFunc1(lfVarx) { + lfMod = parseModule(lfVarx); + moduleLink(lfMod); + await moduleEvaluate(lfMod); +} +oomAfterAllocations(1); diff --git a/js/src/jit-test/tests/modules/bug-1777972.js b/js/src/jit-test/tests/modules/bug-1777972.js new file mode 100644 index 0000000000..e04214a7e1 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1777972.js @@ -0,0 +1,4 @@ +let a = parseModule(`throw new Error`); +moduleLink(a); +moduleEvaluate(a).catch(e => {}); +moduleEvaluate(a).catch(e => {}); diff --git a/js/src/jit-test/tests/modules/bug-1778439.js b/js/src/jit-test/tests/modules/bug-1778439.js new file mode 100644 index 0000000000..ac930d5055 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1778439.js @@ -0,0 +1 @@ +assertEq(parseModule("").evaluationError, undefined); diff --git a/js/src/jit-test/tests/modules/bug-1782496.js b/js/src/jit-test/tests/modules/bug-1782496.js new file mode 100644 index 0000000000..33ea725a7b --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1782496.js @@ -0,0 +1,9 @@ +// |jit-test| exitstatus: 6; allow-overrecursed + +setInterruptCallback(function() { + import("javascript:null"); + interruptIf(true); +}); + +interruptIf(true); +for (;;) {} // Wait for interrupt. diff --git a/js/src/jit-test/tests/modules/bug-1787926.js b/js/src/jit-test/tests/modules/bug-1787926.js new file mode 100644 index 0000000000..fb71014359 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1787926.js @@ -0,0 +1,16 @@ +let m = registerModule('m', parseModule(`import {} from "s";`)); +let l = registerModule('l', parseModule(`import {} from "s";`)); +let s = registerModule('s', parseModule(`await 0;`)); + +let state = "init"; + +moduleLink(m); +moduleEvaluate(m).then(() => { state = "loaded"; }); +drainJobQueue(); + +assertEq(state, "loaded"); + +import("l").then(() => { state = "complete"; }); +drainJobQueue(); + +assertEq(state, "complete"); diff --git a/js/src/jit-test/tests/modules/bug-1789412.js b/js/src/jit-test/tests/modules/bug-1789412.js new file mode 100644 index 0000000000..55a04d83e5 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1789412.js @@ -0,0 +1,12 @@ +let state = "init"; + +let m = registerModule('m', parseModule( + `import "l"; import("l").then(() => { state = "complete" });`)); + +let l = registerModule('l', parseModule( + `await(0);`)); + +moduleLink(m); +moduleEvaluate(m); +drainJobQueue(); +assertEq(state, "complete"); diff --git a/js/src/jit-test/tests/modules/bug-1790352.js b/js/src/jit-test/tests/modules/bug-1790352.js new file mode 100644 index 0000000000..c215b3e8eb --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1790352.js @@ -0,0 +1,13 @@ +let a = registerModule('a', parseModule("import 'b';")); +let b = registerModule('b', parseModule("import 'c'; await 1; throw 'error';")); +let c = registerModule('c', parseModule("import 'b';")); + +let status1; +import('a').then(() => { status1 = 'loaded' }).catch(e => { status1 = e; }); +drainJobQueue(); +assertEq(status1, 'error'); + +let status2; +import('c').then(() => { status2 = 'loaded' }).catch(e => { status2 = e; }); +drainJobQueue(); +assertEq(status2, 'error'); diff --git a/js/src/jit-test/tests/modules/bug-1795845.js b/js/src/jit-test/tests/modules/bug-1795845.js new file mode 100644 index 0000000000..e2641ee098 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1795845.js @@ -0,0 +1,3 @@ +enableShellAllocationMetadataBuilder(); +gczeal(9, 1); +parseModule(``); diff --git a/js/src/jit-test/tests/modules/bug-1802479.js b/js/src/jit-test/tests/modules/bug-1802479.js new file mode 100644 index 0000000000..c00d0e0da6 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1802479.js @@ -0,0 +1,15 @@ +// |jit-test| skip-if: !('oomTest' in this); slow + +function test(lfVarx) { + try { + oomTest(function() { + let m41 = parseModule(lfVarx); + moduleLink(m41); + moduleEvaluate(m41); + }); + } catch (lfVare) {} +} +test(` + var g93 = newGlobal({newCompartment: true}); + g93.eval("f(10);"); +`); 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 0000000000..98e6aded08 --- /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 0000000000..3f6fbeef93 --- /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 0000000000..509adb8e59 --- /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 0000000000..451da2e286 --- /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 0000000000..32df29a8b6 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1210391.js @@ -0,0 +1,7 @@ +let a = registerModule('a', parseModule("export var a = 1; export var b = 2;")); +let b = registerModule('b', parseModule("export var b = 3; export var c = 4;")); +let c = registerModule('c', parseModule("export * from 'a'; export * from 'b';")); +let d = registerModule('d', parseModule("import { a } from 'c'; a;")); +moduleLink(d); +moduleEvaluate(d); + diff --git a/js/src/jit-test/tests/modules/bug1394492.js b/js/src/jit-test/tests/modules/bug1394492.js new file mode 100644 index 0000000000..4fae8ebf9e --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1394492.js @@ -0,0 +1,6 @@ +// |jit-test| error: NaN +let m = parseModule(` + throw i => { return 5; }, m-1; +`); +moduleLink(m); +moduleEvaluate(m); diff --git a/js/src/jit-test/tests/modules/bug1394493.js b/js/src/jit-test/tests/modules/bug1394493.js new file mode 100644 index 0000000000..1fc1899602 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1394493.js @@ -0,0 +1,4 @@ +// |jit-test| error: ReferenceError + +let m = parseModule("export let r = y; y = 4;"); +getModuleEnvironmentValue(m, "r").toString() diff --git a/js/src/jit-test/tests/modules/bug1429031.js b/js/src/jit-test/tests/modules/bug1429031.js new file mode 100644 index 0000000000..b65daa081b --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1429031.js @@ -0,0 +1,16 @@ +// |jit-test| error: ReferenceError + +assertEq = function(a, b) {} +evaluate(` +let a = registerModule('a', parseModule( + 'export var a = 1;' +)); +let b = registerModule('b', parseModule( + \`import * as ns from 'a'; + export var x = ns.a + ns.b;\` +)); +moduleLink(b); +let ns = getModuleEnvironmentValue(b, "ns"); +assertEq(ns.a, 1); +while ( t.ArrayType() ) 1; +`); diff --git a/js/src/jit-test/tests/modules/bug1449153.js b/js/src/jit-test/tests/modules/bug1449153.js new file mode 100644 index 0000000000..4c321854bb --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1449153.js @@ -0,0 +1,33 @@ +// Test performing GetModuleNamespace on an errored module. + +class MyError {} + +async function assertThrowsMyError(f) +{ + let caught = false; + try { + await f(); + } catch (e) { + caught = true; + assertEq(e.constructor, MyError); + } + assertEq(caught, true); +} + +registerModule("a", parseModule(` + throw new MyError(); +`)); + +let c = registerModule("c", parseModule(` + import "a"; +`)); +moduleLink(c); +assertThrowsMyError(() => moduleEvaluate(c)); + +let b = registerModule('b', parseModule(` + import * as ns0 from 'a' +`)); +moduleLink(b); +assertThrowsMyError(() => moduleEvaluate(b)); + +drainJobQueue(); diff --git a/js/src/jit-test/tests/modules/bug1485698.js b/js/src/jit-test/tests/modules/bug1485698.js new file mode 100644 index 0000000000..36f3e53763 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1485698.js @@ -0,0 +1,9 @@ +let m = parseModule(` + function f(x,y,z) { + delete arguments[2]; + import.meta[2] + } + f(1,2,3) +`); +moduleLink(m); +moduleEvaluate(m); diff --git a/js/src/jit-test/tests/modules/bug1584034.js b/js/src/jit-test/tests/modules/bug1584034.js new file mode 100644 index 0000000000..65597effc4 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1584034.js @@ -0,0 +1 @@ +import('./asdf.js').then(() => {}, inJit) diff --git a/js/src/jit-test/tests/modules/bug1584309.js b/js/src/jit-test/tests/modules/bug1584309.js new file mode 100644 index 0000000000..3e5906ea64 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1584309.js @@ -0,0 +1 @@ +import('./asdf.js').then(() => {}, inIon) diff --git a/js/src/jit-test/tests/modules/bug1586599.js b/js/src/jit-test/tests/modules/bug1586599.js new file mode 100644 index 0000000000..612024678a --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1586599.js @@ -0,0 +1,30 @@ +let m1 = parseModule(` +function x() { + return 1; +} +function y() { + x = function() { return 2; }; +} +export { x, y }; +`); +moduleLink(m1); +moduleEvaluate(m1); + +registerModule('m1', m1); + +let m2 = parseModule(` +import {x, y} from "m1"; + +function test(expected) { + for (var i = 0; i < 2000; i++) { + if (i > 1900) { + assertEq(x(), expected); + } + } +} +test(1); +y(); +test(2); +`); +moduleLink(m2); +moduleEvaluate(m2); diff --git a/js/src/jit-test/tests/modules/bug1670236.js b/js/src/jit-test/tests/modules/bug1670236.js new file mode 100644 index 0000000000..35192c2b58 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1670236.js @@ -0,0 +1,6 @@ +// |jit-test| skip-if: !('oomTest' in this) +o0=r=/x/; +this.toString=(function() { + evaluate("",({ element:o0 })); +}) +oomTest(String.prototype.charCodeAt,{ keepFailing:true }) diff --git a/js/src/jit-test/tests/modules/bug1685992.js b/js/src/jit-test/tests/modules/bug1685992.js new file mode 100644 index 0000000000..39fd4ce7fd --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1685992.js @@ -0,0 +1,12 @@ +// |jit-test| --ion-offthread-compile=off; skip-if: !('oomTest' in this) + +function oomModule(lfMod) { + oomTest(function () { + parseModule(lfMod); + }); +} +oomModule(` + class B50 { + #priv() {} + } +`)
\ No newline at end of file diff --git a/js/src/jit-test/tests/modules/bug1699622.js b/js/src/jit-test/tests/modules/bug1699622.js new file mode 100644 index 0000000000..7b8b64b93c --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1699622.js @@ -0,0 +1,4 @@ +// |jit-test| skip-if: helperThreadCount() === 0 +offThreadCompileModuleToStencil(""); +var stencil = finishOffThreadStencil(); +instantiateModuleStencil(stencil); diff --git a/js/src/jit-test/tests/modules/bug1770048.js b/js/src/jit-test/tests/modules/bug1770048.js new file mode 100644 index 0000000000..31395cab9b --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1770048.js @@ -0,0 +1,20 @@ +const m1 = parseModule(` + export let mod = {}; + function setter(elem) { + delete Array.prototype[0]; // Delete the setter + this.push(elem); // Push the element for real + mod = elem; // Export the gathered module + } + Array.prototype.__defineSetter__(0, setter); + export const _foo = await Promise.resolve(5); +`); + +const m2 = parseModule(` + import {mod} from 'm1'; + assertEq(mod.status, undefined); +`); + +registerModule('m1', m1); +moduleLink(m2); +moduleEvaluate(m2); +drainJobQueue(); diff --git a/js/src/jit-test/tests/modules/bug1846247.js b/js/src/jit-test/tests/modules/bug1846247.js new file mode 100644 index 0000000000..4d63f0cfb3 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug1846247.js @@ -0,0 +1,7 @@ +// |jit-test| skip-if: !('oomTest' in this); allow-unhandlable-oom +ignoreUnhandledRejections(); +oomTest(() => { + gc(); + import("javascript:0"); + drainJobQueue(); +}); 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 0000000000..a7d61e9bdf --- /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 0000000000..3ca7bf123e --- /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 0000000000..c343627d51 --- /dev/null +++ b/js/src/jit-test/tests/modules/debugger-frames.js @@ -0,0 +1,83 @@ +// 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({newCompartment: true}); + +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.calleeScript, 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( +` + // Set up a module to import from. + a = registerModule('a', parseModule( + \` + export var a = 1; + export let b = 2; + export const c = 3; + export function f(x) { return x + 1; } + \`)); + moduleLink(a); + moduleEvaluate(a); + + let m = parseModule( + \` + import { a, b, c } from 'a'; + var x = 4; + let y = 5; + const z = 6; + + eval(""); + debugger; + \`); + moduleLink(m); + moduleEvaluate(m); +`); 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 0000000000..64ea177b0e --- /dev/null +++ b/js/src/jit-test/tests/modules/debugger-vars-function.js @@ -0,0 +1,30 @@ +// Test debugger access to aliased and unaliased bindings work correctly. + +load(libdir + "asserts.js"); + +var g = newGlobal({newCompartment: true}); +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 m = parseModule( + \` + var a = 1; + let b = 2; + export var c = 3; + export let d = 4; + let e = 5; + function f() { debugger; return e; } + \`); + moduleLink(m); + moduleEvaluate(m); +`); + 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 0000000000..46a9940098 --- /dev/null +++ b/js/src/jit-test/tests/modules/debugger-vars-toplevel.js @@ -0,0 +1,31 @@ +// Test debugger access to aliased and unaliased bindings work correctly. + +load(libdir + "asserts.js"); + +var g = newGlobal({newCompartment: true}); +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 m = parseModule( + \` + var a = 1; + let b = 2; + export var c = 3; + export let d = 4; + let e = 5; + function f() { return e; } + debugger; + \`); + moduleLink(m); + moduleEvaluate(m); +`); + 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 0000000000..b76c028f6f --- /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 0000000000..4b5f2d1c9d --- /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 0000000000..ef23e2afcb --- /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 0000000000..7e45ac6f37 --- /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 0000000000..fa87ba8ebd --- /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/dynamic-import-error.js b/js/src/jit-test/tests/modules/dynamic-import-error.js new file mode 100644 index 0000000000..98a6af75d0 --- /dev/null +++ b/js/src/jit-test/tests/modules/dynamic-import-error.js @@ -0,0 +1,14 @@ +// |jit-test| module + +let result = null; +let error = null; +let promise = import("nonexistent.js"); +promise.then((ns) => { + result = ns; +}).catch((e) => { + error = e; +}); + +drainJobQueue(); +assertEq(result, null); +assertEq(error instanceof Error, true); diff --git a/js/src/jit-test/tests/modules/dynamic-import-expression.js b/js/src/jit-test/tests/modules/dynamic-import-expression.js new file mode 100644 index 0000000000..2a02c774f4 --- /dev/null +++ b/js/src/jit-test/tests/modules/dynamic-import-expression.js @@ -0,0 +1,214 @@ +// |jit-test| --enable-import-attributes + +load(libdir + "match.js"); +load(libdir + "asserts.js"); + +var { Pattern, MatchError } = Match; + +program = (elts) => Pattern({ + type: "Program", + body: elts +}); +expressionStatement = (expression) => Pattern({ + type: "ExpressionStatement", + expression: expression +}); +assignmentExpression = (left, operator, right) => Pattern({ + type: "AssignmentExpression", + operator: operator, + left: left, + right: right +}); +ident = (name) => Pattern({ + type: "Identifier", + name: name +}); +importCall = (ident, args) => Pattern({ + type: "CallImport", + ident: ident, + arguments: args +}); + +objExpr = (elts) => Pattern({ + type: "ObjectExpression", + properties: elts +}); +property = (key, value) => Pattern({ + type: "Property", + kind: "init", + key: key, + value: value, +}); +lit = (val) => Pattern({ + type: "Literal", + value: val +}); +callExpression = (callee, args) => Pattern({ + type: "CallExpression", + callee: callee, + arguments: args +}); + +function parseAsClassicScript(source) +{ + return Reflect.parse(source); +} + +function parseAsModuleScript(source) +{ + return Reflect.parse(source, {target: "module"}); +} + +for (let parse of [parseAsModuleScript, parseAsClassicScript]) { + program([ + expressionStatement( + importCall( + ident("import"), + [ + ident("foo") + ] + ) + ) + ]).assert(parse("import(foo);")); + + program([ + expressionStatement( + assignmentExpression( + ident("x"), + "=", + importCall( + ident("import"), + [ + ident("foo") + ] + ) + ) + ) + ]).assert(parse("x = import(foo);")); + + if (getRealmConfiguration("importAttributes")) { + program([ + expressionStatement( + importCall( + ident("import"), + [ + ident("foo"), + objExpr([]) + ] + ) + ) + ]).assert(parse("import(foo, {});")); + + program([ + expressionStatement( + importCall( + ident("import"), + + [ + ident("foo"), + objExpr([ + property( + ident("assert"), + objExpr([] + )) + ]) + ] + + ) + ) + ]).assert(parse("import(foo, { assert: {} });")); + + program([ + expressionStatement( + importCall( + ident("import"), + [ + ident("foo"), + objExpr([ + property( + ident("assert"), + objExpr([ + property( + ident("type"), + lit('json') + ) + ] + )) + ]) + ] + ) + ) + ]).assert(parse("import(foo, { assert: { type: 'json' } });")); + + program([ + expressionStatement( + importCall( + ident("import"), + [ + ident("foo"), + objExpr([ + property( + ident("assert"), + objExpr([ + property( + ident("type"), + lit('json') + ), + property( + ident("foo"), + lit('bar') + ) + ] + )) + ]) + ] + ) + ) + ]).assert(parse("import(foo, { assert: { type: 'json', foo: 'bar' } });")); + + program([ + expressionStatement( + importCall( + ident("import"), + [ + ident("foo"), + objExpr([ + property( + ident("assert"), + objExpr([ + property( + ident("type"), + callExpression(ident('getType'), []) + ) + ] + )) + ]) + ] + ) + ) + ]).assert(parse("import(foo, { assert: { type: getType() } });")); + } +} + +function assertParseThrowsSyntaxError(source) +{ + assertThrowsInstanceOf(() => parseAsClassicScript(source), SyntaxError); + assertThrowsInstanceOf(() => parseAsModuleScript(source), SyntaxError); +} + +assertParseThrowsSyntaxError("import"); +assertParseThrowsSyntaxError("import("); +assertParseThrowsSyntaxError("import(1,"); +assertParseThrowsSyntaxError("x = import"); +assertParseThrowsSyntaxError("x = import("); +assertParseThrowsSyntaxError("x = import(1,"); +assertParseThrowsSyntaxError("x = import(1, 2"); + +if (!getRealmConfiguration("importAttributes")) { + assertParseThrowsSyntaxError("import(1, 2"); + assertParseThrowsSyntaxError("import(1, 2)"); + assertParseThrowsSyntaxError("x = import(1, 2)"); +} +else { + assertParseThrowsSyntaxError("import(1, 2, 3)"); +} diff --git a/js/src/jit-test/tests/modules/dynamic-import-ion.js b/js/src/jit-test/tests/modules/dynamic-import-ion.js new file mode 100644 index 0000000000..9c8f5e0e40 --- /dev/null +++ b/js/src/jit-test/tests/modules/dynamic-import-ion.js @@ -0,0 +1,16 @@ +// Even with --ion-eager, this needs to be run twice before it executes the +// ion-compiled version. +for (let i = 0; i < 2; i++) { + let result = null; + let error = null; + let promise = import("../../modules/module1.js"); + promise.then((ns) => { + result = ns; + }).catch((e) => { + error = e; + }); + + drainJobQueue(); + assertEq(error, null); + assertEq(result.a, 1); +} diff --git a/js/src/jit-test/tests/modules/dynamic-import-lazy.js b/js/src/jit-test/tests/modules/dynamic-import-lazy.js new file mode 100644 index 0000000000..ccbf90989d --- /dev/null +++ b/js/src/jit-test/tests/modules/dynamic-import-lazy.js @@ -0,0 +1,4 @@ +function lazyilyParsedFunction() +{ + return import("/module1.js"); +} diff --git a/js/src/jit-test/tests/modules/dynamic-import-module.js b/js/src/jit-test/tests/modules/dynamic-import-module.js new file mode 100644 index 0000000000..3c004258a3 --- /dev/null +++ b/js/src/jit-test/tests/modules/dynamic-import-module.js @@ -0,0 +1,39 @@ +// |jit-test| module + +function testImport(path, name, value) { + let result = null; + let error = null; + let promise = import(path); + promise.then((ns) => { + result = ns; + }).catch((e) => { + error = e; + }); + + drainJobQueue(); + assertEq(error, null); + assertEq(result[name], value); +} + +// Resolved via module load path. +testImport("module1.js", "a", 1); + +// Relative path resolved relative to this script. +testImport("../../modules/module1a.js", "a", 2); + +// Import inside function. +function f() { + testImport("../../modules/module2.js", "b", 2); +} +f(); + +// Import inside direct eval. +eval(`testImport("../../modules/module3.js", "c", 3)`); + +// Import inside indirect eval. +const indirect = eval; +const defineTestFunc = testImport.toString(); +indirect(defineTestFunc + `testImport("../../modules/module3.js");`); + +// Import inside dynamic function. +Function(defineTestFunc + `testImport("../../modules/module3.js");`)(); diff --git a/js/src/jit-test/tests/modules/dynamic-import-oom.js b/js/src/jit-test/tests/modules/dynamic-import-oom.js new file mode 100644 index 0000000000..9682c7560a --- /dev/null +++ b/js/src/jit-test/tests/modules/dynamic-import-oom.js @@ -0,0 +1,9 @@ +// |jit-test| skip-if: !('oomTest' in this); --ion-offthread-compile=off +// +// Note: without --ion-offthread-compile=off this test takes a long time and +// may timeout on some platforms. See bug 1507721. + +ignoreUnhandledRejections(); + +oomTest(() => import("module1.js")); +oomTest(() => import("cyclicImport1.js")); diff --git a/js/src/jit-test/tests/modules/dynamic-import-script.js b/js/src/jit-test/tests/modules/dynamic-import-script.js new file mode 100644 index 0000000000..e6986a42ec --- /dev/null +++ b/js/src/jit-test/tests/modules/dynamic-import-script.js @@ -0,0 +1,45 @@ +function testImport(path, name, value) { + let result = null; + let error = null; + let promise = import(path); + promise.then((ns) => { + result = ns; + }).catch((e) => { + error = e; + }); + + drainJobQueue(); + assertEq(error, null); + assertEq(result[name], value); +} + +// Resolved via module load path. +testImport("module1.js", "a", 1); + +// Relative path resolved relative to this script. +testImport("../../modules/module1a.js", "a", 2); + +// Import inside function. +function f() { + testImport("../../modules/module2.js", "b", 2); +} +f(); + +// Import inside eval. +eval(`testImport("../../modules/module3.js", "c", 3)`); + +// Import inside indirect eval. +const indirect = eval; +const defineTestFunc = testImport.toString(); +indirect(defineTestFunc + `testImport("../../modules/module3.js");`); + +// Import inside dynamic function. +Function(defineTestFunc + `testImport("../../modules/module3.js");`)(); + +// Import in eval in promise handler. +let ran = false; +Promise + .resolve(`import("../../modules/module3.js").then(() => { ran = true; })`) + .then(eval) +drainJobQueue(); +assertEq(ran, true); 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 0000000000..5587670735 --- /dev/null +++ b/js/src/jit-test/tests/modules/eval-module-oom.js @@ -0,0 +1,23 @@ +// |jit-test| skip-if: !('oomTest' in this) + +// OOM tests for module parsing. + +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 = registerModule('a', parseModule(sa)); + let b = registerModule('b', parseModule(sb)); + moduleLink(b); + assertEq(moduleEvaluate(b), 42); +}); diff --git a/js/src/jit-test/tests/modules/export-circular-nonexisting-binding.js b/js/src/jit-test/tests/modules/export-circular-nonexisting-binding.js new file mode 100644 index 0000000000..387c7c369a --- /dev/null +++ b/js/src/jit-test/tests/modules/export-circular-nonexisting-binding.js @@ -0,0 +1,3 @@ +// |jit-test| module; error:SyntaxError + +import "export-circular-nonexisting-binding-1.js"; 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 0000000000..833f4d4c50 --- /dev/null +++ b/js/src/jit-test/tests/modules/export-declaration.js @@ -0,0 +1,569 @@ +// |jit-test| --enable-import-assertions + +load(libdir + "match.js"); +load(libdir + "asserts.js"); + +var { Pattern, MatchError } = Match; + +program = (elts) => Pattern({ + type: "Program", + body: elts +}) +exportDeclaration = (declaration, specifiers, moduleRequest, isDefault) => Pattern({ + type: "ExportDeclaration", + declaration: declaration, + specifiers: specifiers, + moduleRequest: moduleRequest, + isDefault: isDefault +}); +moduleRequest = (specifier, attributes) => Pattern({ + type: "ModuleRequest", + source: specifier, + attributes: attributes +}); +importAttribute = (key, value) => Pattern({ + type: "ImportAttribute", + key: key, + value : value +}); +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") + ) + ], + moduleRequest( + lit("b"), + [], + ), + false + ) +]).assert(parseAsModule("export { a } from 'b'")); + +program([ + exportDeclaration( + null, + [ + exportBatchSpecifier() + ], + moduleRequest( + 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")); + +if (getRealmConfiguration("importAttributes")) { + program([ + exportDeclaration( + null, + [ + exportSpecifier( + ident("a"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [ + importAttribute(ident('type'), lit('js')), + ] + ), + false + ) + ]).assert(parseAsModule("export { a } from 'b' assert { type: 'js' } ")); + + program([ + exportDeclaration( + null, + [ + exportSpecifier( + ident("a"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [ + importAttribute(ident('foo'), lit('bar')), + ], + ), + false + ) + ]).assert(parseAsModule("export { a } from 'b' assert { foo: 'bar', } ")); + + program([ + exportDeclaration( + null, + [ + exportSpecifier( + ident("a"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [ + importAttribute(ident('type'), lit('js')), + importAttribute(ident('foo'), lit('bar')), + importAttribute(ident('test'), lit('123')), + ] + ), + false + ) + ]).assert(parseAsModule("export { a } from 'b' assert { type: 'js', foo: 'bar', 'test': '123' } ")); + + assertThrowsInstanceOf(function () { + parseAsModule("export { a } from 'b' assert { type: type }"); + }, SyntaxError); +} + +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, 1); +assertEq(loc.start.line, 1); +assertEq(loc.end.column, 27); + +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); + +program([ + exportDeclaration( + null, + [ + exportSpecifier( + ident("true"), + ident("true") + ), + ], + moduleRequest( + lit("b"), + [], + ), + false + ) +]).assert(parseAsModule("export { true } from 'b'")); + +program([ + exportDeclaration( + null, + [ + exportSpecifier( + ident("true"), + ident("name") + ), + ], + moduleRequest( + lit("b"), + [], + ), + false + ) +]).assert(parseAsModule("export { true as name } from 'b'")); + +assertThrowsInstanceOf(function() { + parseAsModule("export { true }"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export { true as name }"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export { static }"); +}, SyntaxError); + +assertThrowsInstanceOf(function() { + parseAsModule("export { static as name }"); +}, SyntaxError); + +assertThrowsInstanceOf(function () { + parseAsModule("export { name } 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-destructuring.js b/js/src/jit-test/tests/modules/export-destructuring.js new file mode 100644 index 0000000000..8272097042 --- /dev/null +++ b/js/src/jit-test/tests/modules/export-destructuring.js @@ -0,0 +1,104 @@ +function assertArrayEq(value, expected) +{ + assertEq(value instanceof Array, true); + assertEq(value.length, expected.length); + for (let i = 0; i < value.length; i++) + assertEq(value[i], expected[i]); +} + +registerModule('a', parseModule(` + export const [] = []; + export const [a=0] = []; + export const [b] = [1]; + export const [c, d, e] = [2, 3, 4]; + export const [, f, g] = [5, 6, 7]; + export const [h,, i] = [8, 9, 10]; + export const [,, j] = [11, 12, 13]; + export const [...k] = [14, 15, 16]; + export const [l, ...m] = [17, 18, 19]; + export const [,, ...n] = [20, 21, 22]; +`)); + +m = parseModule(` + import * as a from 'a'; + + assertEq(a.a, 0); + assertEq(a.b, 1); + assertEq(a.c, 2); + assertEq(a.d, 3); + assertEq(a.e, 4); + assertEq(a.f, 6); + assertEq(a.g, 7); + assertEq(a.h, 8); + assertEq(a.i, 10); + assertEq(a.j, 13); + assertArrayEq(a.k, [14, 15, 16]); + assertEq(a.l, 17); + assertArrayEq(a.m, [18, 19]); + assertArrayEq(a.n, [22]); +`); + +moduleLink(m); +moduleEvaluate(m); + +registerModule('o', parseModule(` + export const {} = {}; + export const {x: a=0} = {}; + export const {x: b=0} = {x: 1}; + export const {c, d, e} = {c: 2, d: 3, e: 4}; + export const {x: f} = {x: 5}; + export const {g} = {}; + export const {h=6} = {}; +`)); + +m = parseModule(` + import * as o from 'o'; + + assertEq(o.a, 0); + assertEq(o.b, 1); + assertEq(o.c, 2); + assertEq(o.d, 3); + assertEq(o.e, 4); + assertEq(o.f, 5); + assertEq(o.g, undefined); + assertEq(o.h, 6); +`); + +moduleLink(m); +moduleEvaluate(m); + +registerModule('ao', parseModule(` + export const [{x: a}, {x: b}] = [{x: 1}, {x: 2}]; + export const [{c}, {d}] = [{c: 3}, {d: 4}]; + export const [,, {e}, ...f] = [5, 6, {e: 7}, 8, 9]; + + export const {x: [g, h, i]} = {x: [10, 11, 12]}; + + export const [[], [...j], [, k, l]] = [[], [13, 14], [15, 16, 17]]; + + export const {x: {m, n, o=20}, y: {z: p}} = {x: {m: 18, n: 19}, y: {z: 21}}; +`)); + +m = parseModule(` + import * as ao from 'ao'; + + assertEq(ao.a, 1); + assertEq(ao.b, 2); + assertEq(ao.c, 3); + assertEq(ao.d, 4); + assertEq(ao.e, 7); + assertArrayEq(ao.f, [8, 9]); + assertEq(ao.g, 10); + assertEq(ao.h, 11); + assertEq(ao.i, 12); + assertArrayEq(ao.j, [13, 14]); + assertEq(ao.k, 16); + assertEq(ao.l, 17); + assertEq(ao.m, 18); + assertEq(ao.n, 19); + assertEq(ao.o, 20); + assertEq(ao.p, 21); +`); + +moduleLink(m); +moduleEvaluate(m); 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 0000000000..bb0c50a69e --- /dev/null +++ b/js/src/jit-test/tests/modules/export-entries.js @@ -0,0 +1,130 @@ +// Test localExportEntries property + +function testObjectContents(actual, expected) { + for (var property in expected) { + if(actual[property] instanceof Object) { + testObjectContents(actual[property], expected[property]); + } + else { + assertEq(actual[property], expected[property]); + } + } +} + +function testArrayContents(actual, expected) { + assertEq(actual.length, expected.length); + for (var i = 0; i < actual.length; i++) { + testObjectContents(actual[i], expected[i]); + } +} + +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: {specifier:'mod'}, importName: 'x', localName: null}]); + +testIndirectExportEntries( + 'export {v as x} from "mod";', + [{exportName: 'x', moduleRequest: {specifier:'mod'}, importName: 'v', localName: null}]); + +testIndirectExportEntries( + 'export * from "mod";', + []); + +testIndirectExportEntries( + 'import {v as x} from "mod"; export {x as y};', + [{exportName: 'y', moduleRequest: {specifier:'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: {specifier:'mod'}, importName: null, localName: null}]); diff --git a/js/src/jit-test/tests/modules/export-ns-from.js b/js/src/jit-test/tests/modules/export-ns-from.js new file mode 100644 index 0000000000..2e79d77f42 --- /dev/null +++ b/js/src/jit-test/tests/modules/export-ns-from.js @@ -0,0 +1,10 @@ +// |jit-test| module + +import { ns } from "export-ns.js"; + +load(libdir + 'asserts.js'); + +assertEq(isProxy(ns), true); +assertEq(ns.a, 1); +assertThrowsInstanceOf(function() { eval("delete ns"); }, SyntaxError); +assertThrowsInstanceOf(function() { ns = null; }, TypeError); diff --git a/js/src/jit-test/tests/modules/export-star-cannot-rescue-missing-export.js b/js/src/jit-test/tests/modules/export-star-cannot-rescue-missing-export.js new file mode 100644 index 0000000000..f87829d89b --- /dev/null +++ b/js/src/jit-test/tests/modules/export-star-cannot-rescue-missing-export.js @@ -0,0 +1,4 @@ +// |jit-test| module; error:SyntaxError + +export { a } from "empty.js"; +export* from "module1.js"; diff --git a/js/src/jit-test/tests/modules/export-star-circular-dependencies.js b/js/src/jit-test/tests/modules/export-star-circular-dependencies.js new file mode 100644 index 0000000000..9aa612f087 --- /dev/null +++ b/js/src/jit-test/tests/modules/export-star-circular-dependencies.js @@ -0,0 +1,6 @@ +// |jit-test| module + +import { x, y } from "export-star-circular-1.js"; + +assertEq(x, "pass"); +assertEq(y, "pass"); diff --git a/js/src/jit-test/tests/modules/function-redeclaration.js b/js/src/jit-test/tests/modules/function-redeclaration.js new file mode 100644 index 0000000000..b84704641d --- /dev/null +++ b/js/src/jit-test/tests/modules/function-redeclaration.js @@ -0,0 +1,94 @@ +load(libdir + "asserts.js"); + +var functionDeclarations = [ + "function f(){}", + "function* f(){}", + "async function f(){}", +]; + +var varDeclarations = [ + "var f", + "{ var f; }", + "for (var f in null);", + "for (var f of null);", + "for (var f; ;);", +]; + +var lexicalDeclarations = [ + "let f;", + "const f = 0;", + "class f {};", +]; + +var imports = [ + "import f from '';", + "import f, {} from '';", + "import d, {f} from '';", + "import d, {f as f} from '';", + "import d, {foo as f} from '';", + "import f, * as d from '';", + "import d, * as f from '';", + "import {f} from '';", + "import {f as f} from '';", + "import {foo as f} from '';", + "import* as f from '';", +]; + +var exports = [ + "export var f;", + ...functionDeclarations.map(fn => `export ${fn};`), + ...lexicalDeclarations.map(ld => `export ${ld};`), + ...functionDeclarations.map(fn => `export default ${fn};`), + "export default class f {};", +]; + +var redeclarations = [ + ...functionDeclarations, + ...varDeclarations, + ...lexicalDeclarations, + ...imports, + ...exports, +]; + +var noredeclarations = [ + ...functionDeclarations.map(fn => `{ ${fn} }`), + ...lexicalDeclarations.map(ld => `{ ${ld} }`), + ...["let", "const"].map(ld => `for (${ld} f in null);`), + ...["let", "const"].map(ld => `for (${ld} f of null);`), + ...["let", "const"].map(ld => `for (${ld} f = 0; ;);`), + "export {f};", + "export {f as f};", + "export {foo as f}; var foo;", + "export {f} from '';", + "export {f as f} from '';", + "export {foo as f} from '';", +]; + +for (var decl of functionDeclarations) { + for (var redecl of redeclarations) { + assertThrowsInstanceOf(() => { + parseModule(` + ${decl} + ${redecl} + `); + }, SyntaxError); + + assertThrowsInstanceOf(() => { + parseModule(` + ${redecl} + ${decl} + `); + }, SyntaxError); + } + + for (var redecl of noredeclarations) { + parseModule(` + ${decl} + ${redecl} + `); + parseModule(` + ${redecl} + ${decl} + `); + } +} 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 0000000000..9b4b36bf42 --- /dev/null +++ b/js/src/jit-test/tests/modules/global-scope.js @@ -0,0 +1,35 @@ +// Test interaction with global object and global lexical scope. + +function evalModuleAndCheck(source, expected) { + let m = parseModule(source); + moduleLink(m); + moduleEvaluate(m); + assertEq(getModuleEnvironmentValue(m, "r"), expected); +} + +var x = 1; +evalModuleAndCheck("export let r = x; x = 2;", 1); +assertEq(x, 2); + +let y = 3; +evalModuleAndCheck("export let r = y; y = 4;", 3); +assertEq(y, 4); + +if (helperThreadCount() == 0) + quit(); + +function offThreadEvalModuleAndCheck(source, expected) { + offThreadCompileModuleToStencil(source); + let stencil = finishOffThreadStencil(); + let m = instantiateModuleStencil(stencil); + print("compiled"); + moduleLink(m); + moduleEvaluate(m); + assertEq(getModuleEnvironmentValue(m, "r"), expected); +} + +offThreadEvalModuleAndCheck("export let r = x; x = 5;", 2); +assertEq(x, 5); + +offThreadEvalModuleAndCheck("export let r = y; y = 6;", 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 0000000000..976386bc5b --- /dev/null +++ b/js/src/jit-test/tests/modules/import-declaration.js @@ -0,0 +1,523 @@ +// |jit-test| --enable-import-assertions + +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, + moduleRequest: source +}); +importSpecifier = (id, name) => Pattern({ + type: "ImportSpecifier", + id: id, + name: name +}); +moduleRequest = (specifier, attributes) => Pattern({ + type: "ModuleRequest", + source: specifier, + attributes: attributes +}); +importAttribute = (key, value) => Pattern({ + type: "ImportAttribute", + key: key, + value : value +}); +importNamespaceSpecifier = (name) => Pattern({ + type: "ImportNamespaceSpecifier", + 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") + ) + ], + moduleRequest( + lit("b"), + [] + ) + ) +]).assert(parseAsModule("import a from 'b'")); + +program([ + importDeclaration( + [ + importNamespaceSpecifier( + ident("a") + ) + ], + moduleRequest( + lit("b"), + [] + ) + ) +]).assert(parseAsModule("import * as a from 'b'")); + +program([ + importDeclaration( + [], + moduleRequest( + lit("a"), + [] + ) + ) +]).assert(parseAsModule("import {} from 'a'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [] + ) + ) +]).assert(parseAsModule("import { a } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [] + ) + ) +]).assert(parseAsModule("import { a, } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("b") + ) + ], + moduleRequest( + lit("c"), + [] + ) + ) +]).assert(parseAsModule("import { a as b } from 'c'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("as"), + ident("as") + ) + ], + moduleRequest( + lit("a"), + [] + ) + ) +]).assert(parseAsModule("import { as as as } from 'a'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("a") + ), + importNamespaceSpecifier( + ident("b") + ) + ], + moduleRequest( + lit("c"), + [] + ) + ) +]).assert(parseAsModule("import a, * as b from 'c'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("d") + ) + ], + moduleRequest( + lit("a"), + [] + ) + ) +]).assert(parseAsModule("import d, {} from 'a'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("d") + ), + importSpecifier( + ident("a"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [] + ) + ) +]).assert(parseAsModule("import d, { a } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("d") + ), + importSpecifier( + ident("a"), + ident("b") + ) + ], + moduleRequest( + 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") + ), + ], + moduleRequest( + 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") + ), + ], + moduleRequest( + lit("e"), + [] + ) + ) +]).assert(parseAsModule("import d, { a as b, c as f } from 'e'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("true"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [] + ) + ) +]).assert(parseAsModule("import { true as a } from 'b'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("a") + ), + importSpecifier( + ident("b"), + ident("b") + ), + ], + moduleRequest( + lit("c"), + [] + ) + ) +]).assert(parseAsModule("import { a, b } from 'c'")); + +program([ + importDeclaration( + [ + importSpecifier( + ident("a"), + ident("b") + ), + importSpecifier( + ident("c"), + ident("d") + ), + ], + moduleRequest( + lit("e"), + [] + ) + ) +]).assert(parseAsModule("import { a as b, c as d } from 'e'")); + +program([ + importDeclaration( + [], + moduleRequest( + lit("a"), + [] + ) + ) +]).assert(parseAsModule("import 'a'")); + +if (getRealmConfiguration("importAttributes")) { + program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [] + ) + ) + ]).assert(parseAsModule("import a from 'b' assert {}")); + + program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [ + importAttribute(ident('type'), lit('js')), + ] + ) + ) + ]).assert(parseAsModule("import a from 'b' assert { type: 'js' }")); + + program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [ + importAttribute(ident('foo'), lit('bar')), + ] + ) + ) + ]).assert(parseAsModule("import a from 'b' assert { foo: 'bar' }")); + + program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [ + importAttribute(ident('foo'), lit('bar')), + ] + ) + ) + ]).assert(parseAsModule(`import a from 'b' with { foo: 'bar' }`)); + + // `assert` has NLTH but `with` doesn't + program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [ + importAttribute(ident('foo'), lit('bar')), + ] + ) + ) + ]).assert(parseAsModule(`import a from 'b' + with { foo: 'bar' }`)); + + program([ + importDeclaration( + [ + importSpecifier( + ident("default"), + ident("a") + ) + ], + moduleRequest( + lit("b"), + [ + importAttribute(ident('type'), lit('js')), + importAttribute(ident('foo'), lit('bar')), + ] + ) + ) + ]).assert(parseAsModule("import a from 'b' assert { type: 'js', foo: 'bar' }")); + + assertThrowsInstanceOf(function () { + parseAsModule("import a from 'b' assert { type: type }"); + }, SyntaxError); + + assertThrowsInstanceOf(function () { + // No newline allowed as assert. + parseAsModule(`import foo from "foo" + assert {type: 'js' }`); + }, SyntaxError); +} + +var loc = parseAsModule("import { a as b } from 'c'", { + loc: true +}).body[0].loc; + +assertEq(loc.start.line, 1); +assertEq(loc.start.column, 1); +assertEq(loc.start.line, 1); +assertEq(loc.end.column, 27); + +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-async-asi.js b/js/src/jit-test/tests/modules/import-default-async-asi.js new file mode 100644 index 0000000000..96a4ea155f --- /dev/null +++ b/js/src/jit-test/tests/modules/import-default-async-asi.js @@ -0,0 +1,7 @@ +// |jit-test| module + +import v from "export-default-async-asi.js"; + +assertEq(typeof v, "function"); +assertEq(v.name, "async"); +assertEq(v(), 17); diff --git a/js/src/jit-test/tests/modules/import-default-async-regexpy.js b/js/src/jit-test/tests/modules/import-default-async-regexpy.js new file mode 100644 index 0000000000..10a769cf2c --- /dev/null +++ b/js/src/jit-test/tests/modules/import-default-async-regexpy.js @@ -0,0 +1,5 @@ +// |jit-test| module + +import v from "export-default-async-regexpy.js"; + +assertEq(v, 7); 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 0000000000..ff87649ac6 --- /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 0000000000..95e962448f --- /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 0000000000..e20d4e119b --- /dev/null +++ b/js/src/jit-test/tests/modules/import-entries.js @@ -0,0 +1,87 @@ +// |jit-test| --enable-import-assertions + +// Test importEntries property + +function assertionEq(actual, expected) { + var actualAssertions = actual['assertions']; + var expectedAssertions = expected['assertions']; + + if(actualAssertions === null) { + return expectedAssertions === actualAssertions + } + + if(actualAssertions.length !== expectedAssertions.length) { + return false; + } + + for (var i = 0; i < expected.length; i++) { + if(expected[i].type !== actual[i].type) { + return false; + } + } + + return true; +} + +function importEntryEq(a, b) { + var r1 = a['moduleRequest']['specifier'] === b['moduleRequest']['specifier'] && + a['importName'] === b['importName'] && + a['localName'] === b['localName']; + + return r1 && assertionEq(a['moduleRequest'], b['moduleRequest']); +} + +function findImportEntry(array, target) +{ + for (let i = 0; i < array.length; i++) { + if (importEntryEq(array[i], target)) + return i; + } + return -1; +} + +function testImportEntries(source, expected) { + var module = parseModule(source); + var actual = module.importEntries.slice(0); + assertEq(actual.length, expected.length); + for (var i = 0; i < expected.length; i++) { + let index = findImportEntry(actual, expected[i]); + assertEq(index >= 0, true); + actual.splice(index, 1); + } +} + +testImportEntries('', []); + +testImportEntries('import v from "mod";', + [{moduleRequest: {specifier: 'mod', assertions: null}, importName: 'default', localName: 'v'}]); + +testImportEntries('import * as ns from "mod";', + [{moduleRequest: {specifier: 'mod', assertions: null}, importName: null, localName: 'ns'}]); + +testImportEntries('import {x} from "mod";', + [{moduleRequest: {specifier: 'mod', assertions: null}, importName: 'x', localName: 'x'}]); + +testImportEntries('import {x as v} from "mod";', + [{moduleRequest: {specifier: 'mod', assertions: null}, importName: 'x', localName: 'v'}]); + +testImportEntries('import "mod";', + []); + +testImportEntries('import {x} from "a"; import {y} from "b";', + [{moduleRequest: {specifier: 'a', assertions: null}, importName: 'x', localName: 'x'}, + {moduleRequest: {specifier: 'b', assertions: null}, importName: 'y', localName: 'y'}]); + +if (getRealmConfiguration("importAttributes")) { + testImportEntries('import v from "mod" assert {};', + [{moduleRequest: {specifier: 'mod', assertions: null}, importName: 'default', localName: 'v'}]); + + testImportEntries('import v from "mod" assert { type: "js"};', + [{moduleRequest: {specifier: 'mod', assertions: [{ type: 'js'}]}, importName: 'default', localName: 'v'}]); + + testImportEntries('import {x} from "mod" assert { type: "js"};', + [{moduleRequest: {specifier: 'mod', assertions: [{ type: 'js'}]}, importName: 'x', localName: 'x'}]); + + testImportEntries('import {x as v} from "mod" assert { type: "js"};', + [{moduleRequest: {specifier: 'mod', assertions: [{ type: 'js'}]}, importName: 'x', localName: 'v'}]); +} 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 0000000000..cddacb1428 --- /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-meta-expression.js b/js/src/jit-test/tests/modules/import-meta-expression.js new file mode 100644 index 0000000000..e7562afaed --- /dev/null +++ b/js/src/jit-test/tests/modules/import-meta-expression.js @@ -0,0 +1,91 @@ +load(libdir + "match.js"); +load(libdir + "asserts.js"); + +var { Pattern, MatchError } = Match; + +program = (elts) => Pattern({ + type: "Program", + body: elts +}); +expressionStatement = (expression) => Pattern({ + type: "ExpressionStatement", + expression: expression +}); +assignmentExpression = (left, operator, right) => Pattern({ + type: "AssignmentExpression", + operator: operator, + left: left, + right: right +}); +ident = (name) => Pattern({ + type: "Identifier", + name: name +}); +metaProperty = (meta, property) => Pattern({ + type: "MetaProperty", + meta: meta, + property: property +}); +memberExpression = (object, property) => Pattern({ + type: "MemberExpression", + object: object, + property: property +}); + +function parseAsModule(source) +{ + return Reflect.parse(source, {target: "module"}); +} + +program([ + expressionStatement( + metaProperty( + ident("import"), + ident("meta") + ) + ) +]).assert(parseAsModule("import.meta;")); + +program([ + expressionStatement( + assignmentExpression( + ident("x"), + "=", + metaProperty( + ident("import"), + ident("meta") + ) + ) + ) +]).assert(parseAsModule("x = import.meta;")); + +program([ + expressionStatement( + assignmentExpression( + memberExpression( + metaProperty( + ident("import"), + ident("meta") + ), + ident("foo") + ), + "=", + ident("x"), + ) + ) +]).assert(parseAsModule("import.meta.foo = x;")); + +function assertModuleParseThrowsSyntaxError(source) +{ + assertThrowsInstanceOf(() => parseAsModule(source), SyntaxError); +} + +assertModuleParseThrowsSyntaxError("import"); +assertModuleParseThrowsSyntaxError("import."); +assertModuleParseThrowsSyntaxError("import.met"); +assertModuleParseThrowsSyntaxError("import.metaa"); +assertModuleParseThrowsSyntaxError("x = import"); +assertModuleParseThrowsSyntaxError("x = import."); +assertModuleParseThrowsSyntaxError("x = import.met"); +assertModuleParseThrowsSyntaxError("x = import.metaa"); +assertModuleParseThrowsSyntaxError("import.meta = x"); diff --git a/js/src/jit-test/tests/modules/import-meta-oom.js b/js/src/jit-test/tests/modules/import-meta-oom.js new file mode 100644 index 0000000000..168f1102a1 --- /dev/null +++ b/js/src/jit-test/tests/modules/import-meta-oom.js @@ -0,0 +1,3 @@ +// |jit-test| module; skip-if: !('oomTest' in this) + +oomTest(() => import.meta); diff --git a/js/src/jit-test/tests/modules/import-meta.js b/js/src/jit-test/tests/modules/import-meta.js new file mode 100644 index 0000000000..98697fa2e1 --- /dev/null +++ b/js/src/jit-test/tests/modules/import-meta.js @@ -0,0 +1,67 @@ +// |jit-test| module + +// import.meta is an object. +assertEq(typeof import.meta, "object"); +assertEq(import.meta !== null, true); + +// import.meta always returns the same object. +let obj = import.meta; +assertEq(import.meta, obj); + +// Test calling from lazily compile function. +function get() { + return import.meta; +} +assertEq(get(), import.meta); + +// import.meta.url: This property will contain the module script's base URL, +// serialized. + +assertEq("url" in import.meta, true); +assertEq(import.meta.url.endsWith("import-meta.js"), true); + +assertEq("resolve" in import.meta, true); + +assertEq(import.meta.resolve("./x"), + import.meta.url.replace("import-meta.js", "x")); + +import getOtherMetaObject from "exportImportMeta.js"; + +let otherImportMeta = getOtherMetaObject(); +assertEq(otherImportMeta.url.endsWith("exportImportMeta.js"), true); + +// By default the import.meta object will be extensible, and its properties will +// be writable, configurable, and enumerable. + +assertEq(Object.isExtensible(import.meta), true); + +for (const name of Reflect.ownKeys(import.meta)) { + const desc = Object.getOwnPropertyDescriptor(import.meta, name); + assertEq(desc.writable, true); + assertEq(desc.enumerable, true); + assertEq(desc.configurable, true); + assertEq(desc.value, import.meta[name]); +} + +// The import.meta object's prototype is null. +assertEq(Object.getPrototypeOf(import.meta), null); + +import.meta.url = 0; +assertEq(import.meta.url, 0); + +import.meta.newProp = 42; +assertEq(import.meta.newProp, 42); + +let found = new Set(Reflect.ownKeys(import.meta)); + +assertEq(found.size, 3); +assertEq(found.has("url"), true); +assertEq(found.has("newProp"), true); +assertEq(found.has("resolve"), true); + +delete import.meta.url; +delete import.meta.newProp; +delete import.meta.resolve; + +found = new Set(Reflect.ownKeys(import.meta)); +assertEq(found.size, 0); 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 0000000000..c6c86090bf --- /dev/null +++ b/js/src/jit-test/tests/modules/import-namespace.js @@ -0,0 +1,114 @@ +// |jit-test| +// Test importing module namespaces + +"use strict"; + +load(libdir + "asserts.js"); +load(libdir + "iteration.js"); + +function parseAndEvaluate(source) { + let m = parseModule(source); + moduleLink(m); + return moduleEvaluate(m); +} + +function testHasNames(names, expected) { + assertEq(names.length, expected.length); + expected.forEach(function(name) { + assertEq(names.includes(name), true); + }); +} + +function testEqualArrays(actual, expected) { + assertEq(Array.isArray(actual), true); + assertEq(Array.isArray(expected), true); + assertEq(actual.length, expected.length); + for (let i = 0; i < expected.length; i++) { + assertEq(actual[i], expected[i]); + } +} + +let a = registerModule('a', parseModule( + `// Reflection methods should return these exports alphabetically sorted. + export var b = 2; + export var a = 1;` +)); + +let b = registerModule('b', parseModule( + `import * as ns from 'a'; + export { ns }; + export var x = ns.a + ns.b;` +)); + +moduleLink(b); +moduleEvaluate(b); +testHasNames(getModuleEnvironmentNames(b), ["ns", "x"]); +let ns = getModuleEnvironmentValue(b, "ns"); +testHasNames(Object.keys(ns), ["a", "b"]); +assertEq(ns.a, 1); +assertEq(ns.b, 2); +assertEq(ns.c, undefined); +assertEq(getModuleEnvironmentValue(b, "x"), 3); + +// Test module namespace internal methods as defined in 9.4.6 +assertEq(Object.getPrototypeOf(ns), null); +assertEq(Reflect.setPrototypeOf(ns, null), true); +assertEq(Reflect.setPrototypeOf(ns, Object.prototype), false); +assertThrowsInstanceOf(() => Object.setPrototypeOf(ns, {}), 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, false); +assertEq(typeof desc.get, "undefined"); +assertEq(typeof desc.set, "undefined"); +assertEq(Object.prototype.toString.call(ns), "[object Module]"); + +// Test [[OwnPropertyKeys]] internal method. +testEqualArrays(Reflect.ownKeys(ns), ["a", "b", Symbol.toStringTag]); +testEqualArrays(Object.getOwnPropertyNames(ns), ["a", "b"]); +testEqualArrays(Object.getOwnPropertySymbols(ns), [Symbol.toStringTag]); + +// Test cyclic namespace import and access in module evaluation. +let c = registerModule('c', + parseModule("export let c = 1; import * as ns from 'd'; let d = ns.d;")); +let d = registerModule('d', + parseModule("export let d = 2; import * as ns from 'c'; let c = ns.c;")); +moduleLink(c); +moduleLink(d); +moduleEvaluate(c) + .then(r => { + // We expect the evaluation to throw, so we should not reach this. + assertEq(false, true) + }) + .catch(e => { + assertEq(e instanceof ReferenceError, true) + }); + +// Test cyclic namespace import. +let e = registerModule('e', + parseModule("export let e = 1; import * as ns from 'f'; export function f() { return ns.f }")); +let f = registerModule('f', + parseModule("export let f = 2; import * as ns from 'e'; export function e() { return ns.e }")); +moduleLink(e); +moduleLink(f); +moduleEvaluate(e); +moduleEvaluate(f); +assertEq(e.namespace.f(), 2); +assertEq(f.namespace.e(), 1); +drainJobQueue(); 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 0000000000..05e6e1e8d5 --- /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/inline-data.js b/js/src/jit-test/tests/modules/inline-data.js new file mode 100644 index 0000000000..9c56856f8d --- /dev/null +++ b/js/src/jit-test/tests/modules/inline-data.js @@ -0,0 +1,17 @@ +// |jit-test| module + +import { a } from "javascript: export let a = 42;"; +assertEq(a, 42); + +let result = null; +let error = null; +let promise = import("javascript: export let b = 100;"); +promise.then((ns) => { + result = ns; +}).catch((e) => { + error = e; +}); + +drainJobQueue(); +assertEq(error, null); +assertEq(result.b, 100); diff --git a/js/src/jit-test/tests/modules/instanceof-error-message.js b/js/src/jit-test/tests/modules/instanceof-error-message.js new file mode 100644 index 0000000000..d78eb333b3 --- /dev/null +++ b/js/src/jit-test/tests/modules/instanceof-error-message.js @@ -0,0 +1,14 @@ +function getInstanceOfErrorMessage(x) { + try { + var result = {} instanceof x; + } + catch (e) { + return e.message; + } +} + +// Error message for a Module Namespace Exotic Object should be same as normal +// non-callable when using 'instanceof' +import('empty.js').then( + m => assertEq(getInstanceOfErrorMessage(m), + getInstanceOfErrorMessage({}))); 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 0000000000..b426794340 --- /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 0000000000..a573f05ef3 --- /dev/null +++ b/js/src/jit-test/tests/modules/many-exports.js @@ -0,0 +1,17 @@ +// Test many exports. + +const count = 1024; + +let s = ""; +for (let i = 0; i < count; i++) + s += "export let e" + i + " = " + (i * i) + ";\n"; +let a = registerModule('a', parseModule(s)); + +let b = registerModule('b', parseModule("import * as ns from 'a'")); + +moduleLink(b); +moduleEvaluate(b); + +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 0000000000..9106c6ce85 --- /dev/null +++ b/js/src/jit-test/tests/modules/many-imports.js @@ -0,0 +1,15 @@ +// Test importing an import many times. + +const count = 1024; + +let a = registerModule('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 = registerModule('b', parseModule(s)); + +moduleLink(b); +moduleEvaluate(b); 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 0000000000..df361c7b91 --- /dev/null +++ b/js/src/jit-test/tests/modules/many-namespace-imports.js @@ -0,0 +1,15 @@ +// Test importing a namespace many times. + +const count = 1024; + +let a = registerModule('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 = registerModule('b', parseModule(s)); + +moduleLink(b); +moduleEvaluate(b); diff --git a/js/src/jit-test/tests/modules/missing-export-offthread.js b/js/src/jit-test/tests/modules/missing-export-offthread.js new file mode 100644 index 0000000000..2dca5c8705 --- /dev/null +++ b/js/src/jit-test/tests/modules/missing-export-offthread.js @@ -0,0 +1,10 @@ +// |jit-test| skip-if: helperThreadCount() === 0 + +load(libdir + "asserts.js") + +// Don't assert. +offThreadCompileModuleToStencil("export { x };"); +assertThrowsInstanceOf(() => { + var stencil = finishOffThreadStencil(); + instantiateModuleStencil(stencil); +}, SyntaxError); 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 0000000000..207e49ba05 --- /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 0000000000..43d66a7f6f --- /dev/null +++ b/js/src/jit-test/tests/modules/module-declaration-instantiation.js @@ -0,0 +1,37 @@ +// Exercise ModuleDeclarationInstantiation() operation. + +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(""); +moduleLink(m); +testModuleEnvironment(m, []); + +let a = registerModule('a', parseModule("var x = 1; export { x };")); +let b = registerModule('b', parseModule("import { x as y } from 'a';")); + +moduleLink(a); +moduleLink(b); + +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")); +moduleLink(c); +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 0000000000..fc526cfdd7 --- /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 0000000000..c727f567df --- /dev/null +++ b/js/src/jit-test/tests/modules/module-evaluation.js @@ -0,0 +1,125 @@ +// |jit-test| +// Exercise ModuleEvaluation() concrete method. + +load(libdir + "asserts.js"); + +async function parseAndEvaluate(source) { + let m = parseModule(source); + moduleLink(m); + await moduleEvaluate(m); + return m; +} + +// Check the evaluation of an empty module succeeds. +(async () => { + await parseAndEvaluate(""); +})(); + +(async () => { + // Check that evaluation returns evaluation promise, + // and promise is always the same. + let m = parseModule("1"); + moduleLink(m); + assertEq(typeof moduleEvaluate(m), "object"); + assertEq(moduleEvaluate(m) instanceof Promise, true); + assertEq(moduleEvaluate(m), moduleEvaluate(m)); + await moduleEvaluate(m); +})(); + +(async () => { + // Check top level variables are initialized by evaluation. + let m = parseModule("export var x = 2 + 2;"); + assertEq(typeof getModuleEnvironmentValue(m, "x"), "undefined"); + moduleLink(m); + await moduleEvaluate(m); + assertEq(getModuleEnvironmentValue(m, "x"), 4); +})(); + +(async () => { + let m = parseModule("export let x = 2 * 3;"); + moduleLink(m); + await moduleEvaluate(m); + assertEq(getModuleEnvironmentValue(m, "x"), 6); +})(); + +// Set up a module to import from. +let a = registerModule('a', + parseModule(`var x = 1; + export { x }; + export default 2; + export function f(x) { return x + 1; }`)); + +(async () => { + // Check we can evaluate top level definitions. + await parseAndEvaluate("var foo = 1;"); + await parseAndEvaluate("let foo = 1;"); + await parseAndEvaluate("const foo = 1"); + await parseAndEvaluate("function foo() {}"); + await parseAndEvaluate("class foo { constructor() {} }"); + + // Check we can evaluate all module-related syntax. + await parseAndEvaluate("export var foo = 1;"); + await parseAndEvaluate("export let foo = 1;"); + await parseAndEvaluate("export const foo = 1;"); + await parseAndEvaluate("var x = 1; export { x };"); + await parseAndEvaluate("export default 1"); + await parseAndEvaluate("export default function() {};"); + await parseAndEvaluate("export default function foo() {};"); + await parseAndEvaluate("import a from 'a';"); + await parseAndEvaluate("import { x } from 'a';"); + await parseAndEvaluate("import * as ns from 'a';"); + await parseAndEvaluate("export * from 'a'"); + await parseAndEvaluate("export default class { constructor() {} };"); + await parseAndEvaluate("export default class foo { constructor() {} };"); +})(); + +(async () => { + // Test default import + let m = parseModule("import a from 'a'; export { a };") + moduleLink(m); + await moduleEvaluate(m) + assertEq(getModuleEnvironmentValue(m, "a"), 2); +})(); + +(async () => { + // Test named import + let m = parseModule("import { x as y } from 'a'; export { y };") + moduleLink(m); + await moduleEvaluate(m); + assertEq(getModuleEnvironmentValue(m, "y"), 1); +})(); + +(async () => { + // Call exported function + let m = parseModule("import { f } from 'a'; export let x = f(3);") + moduleLink(m); + await moduleEvaluate(m); + assertEq(getModuleEnvironmentValue(m, "x"), 4); +})(); + +(async () => { + // Test importing an indirect export + registerModule('b', parseModule("export { x as z } from 'a';")); + let m = await parseAndEvaluate("import { z } from 'b'; export { z }"); + assertEq(getModuleEnvironmentValue(m, "z"), 1); +})(); + +(async () => { + // Test cyclic dependencies + registerModule('c1', parseModule("export var x = 1; export {y} from 'c2'")); + registerModule('c2', parseModule("export var y = 2; export {x} from 'c1'")); + let m = await parseAndEvaluate(`import { x as x1, y as y1 } from 'c1'; + import { x as x2, y as y2 } from 'c2'; + export let z = [x1, y1, x2, y2]`); + assertDeepEq(getModuleEnvironmentValue(m, "z"), [1, 2, 1, 2]); +})(); + +(async () => { + // Import access in functions + let m = await parseModule("import { x } from 'a'; function f() { return x; }") + moduleLink(m); + moduleEvaluate(m); + let f = getModuleEnvironmentValue(m, "f"); + assertEq(f(), 1); +})(); +drainJobQueue(); 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 0000000000..2970f0846e --- /dev/null +++ b/js/src/jit-test/tests/modules/module-this.js @@ -0,0 +1,25 @@ +// |jit-test| +// Test 'this' is undefined in modules. + +function parseAndEvaluate(source) { + let m = parseModule(source); + moduleLink(m); + return moduleEvaluate(m); +} + +parseAndEvaluate("this") + .then(value => assertEq(typeof(value), "undefined")) + .catch(error => { + // We shouldn't throw in this case. + assertEq(false, true) + }); + +let m = parseModule("export function getThis() { return this; }"); +moduleLink(m); +moduleEvaluate(m) + .then(() => { + let f = getModuleEnvironmentValue(m, "getThis"); + assertEq(typeof(f()), "undefined"); + }); + +drainJobQueue(); 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 0000000000..ae322246dd --- /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 0000000000..42595b7095 --- /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 0000000000..80de986c6f --- /dev/null +++ b/js/src/jit-test/tests/modules/off-thread-compile.js @@ -0,0 +1,15 @@ +// |jit-test| skip-if: helperThreadCount() === 0 + +// Test off thread module compilation. + +load(libdir + "asserts.js"); + +function offThreadParseAndEvaluate(source) { + offThreadCompileModuleToStencil(source); + let stencil = finishOffThreadStencil(); + let m = instantiateModuleStencil(stencil); + moduleLink(m); + return moduleEvaluate(m); +} + +offThreadParseAndEvaluate("export let x = 2 * 3;"); diff --git a/js/src/jit-test/tests/modules/offthread-oom.js b/js/src/jit-test/tests/modules/offthread-oom.js new file mode 100644 index 0000000000..97b783c1ba --- /dev/null +++ b/js/src/jit-test/tests/modules/offthread-oom.js @@ -0,0 +1,13 @@ +// |jit-test| skip-if: !('oomTest' in this) || helperThreadCount() === 0 + +// Test Out-of-Memory handling when parsing modules off-thread + +function offThreadParseAndEvaluate(source) { + offThreadCompileModuleToStencil(source); + let stencil = finishOffThreadStencil(); + let m = instantiateModuleStencil(stencil); + moduleLink(m); + return moduleEvaluate(m); +} + +oomTest(() => offThreadParseAndEvaluate(`export let i = 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 0000000000..0313321c59 --- /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 0000000000..ebbf8ce6c1 --- /dev/null +++ b/js/src/jit-test/tests/modules/requested-modules.js @@ -0,0 +1,95 @@ +// |jit-test| --enable-import-assertions + +// 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].moduleRequest.specifier, expected[i].specifier); + if(expected[i].assertions === null) { + assertEq(actual[i].moduleRequest.assertions, null); + } + else { + var expectedAssertions = expected[i].assertions; + var actualAssertions = actual[i].moduleRequest.assertions; + assertEq(actualAssertions.length, expectedAssertions.length); + for (var j = 0; j < expectedAssertions.length; j++) { + assertEq(expectedAssertions[j].type, actualAssertions[j].type); + } + } + } +} + +testRequestedModules("", []); + +testRequestedModules("import a from 'foo'", [ + { specifier: 'foo', assertions: null } +]); + +testRequestedModules("import a from 'foo'; import b from 'bar'", [ + { specifier: 'foo', assertions: null }, + { specifier: 'bar', assertions: null } +]); + +testRequestedModules("import a from 'foo'; import b from 'bar'; import c from 'foo'", [ + { specifier: 'foo', assertions: null }, + { specifier: 'bar', assertions: null } +]); + +testRequestedModules("export {} from 'foo'", [ + { specifier: 'foo', assertions: null } +]); + +testRequestedModules("export * from 'bar'",[ + { specifier: 'bar', assertions: null } +]); + +testRequestedModules("import a from 'foo'; export {} from 'bar'; export * from 'baz'", [ + { specifier: 'foo', assertions: null }, + { specifier: 'bar', assertions: null }, + { specifier: 'baz', assertions: null } +]); + +if (getRealmConfiguration("importAttributes")) { + testRequestedModules("import a from 'foo' assert {}", [ + { specifier: 'foo', assertions: null }, + ]); + + testRequestedModules("import a from 'foo' assert { type: 'js'}", [ + { specifier: 'foo', assertions: [ { type: 'js' } ] }, + ]); + + testRequestedModules("import a from 'foo' assert { unsupported: 'test'}", [ + { specifier: 'foo', assertions: null }, + ]); + + testRequestedModules("import a from 'foo' assert { unsupported: 'test', type: 'js', foo: 'bar' }", [ + { specifier: 'foo', assertions: [ { type: 'js' } ] }, + ]); + + testRequestedModules("import a from 'foo' assert { type: 'js1'}; export {} from 'bar' assert { type: 'js2'}; export * from 'baz' assert { type: 'js3'}", [ + { specifier: 'foo', assertions: [ { type: 'js1' } ] }, + { specifier: 'bar', assertions: [ { type: 'js2' } ] }, + { specifier: 'baz', assertions: [ { type: 'js3' } ] } + ]); + + testRequestedModules("export {} from 'foo' assert { type: 'js'}", [ + { specifier: 'foo', assertions: [ { type: 'js' } ] } + ]); + + testRequestedModules("export * from 'bar' assert { type: 'json'}",[ + { specifier: 'bar', assertions: [ { type: 'json' } ] } + ]); + + testRequestedModules("import a from 'foo'; import b from 'bar' assert { type: 'json' };", [ + { specifier: 'foo', assertions: null }, + { specifier: 'bar', assertions: [ { type: 'json' } ] }, + ]); + + testRequestedModules("import b from 'bar' assert { type: 'json' }; import a from 'foo';", [ + { specifier: 'bar', assertions: [ { type: 'json' } ] }, + { specifier: 'foo', assertions: null }, + ]); +} 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 0000000000..d01f10aaa2 --- /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/shell-wrapper.js b/js/src/jit-test/tests/modules/shell-wrapper.js new file mode 100644 index 0000000000..1be1c486c6 --- /dev/null +++ b/js/src/jit-test/tests/modules/shell-wrapper.js @@ -0,0 +1,174 @@ +// |jit-test| module +// Test shell ModuleObject wrapper's accessors and methods + +load(libdir + "asserts.js"); + +function testGetter(obj, name) { + // Check the getter is defined on the instance, instead of prototype. + // * raw ModuleObject's getters are defined on prototype + // * ModuleObject wrapper's getters are defined on instance + const desc = Object.getOwnPropertyDescriptor(obj, name); + assertEq(typeof desc.get, "function"); + assertEq(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(obj), name), + undefined); + + // Check invalid this value. + assertThrowsInstanceOf(() => { + desc.get.call({}); + }, Error); +} + +// ==== namespace getter ==== +const a = registerModule('a', parseModule(` +export const v = 10; +`)); +const b = registerModule('b', parseModule(` +import * as ns from 'a' +`)); +moduleLink(b); +moduleEvaluate(b); +assertEq(a.namespace.v, 10); +testGetter(a, "namespace"); + +// ==== status getter ==== +const MODULE_STATUS_UNLINKED = 0; +const MODULE_STATUS_LINKED = 2; +const MODULE_STATUS_EVALUATED = 5; + +const c = registerModule('c', parseModule(` +`)); +assertEq(c.status, MODULE_STATUS_UNLINKED); +moduleLink(c); +assertEq(c.status, MODULE_STATUS_LINKED); +moduleEvaluate(c); +assertEq(c.status, MODULE_STATUS_EVALUATED); +testGetter(c, "status"); + +// ==== evaluationError getter ==== +const d = registerModule('d', parseModule(` +f(); +`)); +moduleLink(d); +try { + await moduleEvaluate(d); +} catch (e) { +} +assertEq(d.evaluationError instanceof ReferenceError, true); +testGetter(d, "evaluationError"); + +// ==== requestedModules getter ==== +const e = parseModule(` +import a from 'b'; +`); +assertEq(e.requestedModules.length, 1); +assertEq(e.requestedModules[0].moduleRequest.specifier, 'b'); +assertEq(e.requestedModules[0].lineNumber, 2); +assertEq(e.requestedModules[0].columnNumber, 15); +testGetter(e, "requestedModules"); +testGetter(e.requestedModules[0], "moduleRequest"); +testGetter(e.requestedModules[0].moduleRequest, "specifier"); +testGetter(e.requestedModules[0], "lineNumber"); +testGetter(e.requestedModules[0], "columnNumber"); + +// ==== importEntries getter ==== +const f = parseModule(` +import {a as A} from 'b'; +`); +assertEq(f.importEntries.length, 1); +assertEq(f.importEntries[0].moduleRequest.specifier, 'b'); +assertEq(f.importEntries[0].importName, 'a'); +assertEq(f.importEntries[0].localName, 'A'); +assertEq(f.importEntries[0].lineNumber, 2); +assertEq(f.importEntries[0].columnNumber, 9); +testGetter(f, "importEntries"); +testGetter(f.importEntries[0], "moduleRequest"); +testGetter(f.importEntries[0].moduleRequest, "specifier"); +testGetter(f.importEntries[0], "importName"); +testGetter(f.importEntries[0], "localName"); +testGetter(f.importEntries[0], "lineNumber"); +testGetter(f.importEntries[0], "columnNumber"); + +// ==== localExportEntries getter ==== +const g = parseModule(` +export const v = 1; +`); +assertEq(g.localExportEntries.length, 1); +assertEq(g.localExportEntries[0].exportName, 'v'); +assertEq(g.localExportEntries[0].moduleRequest, null); +assertEq(g.localExportEntries[0].importName, null); +assertEq(g.localExportEntries[0].localName, 'v'); +assertEq(g.localExportEntries[0].lineNumber, 0); +assertEq(g.localExportEntries[0].columnNumber, 1); +testGetter(g, "localExportEntries"); +testGetter(g.localExportEntries[0], "exportName"); +testGetter(g.localExportEntries[0], "moduleRequest"); +testGetter(g.localExportEntries[0], "importName"); +testGetter(g.localExportEntries[0], "localName"); +testGetter(g.localExportEntries[0], "lineNumber"); +testGetter(g.localExportEntries[0], "columnNumber"); + +// ==== indirectExportEntries getter ==== +const h = parseModule(` +export {v} from "b"; +`); +assertEq(h.indirectExportEntries.length, 1); +assertEq(h.indirectExportEntries[0].exportName, 'v'); +assertEq(h.indirectExportEntries[0].moduleRequest.specifier, "b"); +assertEq(h.indirectExportEntries[0].importName, "v"); +assertEq(h.indirectExportEntries[0].localName, null); +assertEq(h.indirectExportEntries[0].lineNumber, 2); +assertEq(h.indirectExportEntries[0].columnNumber, 9); + +// ==== starExportEntries getter ==== +const i = parseModule(` +export * from "b"; +`); +assertEq(i.starExportEntries.length, 1); +assertEq(i.starExportEntries[0].exportName, null); +assertEq(i.starExportEntries[0].moduleRequest.specifier, "b"); +assertEq(i.starExportEntries[0].importName, null); +assertEq(i.starExportEntries[0].localName, null); +assertEq(i.starExportEntries[0].lineNumber, 2); +assertEq(i.starExportEntries[0].columnNumber, 8); + +// ==== dfsIndex and dfsAncestorIndex getters ==== +const j = registerModule('j', parseModule(` +export const v1 = 10; +import {v2} from 'k' +`)); +const k = registerModule('k', parseModule(` +export const v2 = 10; +import {v1} from 'j' +`)); +const l = registerModule('l', parseModule(` +export const v3 = 10; +import {v2} from 'k' +import {v1} from 'j' +`)); +assertEq(j.dfsIndex, undefined); +assertEq(j.dfsAncestorIndex, undefined); +assertEq(k.dfsIndex, undefined); +assertEq(k.dfsAncestorIndex, undefined); +assertEq(l.dfsIndex, undefined); +assertEq(l.dfsAncestorIndex, undefined); +moduleLink(l); +assertEq(j.dfsIndex, 2); +assertEq(j.dfsAncestorIndex, 1); +assertEq(k.dfsIndex, 1); +assertEq(k.dfsAncestorIndex, 1); +assertEq(l.dfsIndex, 0); +assertEq(l.dfsAncestorIndex, 0); + +// ==== async and promises getters ==== +const m = parseModule(` +`); +assertEq(m.hasTopLevelAwait, false); +assertEq(m.topLevelCapability, undefined); +assertEq(m.asyncEvaluatingPostOrder, undefined); +assertEq(m.asyncParentModules[0], undefined); +assertEq(m.pendingAsyncDependencies, undefined); +testGetter(m, "hasTopLevelAwait"); +testGetter(m, "topLevelCapability"); +testGetter(m, "asyncEvaluatingPostOrder"); +testGetter(m, "asyncParentModules"); +testGetter(m, "pendingAsyncDependencies"); 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 0000000000..a0c894ef63 --- /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/tla-after-many-bindings.js b/js/src/jit-test/tests/modules/tla-after-many-bindings.js new file mode 100644 index 0000000000..220d2d3ab1 --- /dev/null +++ b/js/src/jit-test/tests/modules/tla-after-many-bindings.js @@ -0,0 +1,24 @@ +parseModule(` + var x = 449627; + var summary = 'foo'; + if (typeof unescape === 'function') { + let x00, x01, x02, x03, x04, x05, x06, x07, x08, x09, x0a, x0b, x0c, x0d, x0e, x0f, + x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x1a, x1b, x1c, x1d, x1e, x1f, + x20, x21, x22, x23, x24, x25, x26, x27, { get } = ()=>{x41++;y63++;z84++}, + x29, x2a, x2b, x2c, x2d, x2e, x2f, + x30, x31, x32, x33, x34, x35, x36, x37, x38, x39, x3a, x3b, x3c, x3d, x3e, x3f, + x40, x41, x42, x43, x44, x45, x46, x47, x48, x49, x4a, x4b, x4c, x4d, x4e, x4f, + x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x5a, x5b, x5c, x5d, x5e, x5f, + x60, x61, x62, x63, x64, x65, x66, x67, x68, x69, x6a, x6b, x6c, x6d, x6e, x6f, + x70, x71, x72, x73, x74, x75, x76, x77, x78, x79, x7a, x7b, x7c, x7d, x7e, x7f, + x80, x81, x82, x83, x84, x85, x86, x87, x88, x89, x8a, x8b, x8c, x8d, x8e, x8f, + x90, x91, x92, x93, x94, x95, x96, x97, x98, x99, x9a, x9b, x9c, x9d, x9e, x9f, + xa0, of , xa2, xa3, xa4, xa5, xa6, xa7, xa8, xa9, xaa, xab, xac, xad, xae, xaf, + xb0, xb1, xb2, xb3, xb4, xb5, xb6, xb7, xb8, xb9, xba, xbb, xbc, xbd, xbe, xbf, + xc0, xc1, xc2, xc3, xc4, xc5, xc6, xc7, xc8, xc9, xca, xcb, xcc, xcd, xce, xcf, + xd0, xd1, xd2, xd3, xd4, xd5, xd6, xd7, xd8, xd9, xda, xdb, xdc, xdd, xde, xdf, + xe0, xe1, xe2, xe3, xe4, xe5, xe6, xe7, xe8, xe9, xea, xeb, xec, xed, xee, xef, + xf0, xf1, xf2, xf3, xf4, xf5, xf6, xf7, xf8, xf9, xfa, xfb, xfc, xfd, xfe, xff; + } + await isOdd(); +`); diff --git a/js/src/jit-test/tests/modules/tla-many-vars.js b/js/src/jit-test/tests/modules/tla-many-vars.js new file mode 100644 index 0000000000..de2e813805 --- /dev/null +++ b/js/src/jit-test/tests/modules/tla-many-vars.js @@ -0,0 +1,15 @@ +a = []; +for (i = 0; i < 1000; ++i) { + a.push("x" + i); +} + +// Sync +parseModule(` + let ${a.join(",")}; + `); + +// Async +parseModule(` + let ${a.join(",")}; + await 1; + `); 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 0000000000..f70405d56f --- /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 }; |