Bug 1341298 - Relax expected module state when resolving modules and circular module dependencies are present. r=jonco
authorAndré Bargull <andre.bargull@gmail.com>
Thu, 23 Feb 2017 07:04:20 -0800
changeset 344657 c1e74895212a5eecbe1d1e643c8e36a80852bc40
parent 344656 49abbdfdd1ab01a71ee588a171102aefb85baf30
child 344658 40da4a08377d0d69f76195b7d7f375ac34e2d3a2
push id31414
push usercbook@mozilla.com
push dateFri, 24 Feb 2017 10:47:41 +0000
treeherdermozilla-central@be661bae6cb9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1341298
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1341298 - Relax expected module state when resolving modules and circular module dependencies are present. r=jonco
js/src/builtin/Module.js
js/src/jit-test/modules/export-circular-nonexisting-binding-1.js
js/src/jit-test/modules/export-circular-nonexisting-binding-2.js
js/src/jit-test/tests/modules/export-circular-nonexisting-binding.js
js/src/vm/EnvironmentObject.cpp
--- a/js/src/builtin/Module.js
+++ b/js/src/builtin/Module.js
@@ -95,17 +95,17 @@ function ModuleResolveExport(exportName,
     }
 
     // Step 5
     let indirectExportEntries = module.indirectExportEntries;
     for (let i = 0; i < indirectExportEntries.length; i++) {
         let e = indirectExportEntries[i];
         if (exportName === e.exportName) {
             let importedModule = CallModuleResolveHook(module, e.moduleRequest,
-                                                       MODULE_STATE_INSTANTIATED);
+                                                       MODULE_STATE_PARSED);
             return callFunction(importedModule.resolveExport, importedModule, e.importName,
                                 resolveSet);
         }
     }
 
     // Step 6
     if (exportName === "default") {
         // A default export cannot be provided by an export *.
@@ -115,17 +115,17 @@ function ModuleResolveExport(exportName,
     // Step 7
     let starResolution = null;
 
     // Step 8
     let starExportEntries = module.starExportEntries;
     for (let i = 0; i < starExportEntries.length; i++) {
         let e = starExportEntries[i];
         let importedModule = CallModuleResolveHook(module, e.moduleRequest,
-                                                   MODULE_STATE_INSTANTIATED);
+                                                   MODULE_STATE_PARSED);
         let resolution = callFunction(importedModule.resolveExport, importedModule,
                                       exportName, resolveSet);
         if (resolution === "ambiguous")
             return resolution;
 
         if (resolution !== null) {
             if (starResolution === null) {
                 starResolution = resolution;
@@ -200,18 +200,18 @@ function GetModuleEnvironment(module)
     assert(env === undefined || IsModuleEnvironment(env),
            "Module environment slot contains unexpected value");
 
     return env;
 }
 
 function RecordInstantationFailure(module)
 {
-    // Set the module's environment slot to 'null' to indicate a failed module
-    // instantiation.
+    // Set the module's state to 'failed' to indicate a failed module
+    // instantiation and reset the environment slot to 'undefined'.
     assert(IsModule(module), "Non-module passed to RecordInstantationFailure");
     SetModuleState(module, MODULE_STATE_FAILED);
     UnsafeSetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT, undefined);
 }
 
 // 15.2.1.16.4 ModuleDeclarationInstantiation()
 function ModuleDeclarationInstantiation()
 {
@@ -262,16 +262,18 @@ function ModuleDeclarationInstantiation(
                 CreateNamespaceBinding(env, imp.localName, namespace);
             } else {
                 let resolution = callFunction(importedModule.resolveExport, importedModule,
                                               imp.importName);
                 if (resolution === null)
                     ThrowSyntaxError(JSMSG_MISSING_IMPORT, imp.importName);
                 if (resolution === "ambiguous")
                     ThrowSyntaxError(JSMSG_AMBIGUOUS_IMPORT, imp.importName);
+                if (resolution.module.state < MODULE_STATE_INSTANTIATED)
+                    ThrowInternalError(JSMSG_BAD_MODULE_STATE);
                 CreateImportBinding(env, imp.localName, resolution.module, resolution.bindingName);
             }
         }
 
         // Step 17.a.iii
         InstantiateModuleFunctionDeclarations(module);
     } catch (e) {
         RecordInstantationFailure(module);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/modules/export-circular-nonexisting-binding-1.js
@@ -0,0 +1,4 @@
+import "export-circular-nonexisting-binding-2.js";
+
+export* from "empty.js";
+export {x} from "empty.js";
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/modules/export-circular-nonexisting-binding-2.js
@@ -0,0 +1,1 @@
+export {x} from "export-circular-nonexisting-binding-1.js";
new file mode 100644
--- /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";
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -483,17 +483,17 @@ ModuleEnvironmentObject::importBindings(
 }
 
 bool
 ModuleEnvironmentObject::createImportBinding(JSContext* cx, HandleAtom importName,
                                              HandleModuleObject module, HandleAtom localName)
 {
     RootedId importNameId(cx, AtomToId(importName));
     RootedId localNameId(cx, AtomToId(localName));
-    RootedModuleEnvironmentObject env(cx, module->environment());
+    RootedModuleEnvironmentObject env(cx, &module->initialEnvironment());
     if (!importBindings().putNew(cx, importNameId, env, localNameId)) {
         ReportOutOfMemory(cx);
         return false;
     }
 
     return true;
 }