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