diff options
author | Moonchild <moonchild@palemoon.org> | 2020-07-03 13:56:49 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2020-07-03 13:56:49 +0000 |
commit | 61a471ef17645c211d228b4dd085a933fba6e6ba (patch) | |
tree | 0ee6503cf1aadea9e5737056896fa61782cb1822 /js | |
parent | 98752af13349e2da56b5ed1219cae30008ef250a (diff) | |
download | UXP-61a471ef17645c211d228b4dd085a933fba6e6ba.tar UXP-61a471ef17645c211d228b4dd085a933fba6e6ba.tar.gz UXP-61a471ef17645c211d228b4dd085a933fba6e6ba.tar.lz UXP-61a471ef17645c211d228b4dd085a933fba6e6ba.tar.xz UXP-61a471ef17645c211d228b4dd085a933fba6e6ba.zip |
Issue #618 - Align module instantiation/errors with the updated spec.
Store and re-throw module instantiation and evaluation errors.
Ref: BZ 1374239, 1394492
Diffstat (limited to 'js')
-rw-r--r-- | js/src/builtin/Module.js | 533 | ||||
-rw-r--r-- | js/src/builtin/ModuleObject.cpp | 69 | ||||
-rw-r--r-- | js/src/builtin/ModuleObject.h | 30 | ||||
-rw-r--r-- | js/src/builtin/SelfHostingDefines.h | 18 | ||||
-rw-r--r-- | js/src/builtin/Utilities.js | 19 | ||||
-rw-r--r-- | js/src/jit-test/tests/modules/ambiguous-star-export.js | 15 | ||||
-rw-r--r-- | js/src/jit-test/tests/modules/bad-namespace-created.js | 17 | ||||
-rw-r--r-- | js/src/jit-test/tests/modules/bug-1284486.js | 39 | ||||
-rw-r--r-- | js/src/jit-test/tests/modules/bug-1287410.js | 2 | ||||
-rw-r--r-- | js/src/jit-test/tests/modules/bug-1394492.js | 6 | ||||
-rw-r--r-- | js/src/jit-test/tests/modules/global-scope.js | 18 | ||||
-rw-r--r-- | js/src/jit-test/tests/modules/module-evaluation.js | 33 | ||||
-rw-r--r-- | js/src/js.msg | 2 | ||||
-rw-r--r-- | js/src/jsapi.cpp | 4 | ||||
-rw-r--r-- | js/src/vm/CommonPropertyNames.h | 4 | ||||
-rw-r--r-- | js/src/vm/SelfHosting.cpp | 19 |
16 files changed, 611 insertions, 217 deletions
diff --git a/js/src/builtin/Module.js b/js/src/builtin/Module.js index 5c3d5e147..064293670 100644 --- a/js/src/builtin/Module.js +++ b/js/src/builtin/Module.js @@ -2,11 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -function CallModuleResolveHook(module, specifier, expectedMinimumState) +function CallModuleResolveHook(module, specifier, expectedMinimumStatus) { let requestedModule = HostResolveImportedModule(module, specifier); - if (requestedModule.state < expectedMinimumState) - ThrowInternalError(JSMSG_BAD_MODULE_STATE); + if (requestedModule.state < expectedMinimumStatus) + ThrowInternalError(JSMSG_BAD_MODULE_STATUS); return requestedModule; } @@ -65,7 +65,36 @@ function ModuleGetExportedNames(exportStarSet = []) return exportedNames; } +function ModuleSetStatus(module, newStatus) +{ + assert(newStatus >= MODULE_STATUS_ERRORED && newStatus <= MODULE_STATUS_EVALUATED, + "Bad new module status in ModuleSetStatus"); + if (newStatus !== MODULE_STATUS_ERRORED) + assert(newStatus > module.status, "New module status inconsistent with current status"); + + UnsafeSetReservedSlot(module, MODULE_OBJECT_STATUS_SLOT, newStatus); +} + // 15.2.1.16.3 ResolveExport(exportName, resolveSet) +// +// Returns an object describing the location of the resolved export or +// indicating a failure. +// +// On success this returns: { resolved: true, module, bindingName } +// +// There are three failure cases: +// +// - The resolution failure can be blamed on a particular module. +// Returns: { resolved: false, module, ambiguous: false } +// +// - No culprit can be determined and the resolution failure was due to star +// export ambiguity. +// Returns: { resolved: false, module: null, ambiguous: true } +// +// - No culprit can be determined and the resolution failure was not due to +// star export ambiguity. +// Returns: { resolved: false, module: null, ambiguous: false } +// function ModuleResolveExport(exportName, resolveSet = []) { if (!IsObject(this) || !IsModule(this)) { @@ -77,88 +106,104 @@ function ModuleResolveExport(exportName, resolveSet = []) let module = this; // Step 2 + assert(module.status !== MODULE_STATUS_ERRORED, "Bad module status in ResolveExport"); + + // Step 3 for (let i = 0; i < resolveSet.length; i++) { let r = resolveSet[i]; - if (r.module === module && r.exportName === exportName) - return null; + if (r.module === module && r.exportName === exportName) { + // This is a circular import request. + return {resolved: false, module: null, ambiguous: false}; + } } - // Step 3 + // Step 4 _DefineDataProperty(resolveSet, resolveSet.length, {module: module, exportName: exportName}); - // Step 4 + // Step 5 let localExportEntries = module.localExportEntries; for (let i = 0; i < localExportEntries.length; i++) { let e = localExportEntries[i]; if (exportName === e.exportName) - return {module: module, bindingName: e.localName}; + return {resolved: true, module, bindingName: e.localName}; } - // Step 5 + // Step 6 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_PARSED); - return callFunction(importedModule.resolveExport, importedModule, e.importName, - resolveSet); + MODULE_STATUS_UNINSTANTIATED); + let resolution = callFunction(importedModule.resolveExport, importedModule, e.importName, + resolveSet); + if (!resolution.resolved && !resolution.module) + resolution.module = module; + return resolution; } } - // Step 6 + // Step 7 if (exportName === "default") { // A default export cannot be provided by an export *. - return null; + return {resolved: false, module: null, ambiguous: false}; } - // Step 7 + // Step 8 let starResolution = null; - // Step 8 + // Step 9 let starExportEntries = module.starExportEntries; for (let i = 0; i < starExportEntries.length; i++) { let e = starExportEntries[i]; let importedModule = CallModuleResolveHook(module, e.moduleRequest, - MODULE_STATE_PARSED); - let resolution = callFunction(importedModule.resolveExport, importedModule, - exportName, resolveSet); - if (resolution === "ambiguous") + MODULE_STATUS_UNINSTANTIATED); + let resolution = callFunction(importedModule.resolveExport, importedModule, exportName, + resolveSet); + if (!resolution.resolved && (resolution.module || resolution.ambiguous)) return resolution; - if (resolution !== null) { + if (resolution.resolved) { if (starResolution === null) { starResolution = resolution; } else { if (resolution.module !== starResolution.module || - resolution.exportName !== starResolution.exportName) + resolution.bindingName !== starResolution.bindingName) { - return "ambiguous"; + return {resolved: false, module: null, ambiguous: true}; } } } } - // Step 9 - return starResolution; + // Step 10 + if (starResolution !== null) + return starResolution; + + return {resolved: false, module: null, ambiguous: false}; } // 15.2.1.18 GetModuleNamespace(module) function GetModuleNamespace(module) { + // Step 1 + assert(IsModule(module), "GetModuleNamespace called with non-module"); + // Step 2 - let namespace = module.namespace; + assert(module.status !== MODULE_STATUS_UNINSTANTIATED && + module.status !== MODULE_STATUS_ERRORED, + "Bad module status in GetModuleNamespace"); // Step 3 + let namespace = module.namespace; + if (typeof namespace === "undefined") { let exportedNames = callFunction(module.getExportedNames, module); let unambiguousNames = []; for (let i = 0; i < exportedNames.length; i++) { let name = exportedNames[i]; let resolution = callFunction(module.resolveExport, module, name); - if (resolution === null) - ThrowSyntaxError(JSMSG_MISSING_NAMESPACE_EXPORT); - if (resolution !== "ambiguous") + if (resolution.resolved) _DefineDataProperty(unambiguousNames, unambiguousNames.length, name); } namespace = ModuleNamespaceCreate(module, unambiguousNames); @@ -180,7 +225,7 @@ function ModuleNamespaceCreate(module, exports) for (let i = 0; i < exports.length; i++) { let name = exports[i]; let binding = callFunction(module.resolveExport, module, name); - assert(binding !== null && binding !== "ambiguous", "Failed to resolve binding"); + assert(binding.resolved, "Failed to resolve binding"); AddModuleNamespaceBinding(ns, name, binding.module, binding.bindingName); } @@ -193,8 +238,8 @@ function GetModuleEnvironment(module) // Check for a previous failed attempt to instantiate this module. This can // only happen due to a bug in the module loader. - if (module.state == MODULE_STATE_FAILED) - ThrowInternalError(JSMSG_MODULE_INSTANTIATE_FAILED); + if (module.status === MODULE_STATUS_ERRORED) + ThrowInternalError(JSMSG_MODULE_INSTANTIATE_FAILED, module.status); let env = UnsafeGetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT); assert(env === undefined || IsModuleEnvironment(env), @@ -203,112 +248,396 @@ function GetModuleEnvironment(module) return env; } -function RecordInstantationFailure(module) +function RecordModuleError(module, error) { - // 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); + // Set the module's status to 'errored' to indicate a failed module + // instantiation and record the exception. The environment slot is also + // reset to 'undefined'. + + assert(IsObject(module) && IsModule(module), "Non-module passed to RecordModuleError"); + + ModuleSetStatus(module, MODULE_STATUS_ERRORED); + UnsafeSetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT, error); UnsafeSetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT, undefined); } -// 15.2.1.16.4 ModuleDeclarationInstantiation() -function ModuleDeclarationInstantiation() +function CountArrayValues(array, value) +{ + let count = 0; + for (let i = 0; i < array.length; i++) { + if (array[i] === value) + count++; + } + return count; +} + +function ArrayContains(array, value) +{ + for (let i = 0; i < array.length; i++) { + if (array[i] === value) + return true; + } + return false; +} + +// 15.2.1.16.4 ModuleInstantiate() +function ModuleInstantiate() { if (!IsObject(this) || !IsModule(this)) - return callFunction(CallModuleMethodIfWrapped, this, "ModuleDeclarationInstantiation"); + return callFunction(CallModuleMethodIfWrapped, this, "ModuleInstantiate"); // Step 1 let module = this; - // Step 5 - if (GetModuleEnvironment(module) !== undefined) - return; - - // Step 7 - CreateModuleEnvironment(module); - let env = GetModuleEnvironment(module); + // Step 2 + if (module.status === MODULE_STATUS_INSTANTIATING || + module.status === MODULE_STATUS_EVALUATING) + { + ThrowInternalError(JSMSG_BAD_MODULE_STATUS); + } - SetModuleState(this, MODULE_STATE_INSTANTIATED); + // Step 3 + let stack = []; + // Steps 4-5 try { - // Step 8 - let requestedModules = module.requestedModules; - for (let i = 0; i < requestedModules.length; i++) { - let required = requestedModules[i]; - let requiredModule = CallModuleResolveHook(module, required, MODULE_STATE_PARSED); - callFunction(requiredModule.declarationInstantiation, requiredModule); + InnerModuleDeclarationInstantiation(module, stack, 0); + } catch (error) { + for (let i = 0; i < stack.length; i++) { + let m = stack[i]; + + assert(m.status === MODULE_STATUS_INSTANTIATING || + m.status === MODULE_STATUS_ERRORED, + "Bad module status after failed instantiation"); + + RecordModuleError(m, error); } - // Step 9 - let indirectExportEntries = module.indirectExportEntries; - for (let i = 0; i < indirectExportEntries.length; i++) { - let e = indirectExportEntries[i]; - let resolution = callFunction(module.resolveExport, module, e.exportName); - if (resolution === null) - ThrowSyntaxError(JSMSG_MISSING_INDIRECT_EXPORT, e.exportName); - if (resolution === "ambiguous") - ThrowSyntaxError(JSMSG_AMBIGUOUS_INDIRECT_EXPORT, e.exportName); + if (stack.length === 0 && + typeof(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT)) === "undefined") + { + // This can happen due to OOM when appending to the stack. + assert(error === "out of memory", + "Stack must contain module unless we hit OOM"); + RecordModuleError(module, error); } - // Step 12 - let importEntries = module.importEntries; - for (let i = 0; i < importEntries.length; i++) { - let imp = importEntries[i]; - let importedModule = CallModuleResolveHook(module, imp.moduleRequest, - MODULE_STATE_INSTANTIATED); - if (imp.importName === "*") { - let namespace = GetModuleNamespace(importedModule); - 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); - } + assert(module.status === MODULE_STATUS_ERRORED, + "Bad module status after failed instantiation"); + assert(SameValue(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT), error), + "Module has different error set after failed instantiation"); + + throw error; + } + + // Step 6 + assert(module.status == MODULE_STATUS_INSTANTIATED || + module.status == MODULE_STATUS_EVALUATED, + "Bad module status after successful instantiation"); + + // Step 7 + assert(stack.length === 0, + "Stack should be empty after successful instantiation"); + + // Step 8 + return undefined; +} +_SetCanonicalName(ModuleInstantiate, "ModuleInstantiate"); + +// 15.2.1.16.4.1 InnerModuleDeclarationInstantiation(module, stack, index) +function InnerModuleDeclarationInstantiation(module, stack, index) +{ + // Step 1 + // TODO: Support module records other than source text module records. + + // Step 2 + if (module.status === MODULE_STATUS_INSTANTIATING || + module.status === MODULE_STATUS_INSTANTIATED || + module.status === MODULE_STATUS_EVALUATED) + { + return index; + } + + // Step 3 + if (module.status === MODULE_STATUS_ERRORED) + throw module.error; + + // Step 4 + assert(module.status === MODULE_STATUS_UNINSTANTIATED, + "Bad module status in ModuleDeclarationInstantiation"); + + // Steps 5 + ModuleSetStatus(module, MODULE_STATUS_INSTANTIATING); + + // Step 6-8 + UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_INDEX_SLOT, index); + UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT, index); + index++; + + // Step 9 + _DefineDataProperty(stack, stack.length, module); + + // Step 10 + let requestedModules = module.requestedModules; + for (let i = 0; i < requestedModules.length; i++) { + let required = requestedModules[i]; + let requiredModule = CallModuleResolveHook(module, required, MODULE_STATUS_ERRORED); + + index = InnerModuleDeclarationInstantiation(requiredModule, stack, index); + + assert(requiredModule.status === MODULE_STATUS_INSTANTIATING || + requiredModule.status === MODULE_STATUS_INSTANTIATED || + requiredModule.status === MODULE_STATUS_EVALUATED, + "Bad required module status after InnerModuleDeclarationInstantiation"); + + assert((requiredModule.status === MODULE_STATUS_INSTANTIATING) === + ArrayContains(stack, requiredModule), + "Required module should be in the stack iff it is currently being instantiated"); + + assert(typeof requiredModule.dfsIndex === "number", "Bad dfsIndex"); + assert(typeof requiredModule.dfsAncestorIndex === "number", "Bad dfsAncestorIndex"); + + if (requiredModule.status === MODULE_STATUS_INSTANTIATING) { + UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT, + std_Math_min(module.dfsAncestorIndex, + requiredModule.dfsAncestorIndex)); + } + } + + // Step 11 + ModuleDeclarationEnvironmentSetup(module); + + // Steps 12-13 + assert(CountArrayValues(stack, module) === 1, + "Current module should appear exactly once in the stack"); + assert(module.dfsAncestorIndex <= module.dfsIndex, + "Bad DFS ancestor index"); + + // Step 14 + if (module.dfsAncestorIndex === module.dfsIndex) { + let requiredModule; + do { + requiredModule = callFunction(std_Array_pop, stack); + ModuleSetStatus(requiredModule, MODULE_STATUS_INSTANTIATED); + } while (requiredModule !== module); + } + + // Step 15 + return index; +} + +// 15.2.1.16.4.2 ModuleDeclarationEnvironmentSetup(module) +function ModuleDeclarationEnvironmentSetup(module) +{ + // Step 1 + let indirectExportEntries = module.indirectExportEntries; + for (let i = 0; i < indirectExportEntries.length; i++) { + let e = indirectExportEntries[i]; + let resolution = callFunction(module.resolveExport, module, e.exportName); + assert(resolution.resolved || resolution.module, + "Unexpected failure to resolve export in ModuleDeclarationEnvironmentSetup"); + if (!resolution.resolved) + return ResolutionError(resolution, "indirectExport", e.exportName) + } + + // Steps 5-6 + CreateModuleEnvironment(module); + let env = GetModuleEnvironment(module); + + // Step 8 + let importEntries = module.importEntries; + for (let i = 0; i < importEntries.length; i++) { + let imp = importEntries[i]; + let importedModule = CallModuleResolveHook(module, imp.moduleRequest, + MODULE_STATUS_INSTANTIATING); + if (imp.importName === "*") { + let namespace = GetModuleNamespace(importedModule); + CreateNamespaceBinding(env, imp.localName, namespace); + } else { + let resolution = callFunction(importedModule.resolveExport, importedModule, + imp.importName); + if (!resolution.resolved && !resolution.module) + resolution.module = module; + + if (!resolution.resolved) + return ResolutionError(resolution, "import", imp.importName); + + CreateImportBinding(env, imp.localName, resolution.module, resolution.bindingName); } + } + + InstantiateModuleFunctionDeclarations(module); +} - // Step 17.a.iii - InstantiateModuleFunctionDeclarations(module); - } catch (e) { - RecordInstantationFailure(module); - throw e; +// 15.2.1.16.4.3 ResolutionError(module) +function ResolutionError(resolution, kind, name) +{ + let module = resolution.module; + assert(module !== null, + "Null module passed to ResolutionError"); + + assert(module.status === MODULE_STATUS_UNINSTANTIATED || + module.status === MODULE_STATUS_INSTANTIATING, + "Unexpected module status in ResolutionError"); + + assert(kind === "import" || kind === "indirectExport", + "Unexpected kind in ResolutionError"); + + let message; + if (kind === "import") { + message = resolution.ambiguous ? JSMSG_AMBIGUOUS_IMPORT + : JSMSG_MISSING_IMPORT; + } else { + message = resolution.ambiguous ? JSMSG_AMBIGUOUS_INDIRECT_EXPORT + : JSMSG_MISSING_INDIRECT_EXPORT; + } + + try { + ThrowSyntaxError(message, name); + } catch (error) { + RecordModuleError(module, error); + throw error; } } -_SetCanonicalName(ModuleDeclarationInstantiation, "ModuleDeclarationInstantiation"); -// 15.2.1.16.5 ModuleEvaluation() -function ModuleEvaluation() +// 15.2.1.16.5 ModuleEvaluate() +function ModuleEvaluate() { if (!IsObject(this) || !IsModule(this)) - return callFunction(CallModuleMethodIfWrapped, this, "ModuleEvaluation"); + return callFunction(CallModuleMethodIfWrapped, this, "ModuleEvaluatie"); // Step 1 let module = this; - if (module.state < MODULE_STATE_INSTANTIATED) - ThrowInternalError(JSMSG_BAD_MODULE_STATE); + // Step 2 + if (module.status !== MODULE_STATUS_ERRORED && + module.status !== MODULE_STATUS_INSTANTIATED && + module.status !== MODULE_STATUS_EVALUATED) + { + ThrowInternalError(JSMSG_BAD_MODULE_STATUS); + } + + // Step 3 + let stack = []; + + // Steps 4-5 + try { + InnerModuleEvaluation(module, stack, 0); + } catch (error) { + for (let i = 0; i < stack.length; i++) { + let m = stack[i]; + + assert(m.status === MODULE_STATUS_EVALUATING, + "Bad module status after failed evaluation"); + + RecordModuleError(m, error); + } + + if (stack.length === 0 && + typeof(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT)) === "undefined") + { + // This can happen due to OOM when appending to the stack. + assert(error === "out of memory", + "Stack must contain module unless we hit OOM"); + RecordModuleError(module, error); + } + + assert(module.status === MODULE_STATUS_ERRORED, + "Bad module status after failed evaluation"); + assert(SameValue(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT), error), + "Module has different error set after failed evaluation"); + + throw error; + } + + assert(module.status == MODULE_STATUS_EVALUATED, + "Bad module status after successful evaluation"); + assert(stack.length === 0, + "Stack should be empty after successful evaluation"); + + return undefined; +} +_SetCanonicalName(ModuleEvaluate, "ModuleEvaluate"); + +// 15.2.1.16.5.1 InnerModuleEvaluation(module, stack, index) +function InnerModuleEvaluation(module, stack, index) +{ + // Step 1 + // TODO: Support module records other than source text module records. + + // Step 2 + if (module.status === MODULE_STATUS_EVALUATING || + module.status === MODULE_STATUS_EVALUATED) + { + return index; + } + + // Step 3 + if (module.status === MODULE_STATUS_ERRORED) + throw module.error; // Step 4 - if (module.state == MODULE_STATE_EVALUATED) - return undefined; + assert(module.status === MODULE_STATUS_INSTANTIATED, + "Bad module status in ModuleEvaluation"); // Step 5 - SetModuleState(this, MODULE_STATE_EVALUATED); + ModuleSetStatus(module, MODULE_STATUS_EVALUATING); - // Step 6 + // Steps 6-8 + UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_INDEX_SLOT, index); + UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT, index); + index++; + + // Step 9 + _DefineDataProperty(stack, stack.length, module); + + // Step 10 let requestedModules = module.requestedModules; for (let i = 0; i < requestedModules.length; i++) { let required = requestedModules[i]; - let requiredModule = CallModuleResolveHook(module, required, MODULE_STATE_INSTANTIATED); - callFunction(requiredModule.evaluation, requiredModule); + let requiredModule = + CallModuleResolveHook(module, required, MODULE_STATUS_INSTANTIATED); + + index = InnerModuleEvaluation(requiredModule, stack, index); + + assert(requiredModule.status == MODULE_STATUS_EVALUATING || + requiredModule.status == MODULE_STATUS_EVALUATED, + "Bad module status after InnerModuleEvaluation"); + + assert((requiredModule.status === MODULE_STATUS_EVALUATING) === + ArrayContains(stack, requiredModule), + "Required module should be in the stack iff it is currently being evaluated"); + + assert(typeof requiredModule.dfsIndex === "number", "Bad dfsIndex"); + assert(typeof requiredModule.dfsAncestorIndex === "number", "Bad dfsAncestorIndex"); + + if (requiredModule.status === MODULE_STATUS_EVALUATING) { + UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT, + std_Math_min(module.dfsAncestorIndex, + requiredModule.dfsAncestorIndex)); + } + } + + // Step 11 + ExecuteModule(module); + + // Step 12 + assert(CountArrayValues(stack, module) === 1, + "Current module should appear exactly once in the stack"); + + // Step 13 + assert(module.dfsAncestorIndex <= module.dfsIndex, + "Bad DFS ancestor index"); + + // Step 14 + if (module.dfsAncestorIndex === module.dfsIndex) { + let requiredModule; + do { + requiredModule = callFunction(std_Array_pop, stack); + ModuleSetStatus(requiredModule, MODULE_STATUS_EVALUATED); + } while (requiredModule !== module); } - return EvaluateModule(module); + // Step 15 + return index; } -_SetCanonicalName(ModuleEvaluation, "ModuleEvaluation"); diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index b275cb968..0a836c75b 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -18,10 +18,11 @@ using namespace js; using namespace js::frontend; -static_assert(MODULE_STATE_FAILED < MODULE_STATE_PARSED && - MODULE_STATE_PARSED < MODULE_STATE_INSTANTIATED && - MODULE_STATE_INSTANTIATED < MODULE_STATE_EVALUATED, - "Module states are ordered incorrectly"); +static_assert(MODULE_STATUS_ERRORED < MODULE_STATUS_UNINSTANTIATED && + MODULE_STATUS_UNINSTANTIATED < MODULE_STATUS_INSTANTIATING && + MODULE_STATUS_INSTANTIATING < MODULE_STATUS_INSTANTIATED && + MODULE_STATUS_INSTANTIATED < MODULE_STATUS_EVALUATED, + "Module statuses are ordered incorrectly"); template<typename T, Value ValueGetter(const T* obj)> static bool @@ -42,7 +43,7 @@ ModuleValueGetter(JSContext* cx, unsigned argc, Value* vp) #define DEFINE_GETTER_FUNCTIONS(cls, name, slot) \ static Value \ cls##_##name##Value(const cls* obj) { \ - return obj->getFixedSlot(cls::slot); \ + return obj->getReservedSlot(cls::slot); \ } \ \ static bool \ @@ -564,7 +565,7 @@ ModuleObject::class_ = { ArrayObject& \ cls::name() const \ { \ - return getFixedSlot(cls::slot).toObject().as<ArrayObject>(); \ + return getReservedSlot(cls::slot).toObject().as<ArrayObject>(); \ } DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, requestedModules, RequestedModulesSlot) @@ -688,7 +689,7 @@ void ModuleObject::init(HandleScript script) { initReservedSlot(ScriptSlot, PrivateValue(script)); - initReservedSlot(StateSlot, Int32Value(MODULE_STATE_FAILED)); + initReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_ERRORED)); } void @@ -709,7 +710,7 @@ ModuleObject::initImportExportData(HandleArrayObject requestedModules, initReservedSlot(LocalExportEntriesSlot, ObjectValue(*localExportEntries)); initReservedSlot(IndirectExportEntriesSlot, ObjectValue(*indirectExportEntries)); initReservedSlot(StarExportEntriesSlot, ObjectValue(*starExportEntries)); - setReservedSlot(StateSlot, Int32Value(MODULE_STATE_PARSED)); + setReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_UNINSTANTIATED)); } static bool @@ -790,17 +791,24 @@ ModuleObject::script() const } static inline void -AssertValidModuleState(ModuleState state) +AssertValidModuleStatus(ModuleStatus status) { - MOZ_ASSERT(state >= MODULE_STATE_FAILED && state <= MODULE_STATE_EVALUATED); + MOZ_ASSERT(status >= MODULE_STATUS_ERRORED && status <= MODULE_STATUS_EVALUATED); } -ModuleState -ModuleObject::state() const +ModuleStatus +ModuleObject::status() const { - ModuleState state = getReservedSlot(StateSlot).toInt32(); - AssertValidModuleState(state); - return state; + ModuleStatus status = getReservedSlot(StatusSlot).toInt32(); + AssertValidModuleStatus(status); + return status; +} + +Value +ModuleObject::error() const +{ + MOZ_ASSERT(status() == MODULE_STATUS_ERRORED); + return getReservedSlot(ErrorSlot); } Value @@ -899,17 +907,8 @@ ModuleObject::instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject return true; } -void -ModuleObject::setState(int32_t newState) -{ - AssertValidModuleState(newState); - MOZ_ASSERT(state() != MODULE_STATE_FAILED); - MOZ_ASSERT(newState == MODULE_STATE_FAILED || newState > state()); - setReservedSlot(StateSlot, Int32Value(newState)); -} - /* static */ bool -ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValue rval) +ModuleObject::execute(JSContext* cx, HandleModuleObject self, MutableHandleValue rval) { MOZ_ASSERT(IsFrozen(cx, self)); @@ -959,36 +958,42 @@ InvokeSelfHostedMethod(JSContext* cx, HandleModuleObject self, HandlePropertyNam } /* static */ bool -ModuleObject::DeclarationInstantiation(JSContext* cx, HandleModuleObject self) +ModuleObject::Instantiate(JSContext* cx, HandleModuleObject self) { - return InvokeSelfHostedMethod(cx, self, cx->names().ModuleDeclarationInstantiation); + return InvokeSelfHostedMethod(cx, self, cx->names().ModuleInstantiate); } /* static */ bool -ModuleObject::Evaluation(JSContext* cx, HandleModuleObject self) +ModuleObject::Evaluate(JSContext* cx, HandleModuleObject self) { - return InvokeSelfHostedMethod(cx, self, cx->names().ModuleEvaluation); + return InvokeSelfHostedMethod(cx, self, cx->names().ModuleEvaluate); } DEFINE_GETTER_FUNCTIONS(ModuleObject, namespace_, NamespaceSlot) -DEFINE_GETTER_FUNCTIONS(ModuleObject, state, StateSlot) +DEFINE_GETTER_FUNCTIONS(ModuleObject, status, StatusSlot) +DEFINE_GETTER_FUNCTIONS(ModuleObject, error, ErrorSlot) DEFINE_GETTER_FUNCTIONS(ModuleObject, requestedModules, RequestedModulesSlot) DEFINE_GETTER_FUNCTIONS(ModuleObject, importEntries, ImportEntriesSlot) DEFINE_GETTER_FUNCTIONS(ModuleObject, localExportEntries, LocalExportEntriesSlot) DEFINE_GETTER_FUNCTIONS(ModuleObject, indirectExportEntries, IndirectExportEntriesSlot) DEFINE_GETTER_FUNCTIONS(ModuleObject, starExportEntries, StarExportEntriesSlot) +DEFINE_GETTER_FUNCTIONS(ModuleObject, dfsIndex, DFSIndexSlot) +DEFINE_GETTER_FUNCTIONS(ModuleObject, dfsAncestorIndex, DFSAncestorIndexSlot) /* static */ bool GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global) { static const JSPropertySpec protoAccessors[] = { JS_PSG("namespace", ModuleObject_namespace_Getter, 0), - JS_PSG("state", ModuleObject_stateGetter, 0), + JS_PSG("status", ModuleObject_statusGetter, 0), + JS_PSG("error", ModuleObject_errorGetter, 0), JS_PSG("requestedModules", ModuleObject_requestedModulesGetter, 0), JS_PSG("importEntries", ModuleObject_importEntriesGetter, 0), JS_PSG("localExportEntries", ModuleObject_localExportEntriesGetter, 0), JS_PSG("indirectExportEntries", ModuleObject_indirectExportEntriesGetter, 0), JS_PSG("starExportEntries", ModuleObject_starExportEntriesGetter, 0), + JS_PSG("dfsIndex", ModuleObject_dfsIndexGetter, 0), + JS_PSG("dfsAncestorIndex", ModuleObject_dfsAncestorIndexGetter, 0), JS_PS_END }; @@ -997,6 +1002,8 @@ GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global) 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_SELF_HOSTED_FN("declarationInstantiation", "ModuleInstantiate", 0, 0), + JS_SELF_HOSTED_FN("evaluation", "ModuleEvaluate", 0, 0), JS_FS_END }; diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index 22db762ac..365fcd4bf 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -192,8 +192,8 @@ struct FunctionDeclaration using FunctionDeclarationVector = GCVector<FunctionDeclaration, 0, ZoneAllocPolicy>; -// Possible values for ModuleState are defined in SelfHostingDefines.h. -using ModuleState = int32_t; +// Possible values for ModuleStatus are defined in SelfHostingDefines.h. +using ModuleStatus = int32_t; class ModuleObject : public NativeObject { @@ -204,7 +204,8 @@ class ModuleObject : public NativeObject InitialEnvironmentSlot, EnvironmentSlot, NamespaceSlot, - StateSlot, + StatusSlot, + ErrorSlot, HostDefinedSlot, RequestedModulesSlot, ImportEntriesSlot, @@ -215,11 +216,21 @@ class ModuleObject : public NativeObject NamespaceExportsSlot, NamespaceBindingsSlot, FunctionDeclarationsSlot, + DFSIndexSlot, + DFSAncestorIndexSlot, SlotCount }; static_assert(EnvironmentSlot == MODULE_OBJECT_ENVIRONMENT_SLOT, "EnvironmentSlot must match self-hosting define"); + static_assert(StatusSlot == MODULE_OBJECT_STATUS_SLOT, + "StatusSlot must match self-hosting define"); + static_assert(ErrorSlot == MODULE_OBJECT_ERROR_SLOT, + "ErrorSlot must match self-hosting define"); + static_assert(DFSIndexSlot == MODULE_OBJECT_DFS_INDEX_SLOT, + "DFSIndexSlot must match self-hosting define"); + static_assert(DFSAncestorIndexSlot == MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT, + "DFSAncestorIndexSlot must match self-hosting define"); static const Class class_; @@ -244,7 +255,8 @@ class ModuleObject : public NativeObject ModuleEnvironmentObject& initialEnvironment() const; ModuleEnvironmentObject* environment() const; ModuleNamespaceObject* namespace_(); - ModuleState state() const; + ModuleStatus status() const; + Value error() const; Value hostDefinedField() const; ArrayObject& requestedModules() const; ArrayObject& importEntries() const; @@ -255,8 +267,8 @@ class ModuleObject : public NativeObject JSObject* namespaceExports(); IndirectBindingMap* namespaceBindings(); - static bool DeclarationInstantiation(JSContext* cx, HandleModuleObject self); - static bool Evaluation(JSContext* cx, HandleModuleObject self); + static bool Instantiate(JSContext* cx, HandleModuleObject self); + static bool Evaluate(JSContext* cx, HandleModuleObject self); void setHostDefinedField(const JS::Value& value); @@ -269,10 +281,8 @@ class ModuleObject : public NativeObject // For intrinsic_InstantiateModuleFunctionDeclarations. static bool instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject self); - void setState(ModuleState newState); - - // For intrinsic_EvaluateModule. - static bool evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValue rval); + // For intrinsic_ExecuteModule. + static bool execute(JSContext* cx, HandleModuleObject self, MutableHandleValue rval); // For intrinsic_NewModuleNamespace. static ModuleNamespaceObject* createNamespace(JSContext* cx, HandleModuleObject self, diff --git a/js/src/builtin/SelfHostingDefines.h b/js/src/builtin/SelfHostingDefines.h index 117ac7ffd..a06c2aa62 100644 --- a/js/src/builtin/SelfHostingDefines.h +++ b/js/src/builtin/SelfHostingDefines.h @@ -97,11 +97,17 @@ #define REGEXP_STRING_ITERATOR_FLAGS_SLOT 2 #define REGEXP_STRING_ITERATOR_DONE_SLOT 3 -#define MODULE_OBJECT_ENVIRONMENT_SLOT 2 - -#define MODULE_STATE_FAILED 0 -#define MODULE_STATE_PARSED 1 -#define MODULE_STATE_INSTANTIATED 2 -#define MODULE_STATE_EVALUATED 3 +#define MODULE_OBJECT_ENVIRONMENT_SLOT 2 +#define MODULE_OBJECT_STATUS_SLOT 4 +#define MODULE_OBJECT_ERROR_SLOT 5 +#define MODULE_OBJECT_DFS_INDEX_SLOT 16 +#define MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT 17 + +#define MODULE_STATUS_ERRORED 0 +#define MODULE_STATUS_UNINSTANTIATED 1 +#define MODULE_STATUS_INSTANTIATING 2 +#define MODULE_STATUS_INSTANTIATED 3 +#define MODULE_STATUS_EVALUATING 4 +#define MODULE_STATUS_EVALUATED 5 #endif diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index d5f233d05..3916311db 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -27,13 +27,20 @@ // Assertions and debug printing, defined here instead of in the header above // to make `assert` invisible to C++. #ifdef DEBUG -#define assert(b, info) if (!(b)) AssertionFailed(__FILE__ + ":" + __LINE__ + ": " + info) -#define dbg(msg) DumpMessage(callFunction(std_Array_pop, \ - StringSplitString(__FILE__, '/')) \ - + '#' + __LINE__ + ': ' + msg) +#define assert(b, info) \ + do { \ + if (!(b)) \ + AssertionFailed(__FILE__ + ":" + __LINE__ + ": " + info) \ + } while (false) +#define dbg(msg) \ + do { \ + DumpMessage(callFunction(std_Array_pop, \ + StringSplitString(__FILE__, '/')) + \ + '#' + __LINE__ + ': ' + msg) \ + } while (false) #else -#define assert(b, info) // Elided assertion. -#define dbg(msg) // Elided debugging output. +#define assert(b, info) do {} while (false) // Elided assertion. +#define dbg(msg) do {} while (false) // Elided debugging output. #endif // All C++-implemented standard builtins library functions used in self-hosted diff --git a/js/src/jit-test/tests/modules/ambiguous-star-export.js b/js/src/jit-test/tests/modules/ambiguous-star-export.js index b8c91445c..94aa7ac4a 100644 --- a/js/src/jit-test/tests/modules/ambiguous-star-export.js +++ b/js/src/jit-test/tests/modules/ambiguous-star-export.js @@ -5,10 +5,11 @@ load(libdir + "asserts.js"); load(libdir + "dummyModuleResolveHook.js"); -function checkModuleEval(source, result) { +function checkModuleEval(source) { let m = parseModule(source); m.declarationInstantiation(); - assertEq(m.evaluation(), result); + m.evaluation(); + return m; } function checkModuleSyntaxError(source) { @@ -23,17 +24,19 @@ c.declarationInstantiation(); c.evaluation(); // Check importing/exporting non-ambiguous name works. -checkModuleEval("import { a } from 'c'; a;", 1); -checkModuleEval("export { a } from 'c';", undefined); +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'; ns;"); +let m = parseModule("import * as ns from 'c';"); m.declarationInstantiation(); -let ns = m.evaluation(); +m.evaluation(); +let ns = c.namespace; let names = Object.keys(ns); assertEq(names.length, 2); assertEq('a' in ns, true); 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 000000000..127892d6e --- /dev/null +++ b/js/src/jit-test/tests/modules/bad-namespace-created.js @@ -0,0 +1,17 @@ +// 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");
+load(libdir + "dummyModuleResolveHook.js");
+
+moduleRepo['A'] = parseModule('import "B"; export {x} from "C"');
+moduleRepo['B'] = parseModule('import * as a from "A"');
+moduleRepo['C'] = parseModule('export * from "D"; export * from "E"');
+moduleRepo['D'] = parseModule('export let x');
+moduleRepo['E'] = parseModule('export let x');
+
+let m = moduleRepo['A'];
+assertThrowsInstanceOf(() => m.declarationInstantiation(), SyntaxError);
diff --git a/js/src/jit-test/tests/modules/bug-1284486.js b/js/src/jit-test/tests/modules/bug-1284486.js index 9a3244ec3..08286393a 100644 --- a/js/src/jit-test/tests/modules/bug-1284486.js +++ b/js/src/jit-test/tests/modules/bug-1284486.js @@ -1,23 +1,36 @@ -// |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. +// time after a failure re-throws the same error. // // 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]; -}); +load(libdir + "dummyModuleResolveHook.js"); + +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 e1; +let threw = false; 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) {} +} catch (exc) { + threw = true; + e1 = exc; +} +assertEq(threw, true); +assertEq(typeof e1 === "undefined", false); + 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(); + +threw = false; +let e2; +try { + d.declarationInstantiation(); +} catch (exc) { + threw = true; + e2 = exc; +} +assertEq(threw, true); +assertEq(e1, e2); diff --git a/js/src/jit-test/tests/modules/bug-1287410.js b/js/src/jit-test/tests/modules/bug-1287410.js index 8a891372a..7df5621a5 100644 --- a/js/src/jit-test/tests/modules/bug-1287410.js +++ b/js/src/jit-test/tests/modules/bug-1287410.js @@ -20,3 +20,5 @@ 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(); +d.evaluation(); + diff --git a/js/src/jit-test/tests/modules/bug-1394492.js b/js/src/jit-test/tests/modules/bug-1394492.js new file mode 100644 index 000000000..a0e5d2ac3 --- /dev/null +++ b/js/src/jit-test/tests/modules/bug-1394492.js @@ -0,0 +1,6 @@ +// |jit-test| error: NaN +let m = parseModule(` + throw i => { return 5; }, m-1; +`); +m.declarationInstantiation(); +m.evaluation(); diff --git a/js/src/jit-test/tests/modules/global-scope.js b/js/src/jit-test/tests/modules/global-scope.js index 90a9f7026..b99019fa8 100644 --- a/js/src/jit-test/tests/modules/global-scope.js +++ b/js/src/jit-test/tests/modules/global-scope.js @@ -1,32 +1,34 @@ // Test interaction with global object and global lexical scope. -function parseAndEvaluate(source) { +function evalModuleAndCheck(source, expected) { let m = parseModule(source); m.declarationInstantiation(); - return m.evaluation(); + m.evaluation(); + assertEq(getModuleEnvironmentValue(m, "r"), expected); } var x = 1; -assertEq(parseAndEvaluate("let r = x; x = 2; r"), 1); +evalModuleAndCheck("export let r = x; x = 2;", 1); assertEq(x, 2); let y = 3; -assertEq(parseAndEvaluate("let r = y; y = 4; r"), 3); +evalModuleAndCheck("export let r = y; y = 4;", 3); assertEq(y, 4); if (helperThreadCount() == 0) quit(); -function offThreadParseAndEvaluate(source) { +function offThreadEvalModuleAndCheck(source, expected) { offThreadCompileModule(source); let m = finishOffThreadModule(); print("compiled"); m.declarationInstantiation(); - return m.evaluation(); + m.evaluation(); + assertEq(getModuleEnvironmentValue(m, "r"), expected); } -assertEq(offThreadParseAndEvaluate("let r = x; x = 5; r"), 2); +offThreadEvalModuleAndCheck("export let r = x; x = 5;", 2); assertEq(x, 5); -assertEq(offThreadParseAndEvaluate("let r = y; y = 6; r"), 4); +offThreadEvalModuleAndCheck("export let r = y; y = 6;", 4); assertEq(y, 6); diff --git a/js/src/jit-test/tests/modules/module-evaluation.js b/js/src/jit-test/tests/modules/module-evaluation.js index eec13c040..84d88f19c 100644 --- a/js/src/jit-test/tests/modules/module-evaluation.js +++ b/js/src/jit-test/tests/modules/module-evaluation.js @@ -6,16 +6,17 @@ load(libdir + "dummyModuleResolveHook.js"); function parseAndEvaluate(source) { let m = parseModule(source); m.declarationInstantiation(); - return m.evaluation(); + m.evaluation(); + return m; } // Check the evaluation of an empty module succeeds. -assertEq(typeof parseAndEvaluate(""), "undefined"); +parseAndEvaluate(""); // Check evaluation returns evaluation result the first time, then undefined. let m = parseModule("1"); m.declarationInstantiation(); -assertEq(m.evaluation(), 1); +assertEq(m.evaluation(), undefined); assertEq(typeof m.evaluation(), "undefined"); // Check top level variables are initialized by evaluation. @@ -60,31 +61,35 @@ parseAndEvaluate("export default class { constructor() {} };"); parseAndEvaluate("export default class foo { constructor() {} };"); // Test default import -m = parseModule("import a from 'a'; a;") +m = parseModule("import a from 'a'; export { a };") m.declarationInstantiation(); -assertEq(m.evaluation(), 2); +m.evaluation(); +assertEq(getModuleEnvironmentValue(m, "a"), 2); // Test named import -m = parseModule("import { x as y } from 'a'; y;") +m = parseModule("import { x as y } from 'a'; export { y };") m.declarationInstantiation(); -assertEq(m.evaluation(), 1); +m.evaluation(); +assertEq(getModuleEnvironmentValue(m, "y"), 1); // Call exported function -m = parseModule("import { f } from 'a'; f(3);") +m = parseModule("import { f } from 'a'; export let x = f(3);") m.declarationInstantiation(); -assertEq(m.evaluation(), 4); +m.evaluation(); +assertEq(getModuleEnvironmentValue(m, "x"), 4); // Test importing an indirect export moduleRepo['b'] = parseModule("export { x as z } from 'a';"); -assertEq(parseAndEvaluate("import { z } from 'b'; z"), 1); +m = parseAndEvaluate("import { z } from 'b'; export { z }"); +assertEq(getModuleEnvironmentValue(m, "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]); +m = 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]); // Import access in functions m = parseModule("import { x } from 'a'; function f() { return x; }") diff --git a/js/src/js.msg b/js/src/js.msg index 9dc5f4e9f..ee74c8dd5 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -580,7 +580,7 @@ MSG_DEF(JSMSG_AMBIGUOUS_IMPORT, 1, JSEXN_SYNTAXERR, "ambiguous import ' MSG_DEF(JSMSG_MISSING_NAMESPACE_EXPORT, 0, JSEXN_SYNTAXERR, "export not found for namespace") MSG_DEF(JSMSG_MISSING_EXPORT, 1, JSEXN_SYNTAXERR, "local binding for export '{0}' not found") MSG_DEF(JSMSG_MODULE_INSTANTIATE_FAILED, 0, JSEXN_INTERNALERR, "attempt to re-instantiate module after failure") -MSG_DEF(JSMSG_BAD_MODULE_STATE, 0, JSEXN_INTERNALERR, "module record in unexpected state") +MSG_DEF(JSMSG_BAD_MODULE_STATUS, 0, JSEXN_INTERNALERR, "module record has unexpected status") // Promise MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.") diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index d75a3c33a..53ea4ebc6 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4709,7 +4709,7 @@ JS::ModuleDeclarationInstantiation(JSContext* cx, JS::HandleObject moduleArg) AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, moduleArg); - return ModuleObject::DeclarationInstantiation(cx, moduleArg.as<ModuleObject>()); + return ModuleObject::Instantiate(cx, moduleArg.as<ModuleObject>()); } JS_PUBLIC_API(bool) @@ -4718,7 +4718,7 @@ JS::ModuleEvaluation(JSContext* cx, JS::HandleObject moduleArg) AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, moduleArg); - return ModuleObject::Evaluation(cx, moduleArg.as<ModuleObject>()); + return ModuleObject::Evaluate(cx, moduleArg.as<ModuleObject>()); } JS_PUBLIC_API(JSObject*) diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index b4a2de6f3..aa555886e 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -227,8 +227,8 @@ macro(missingArguments, missingArguments, "missingArguments") \ macro(module, module, "module") \ macro(Module, Module, "Module") \ - macro(ModuleDeclarationInstantiation, ModuleDeclarationInstantiation, "ModuleDeclarationInstantiation") \ - macro(ModuleEvaluation, ModuleEvaluation, "ModuleEvaluation") \ + macro(ModuleInstantiate, ModuleInstantiate, "ModuleInstantiate") \ + macro(ModuleEvaluate, ModuleEvaluate, "ModuleEvaluate") \ macro(month, month, "month") \ macro(multiline, multiline, "multiline") \ macro(name, name, "name") \ diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 2216bf91e..89750d61a 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2060,24 +2060,12 @@ intrinsic_InstantiateModuleFunctionDeclarations(JSContext* cx, unsigned argc, Va } static bool -intrinsic_SetModuleState(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 2); - RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>()); - ModuleState newState = args[1].toInt32(); - module->setState(newState); - args.rval().setUndefined(); - return true; -} - -static bool -intrinsic_EvaluateModule(JSContext* cx, unsigned argc, Value* vp) +intrinsic_ExecuteModule(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); MOZ_ASSERT(args.length() == 1); RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>()); - return ModuleObject::evaluate(cx, module, args.rval()); + return ModuleObject::execute(cx, module, args.rval()); } static bool @@ -2630,8 +2618,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("CreateNamespaceBinding", intrinsic_CreateNamespaceBinding, 3, 0), JS_FN("InstantiateModuleFunctionDeclarations", intrinsic_InstantiateModuleFunctionDeclarations, 1, 0), - JS_FN("SetModuleState", intrinsic_SetModuleState, 1, 0), - JS_FN("EvaluateModule", intrinsic_EvaluateModule, 1, 0), + JS_FN("ExecuteModule", intrinsic_ExecuteModule, 1, 0), JS_FN("NewModuleNamespace", intrinsic_NewModuleNamespace, 2, 0), JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0), JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0), |