summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/modules
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/modules')
-rw-r--r--js/src/jit-test/tests/modules/add-to-namespace-import.js3
-rw-r--r--js/src/jit-test/tests/modules/ambiguous-import.js2
-rw-r--r--js/src/jit-test/tests/modules/ambiguous-indirect-export.js2
-rw-r--r--js/src/jit-test/tests/modules/ambiguous-star-export.js43
-rw-r--r--js/src/jit-test/tests/modules/assign-to-import.js3
-rw-r--r--js/src/jit-test/tests/modules/assign-to-namespace-import.js3
-rw-r--r--js/src/jit-test/tests/modules/assign-to-namespace.js3
-rw-r--r--js/src/jit-test/tests/modules/async-eval-state.js207
-rw-r--r--js/src/jit-test/tests/modules/bad-namespace-created.js15
-rw-r--r--js/src/jit-test/tests/modules/bug-1168666.js2
-rw-r--r--js/src/jit-test/tests/modules/bug-1217593.js6
-rw-r--r--js/src/jit-test/tests/modules/bug-1219044.js4
-rw-r--r--js/src/jit-test/tests/modules/bug-1219408.js2
-rw-r--r--js/src/jit-test/tests/modules/bug-1225346.js2
-rw-r--r--js/src/jit-test/tests/modules/bug-1233117.js2
-rw-r--r--js/src/jit-test/tests/modules/bug-1233179.js8
-rw-r--r--js/src/jit-test/tests/modules/bug-1233915.js11
-rw-r--r--js/src/jit-test/tests/modules/bug-1236875.js2
-rw-r--r--js/src/jit-test/tests/modules/bug-1245518.js15
-rw-r--r--js/src/jit-test/tests/modules/bug-1247934.js5
-rw-r--r--js/src/jit-test/tests/modules/bug-1258097.js3
-rw-r--r--js/src/jit-test/tests/modules/bug-1283448.js4
-rw-r--r--js/src/jit-test/tests/modules/bug-1284486-2.js34
-rw-r--r--js/src/jit-test/tests/modules/bug-1284486.js33
-rw-r--r--js/src/jit-test/tests/modules/bug-1287406.js1
-rw-r--r--js/src/jit-test/tests/modules/bug-1287410.js17
-rw-r--r--js/src/jit-test/tests/modules/bug-1320993.js2
-rw-r--r--js/src/jit-test/tests/modules/bug-1372258.js26
-rw-r--r--js/src/jit-test/tests/modules/bug-1402535.js6
-rw-r--r--js/src/jit-test/tests/modules/bug-1402649.js14
-rw-r--r--js/src/jit-test/tests/modules/bug-1406452.js5
-rw-r--r--js/src/jit-test/tests/modules/bug-1420420-2.js17
-rw-r--r--js/src/jit-test/tests/modules/bug-1420420-3.js7
-rw-r--r--js/src/jit-test/tests/modules/bug-1420420-4.js18
-rw-r--r--js/src/jit-test/tests/modules/bug-1420420.js17
-rw-r--r--js/src/jit-test/tests/modules/bug-1435327.js27
-rw-r--r--js/src/jit-test/tests/modules/bug-1439416-2.js10
-rw-r--r--js/src/jit-test/tests/modules/bug-1439416.js10
-rw-r--r--js/src/jit-test/tests/modules/bug-1443555.js29
-rw-r--r--js/src/jit-test/tests/modules/bug-1462286.js8
-rw-r--r--js/src/jit-test/tests/modules/bug-1462326.js6
-rw-r--r--js/src/jit-test/tests/modules/bug-1466487.js7
-rw-r--r--js/src/jit-test/tests/modules/bug-1476921.js31
-rw-r--r--js/src/jit-test/tests/modules/bug-1498980.js29
-rw-r--r--js/src/jit-test/tests/modules/bug-1501154.js25
-rw-r--r--js/src/jit-test/tests/modules/bug-1501157.js2
-rw-r--r--js/src/jit-test/tests/modules/bug-1502669.js5
-rw-r--r--js/src/jit-test/tests/modules/bug-1503009.js1
-rw-r--r--js/src/jit-test/tests/modules/bug-1510598.js9
-rw-r--r--js/src/jit-test/tests/modules/bug-1519140.js3
-rw-r--r--js/src/jit-test/tests/modules/bug-1604792.js7
-rw-r--r--js/src/jit-test/tests/modules/bug-1657066.js3
-rw-r--r--js/src/jit-test/tests/modules/bug-1680878.js7
-rw-r--r--js/src/jit-test/tests/modules/bug-1681256.js20
-rw-r--r--js/src/jit-test/tests/modules/bug-1711342.js6
-rw-r--r--js/src/jit-test/tests/modules/bug-1764239.js13
-rw-r--r--js/src/jit-test/tests/modules/bug-1771090.js9
-rw-r--r--js/src/jit-test/tests/modules/bug-1777972.js4
-rw-r--r--js/src/jit-test/tests/modules/bug-1778439.js1
-rw-r--r--js/src/jit-test/tests/modules/bug-1782496.js9
-rw-r--r--js/src/jit-test/tests/modules/bug-1787926.js16
-rw-r--r--js/src/jit-test/tests/modules/bug-1789412.js12
-rw-r--r--js/src/jit-test/tests/modules/bug-1790352.js13
-rw-r--r--js/src/jit-test/tests/modules/bug-1795845.js3
-rw-r--r--js/src/jit-test/tests/modules/bug-1802479.js15
-rw-r--r--js/src/jit-test/tests/modules/bug1105608.js9
-rw-r--r--js/src/jit-test/tests/modules/bug1169850.js9
-rw-r--r--js/src/jit-test/tests/modules/bug1198673.js2
-rw-r--r--js/src/jit-test/tests/modules/bug1204857.js2
-rw-r--r--js/src/jit-test/tests/modules/bug1210391.js7
-rw-r--r--js/src/jit-test/tests/modules/bug1394492.js6
-rw-r--r--js/src/jit-test/tests/modules/bug1394493.js4
-rw-r--r--js/src/jit-test/tests/modules/bug1429031.js16
-rw-r--r--js/src/jit-test/tests/modules/bug1449153.js33
-rw-r--r--js/src/jit-test/tests/modules/bug1485698.js9
-rw-r--r--js/src/jit-test/tests/modules/bug1584034.js1
-rw-r--r--js/src/jit-test/tests/modules/bug1584309.js1
-rw-r--r--js/src/jit-test/tests/modules/bug1586599.js30
-rw-r--r--js/src/jit-test/tests/modules/bug1670236.js6
-rw-r--r--js/src/jit-test/tests/modules/bug1685992.js12
-rw-r--r--js/src/jit-test/tests/modules/bug1699622.js4
-rw-r--r--js/src/jit-test/tests/modules/bug1770048.js20
-rw-r--r--js/src/jit-test/tests/modules/cyclic-function-import.js7
-rw-r--r--js/src/jit-test/tests/modules/cyclic-import.js3
-rw-r--r--js/src/jit-test/tests/modules/debugger-frames.js83
-rw-r--r--js/src/jit-test/tests/modules/debugger-vars-function.js30
-rw-r--r--js/src/jit-test/tests/modules/debugger-vars-toplevel.js31
-rw-r--r--js/src/jit-test/tests/modules/delete-import.js3
-rw-r--r--js/src/jit-test/tests/modules/delete-namespace-import.js3
-rw-r--r--js/src/jit-test/tests/modules/delete-namespace.js3
-rw-r--r--js/src/jit-test/tests/modules/duplicate-exports.js32
-rw-r--r--js/src/jit-test/tests/modules/duplicate-imports.js27
-rw-r--r--js/src/jit-test/tests/modules/dynamic-import-error.js14
-rw-r--r--js/src/jit-test/tests/modules/dynamic-import-expression.js213
-rw-r--r--js/src/jit-test/tests/modules/dynamic-import-ion.js16
-rw-r--r--js/src/jit-test/tests/modules/dynamic-import-lazy.js4
-rw-r--r--js/src/jit-test/tests/modules/dynamic-import-module.js39
-rw-r--r--js/src/jit-test/tests/modules/dynamic-import-oom.js9
-rw-r--r--js/src/jit-test/tests/modules/dynamic-import-script.js45
-rw-r--r--js/src/jit-test/tests/modules/eval-module-oom.js23
-rw-r--r--js/src/jit-test/tests/modules/export-circular-nonexisting-binding.js3
-rw-r--r--js/src/jit-test/tests/modules/export-declaration.js567
-rw-r--r--js/src/jit-test/tests/modules/export-destructuring.js104
-rw-r--r--js/src/jit-test/tests/modules/export-entries.js130
-rw-r--r--js/src/jit-test/tests/modules/export-ns-from.js10
-rw-r--r--js/src/jit-test/tests/modules/export-star-cannot-rescue-missing-export.js4
-rw-r--r--js/src/jit-test/tests/modules/export-star-circular-dependencies.js6
-rw-r--r--js/src/jit-test/tests/modules/function-redeclaration.js94
-rw-r--r--js/src/jit-test/tests/modules/global-scope.js35
-rw-r--r--js/src/jit-test/tests/modules/import-declaration.js479
-rw-r--r--js/src/jit-test/tests/modules/import-default-async-asi.js7
-rw-r--r--js/src/jit-test/tests/modules/import-default-async-regexpy.js5
-rw-r--r--js/src/jit-test/tests/modules/import-default-class.js5
-rw-r--r--js/src/jit-test/tests/modules/import-default-function.js4
-rw-r--r--js/src/jit-test/tests/modules/import-entries.js85
-rw-r--r--js/src/jit-test/tests/modules/import-in-lazy-function.js11
-rw-r--r--js/src/jit-test/tests/modules/import-meta-expression.js91
-rw-r--r--js/src/jit-test/tests/modules/import-meta-oom.js3
-rw-r--r--js/src/jit-test/tests/modules/import-meta.js67
-rw-r--r--js/src/jit-test/tests/modules/import-namespace.js114
-rw-r--r--js/src/jit-test/tests/modules/import-not-found.js2
-rw-r--r--js/src/jit-test/tests/modules/inline-data.js17
-rw-r--r--js/src/jit-test/tests/modules/instanceof-error-message.js14
-rw-r--r--js/src/jit-test/tests/modules/let-tdz.js3
-rw-r--r--js/src/jit-test/tests/modules/many-exports.js17
-rw-r--r--js/src/jit-test/tests/modules/many-imports.js15
-rw-r--r--js/src/jit-test/tests/modules/many-namespace-imports.js15
-rw-r--r--js/src/jit-test/tests/modules/missing-export-offthread.js10
-rw-r--r--js/src/jit-test/tests/modules/missing-indirect-export.js2
-rw-r--r--js/src/jit-test/tests/modules/module-declaration-instantiation.js37
-rw-r--r--js/src/jit-test/tests/modules/module-environment.js34
-rw-r--r--js/src/jit-test/tests/modules/module-evaluation.js125
-rw-r--r--js/src/jit-test/tests/modules/module-this.js25
-rw-r--r--js/src/jit-test/tests/modules/namespace-import-compilation-2.js17
-rw-r--r--js/src/jit-test/tests/modules/namespace-import-compilation.js17
-rw-r--r--js/src/jit-test/tests/modules/off-thread-compile.js15
-rw-r--r--js/src/jit-test/tests/modules/offthread-oom.js13
-rw-r--r--js/src/jit-test/tests/modules/recursive-star-export.js2
-rw-r--r--js/src/jit-test/tests/modules/requested-modules.js93
-rw-r--r--js/src/jit-test/tests/modules/shell-parse.js30
-rw-r--r--js/src/jit-test/tests/modules/shell-wrapper.js174
-rw-r--r--js/src/jit-test/tests/modules/simple-imports.js11
-rw-r--r--js/src/jit-test/tests/modules/tla-many-vars.js15
-rw-r--r--js/src/jit-test/tests/modules/unbound-export.js2
144 files changed, 4169 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..930bd62776
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug-1802479.js
@@ -0,0 +1,15 @@
+// |jit-test| skip-if: !('oomTest' in this)
+
+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/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..05ffde0569
--- /dev/null
+++ b/js/src/jit-test/tests/modules/dynamic-import-expression.js
@@ -0,0 +1,213 @@
+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()['importAssertions']) {
+ 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()['importAssertions']) {
+ 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..e728fd66e2
--- /dev/null
+++ b/js/src/jit-test/tests/modules/export-declaration.js
@@ -0,0 +1,567 @@
+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, assertions) => Pattern({
+ type: "ModuleRequest",
+ source: specifier,
+ assertions: assertions
+});
+importAssertion = (key, value) => Pattern({
+ type: "ImportAssertion",
+ 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()['importAssertions']) {
+ program([
+ exportDeclaration(
+ null,
+ [
+ exportSpecifier(
+ ident("a"),
+ ident("a")
+ )
+ ],
+ moduleRequest(
+ lit("b"),
+ [
+ importAssertion(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"),
+ [
+ importAssertion(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"),
+ [
+ importAssertion(ident('type'), lit('js')),
+ importAssertion(ident('foo'), lit('bar')),
+ importAssertion(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, 0);
+assertEq(loc.start.line, 1);
+assertEq(loc.end.column, 26);
+
+assertThrowsInstanceOf(function () {
+ parseAsModule("function f() { export a }");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function () {
+ parseAsModule("if (true) export a");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("export {");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("export {} from");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("export {,} from 'a'");
+}, SyntaxError);
+
+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..43383e97e5
--- /dev/null
+++ b/js/src/jit-test/tests/modules/import-declaration.js
@@ -0,0 +1,479 @@
+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, assertions) => Pattern({
+ type: "ModuleRequest",
+ source: specifier,
+ assertions: assertions
+});
+importAssertion = (key, value) => Pattern({
+ type: "ImportAssertion",
+ 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()['importAssertions']) {
+ 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"),
+ [
+ importAssertion(ident('type'), lit('js')),
+ ]
+ )
+ )
+ ]).assert(parseAsModule("import a from 'b' assert { type: 'js' }"));
+
+ program([
+ importDeclaration(
+ [
+ importSpecifier(
+ ident("default"),
+ ident("a")
+ )
+ ],
+ moduleRequest(
+ lit("b"),
+ [
+ importAssertion(ident('foo'), lit('bar')),
+ ]
+ )
+ )
+ ]).assert(parseAsModule("import a from 'b' assert { foo: 'bar' }"));
+
+ program([
+ importDeclaration(
+ [
+ importSpecifier(
+ ident("default"),
+ ident("a")
+ )
+ ],
+ moduleRequest(
+ lit("b"),
+ [
+ importAssertion(ident('type'), lit('js')),
+ importAssertion(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);
+}
+
+var loc = parseAsModule("import { a as b } from 'c'", {
+ loc: true
+}).body[0].loc;
+
+assertEq(loc.start.line, 1);
+assertEq(loc.start.column, 0);
+assertEq(loc.start.line, 1);
+assertEq(loc.end.column, 26);
+
+assertThrowsInstanceOf(function () {
+ parseAsModule("function f() { import a from 'b' }");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function () {
+ parseAsModule("if (true) import a from 'b'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import {");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import {}");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import {} from");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import {,} from 'a'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import { a as true } from 'b'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import { true } from 'a'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import a,");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import a, b from 'a'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import * as a,");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import * as a, {} from 'a'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import as a from 'a'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import * a from 'a'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import * as from 'a'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import , {} from 'a'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import d, from 'a'");
+}, SyntaxError);
+
+assertThrowsInstanceOf(function() {
+ parseAsModule("import * as true from 'b'");
+}, SyntaxError);
diff --git a/js/src/jit-test/tests/modules/import-default-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..d79bc0a4d5
--- /dev/null
+++ b/js/src/jit-test/tests/modules/import-entries.js
@@ -0,0 +1,85 @@
+// 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()['importAssertions']) {
+ 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'}]);
+} \ No newline at end of file
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..636a73d922
--- /dev/null
+++ b/js/src/jit-test/tests/modules/requested-modules.js
@@ -0,0 +1,93 @@
+// 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()['importAssertions']) {
+ 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 },
+ ]);
+} \ No newline at end of file
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..83c99b6e4a
--- /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, 14);
+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, 8);
+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, 0);
+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, 8);
+
+// ==== 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, 7);
+
+// ==== 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-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 };