Bug 1341411 - Support circular module dependencies through export* per ES2017. r=jonco
authorAndré Bargull <andre.bargull@gmail.com>
Thu, 23 Feb 2017 03:10:16 -0800
changeset 344633 8c85b69a7a187b719da40c925101795a9a706749
parent 344632 fb79fab50a60eaf84a6a91772912beaec1ab1055
child 344634 212db4739778f1e58dfba06c660e7b1acd399750
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
bugs1341411
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 1341411 - Support circular module dependencies through export* per ES2017. r=jonco
js/src/builtin/Module.js
js/src/builtin/ModuleObject.cpp
js/src/jit-test/modules/empty.js
js/src/jit-test/modules/export-star-circular-1.js
js/src/jit-test/modules/export-star-circular-2.js
js/src/jit-test/tests/modules/export-star-cannot-rescue-missing-export.js
js/src/jit-test/tests/modules/export-star-circular-dependencies.js
--- a/js/src/builtin/Module.js
+++ b/js/src/builtin/Module.js
@@ -60,22 +60,22 @@ function ModuleGetExportedNames(exportSt
             if (n !== "default" && !callFunction(ArrayIncludes, exportedNames, n))
                 _DefineDataProperty(exportedNames, namesCount++, n);
         }
     }
 
     return exportedNames;
 }
 
-// 15.2.1.16.3 ResolveExport(exportName, resolveSet, exportStarSet)
-function ModuleResolveExport(exportName, resolveSet = [], exportStarSet = [])
+// 15.2.1.16.3 ResolveExport(exportName, resolveSet)
+function ModuleResolveExport(exportName, resolveSet = [])
 {
     if (!IsObject(this) || !IsModule(this)) {
         return callFunction(CallModuleMethodIfWrapped, this, exportName, resolveSet,
-                            exportStarSet, "ModuleResolveExport");
+                            "ModuleResolveExport");
     }
 
     // Step 1
     let module = this;
 
     // Step 2
     for (let i = 0; i < resolveSet.length; i++) {
         let r = resolveSet[i];
@@ -96,63 +96,55 @@ 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);
-            let indirectResolution = callFunction(importedModule.resolveExport, importedModule,
-                                                  e.importName, resolveSet, exportStarSet);
-            if (indirectResolution !== null)
-                return indirectResolution;
+            return callFunction(importedModule.resolveExport, importedModule, e.importName,
+                                resolveSet);
         }
     }
 
     // Step 6
     if (exportName === "default") {
         // A default export cannot be provided by an export *.
-        ThrowSyntaxError(JSMSG_BAD_DEFAULT_EXPORT);
+        return null;
     }
 
     // Step 7
-    if (callFunction(ArrayIncludes, exportStarSet, module))
-        return null;
+    let starResolution = null;
 
     // Step 8
-    _DefineDataProperty(exportStarSet, exportStarSet.length, module);
-
-    // Step 9
-    let starResolution = null;
-
-    // Step 10
     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);
         let resolution = callFunction(importedModule.resolveExport, importedModule,
-                                      exportName, resolveSet, exportStarSet);
+                                      exportName, resolveSet);
         if (resolution === "ambiguous")
             return resolution;
 
         if (resolution !== null) {
             if (starResolution === null) {
                 starResolution = resolution;
             } else {
                 if (resolution.module !== starResolution.module ||
                     resolution.exportName !== starResolution.exportName)
                 {
                     return "ambiguous";
                 }
             }
         }
     }
 
+    // Step 9
     return starResolution;
 }
 
 // 15.2.1.18 GetModuleNamespace(module)
 function GetModuleNamespace(module)
 {
     // Step 2
     let namespace = module.namespace;
@@ -274,17 +266,17 @@ function ModuleDeclarationInstantiation(
                 if (resolution === null)
                     ThrowSyntaxError(JSMSG_MISSING_IMPORT, imp.importName);
                 if (resolution === "ambiguous")
                     ThrowSyntaxError(JSMSG_AMBIGUOUS_IMPORT, imp.importName);
                 CreateImportBinding(env, imp.localName, resolution.module, resolution.bindingName);
             }
         }
 
-        // Step 16.iv
+        // Step 17.a.iii
         InstantiateModuleFunctionDeclarations(module);
     } catch (e) {
         RecordInstantationFailure(module);
         throw e;
     }
 }
 _SetCanonicalName(ModuleDeclarationInstantiation, "ModuleDeclarationInstantiation");
 
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -989,17 +989,17 @@ GlobalObject::initModuleProto(JSContext*
         JS_PSG("localExportEntries", ModuleObject_localExportEntriesGetter, 0),
         JS_PSG("indirectExportEntries", ModuleObject_indirectExportEntriesGetter, 0),
         JS_PSG("starExportEntries", ModuleObject_starExportEntriesGetter, 0),
         JS_PS_END
     };
 
     static const JSFunctionSpec protoFunctions[] = {
         JS_SELF_HOSTED_FN("getExportedNames", "ModuleGetExportedNames", 1, 0),
-        JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 3, 0),
+        JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 2, 0),
         JS_SELF_HOSTED_FN("declarationInstantiation", "ModuleDeclarationInstantiation", 0, 0),
         JS_SELF_HOSTED_FN("evaluation", "ModuleEvaluation", 0, 0),
         JS_FS_END
     };
 
     RootedObject proto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
     if (!proto)
         return false;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/modules/empty.js
@@ -0,0 +1,1 @@
+// Intentionally empty.
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/modules/export-star-circular-1.js
@@ -0,0 +1,1 @@
+export* from "export-star-circular-2.js";
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/modules/export-star-circular-2.js
@@ -0,0 +1,3 @@
+export {y as x} from "export-star-circular-1.js";
+
+export var y = "pass";
new file mode 100644
--- /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";
new file mode 100644
--- /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");