From 3f25d0c8e4d9296f0d45c85c251eab71f076937b Mon Sep 17 00:00:00 2001 From: Moonchild Date: Fri, 3 Jul 2020 13:56:49 +0000 Subject: Issue #618 - Align module instantiation/errors with the updated spec. Store and re-throw module instantiation and evaluation errors. Ref: BZ 1374239, 1394492 --- js/src/builtin/Module.js | 533 +++++++++++++++++++++++++++++------- js/src/builtin/ModuleObject.cpp | 69 ++--- js/src/builtin/ModuleObject.h | 30 +- js/src/builtin/SelfHostingDefines.h | 18 +- js/src/builtin/Utilities.js | 19 +- 5 files changed, 514 insertions(+), 155 deletions(-) (limited to 'js/src/builtin') 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 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(); \ + return getReservedSlot(cls::slot).toObject().as(); \ } 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 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 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; -// 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 -- cgit v1.2.3