summaryrefslogtreecommitdiffstats
path: root/js/src/builtin/Module.js
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2020-07-03 13:56:49 +0000
committerMoonchild <moonchild@palemoon.org>2020-07-10 18:29:33 +0000
commit3f25d0c8e4d9296f0d45c85c251eab71f076937b (patch)
tree2d5d342b0ea6f7b7cfcedc6bf3349ca3ff6cf418 /js/src/builtin/Module.js
parentab0501702637f3448ec16a188a050e5b9f688787 (diff)
downloadUXP-3f25d0c8e4d9296f0d45c85c251eab71f076937b.tar
UXP-3f25d0c8e4d9296f0d45c85c251eab71f076937b.tar.gz
UXP-3f25d0c8e4d9296f0d45c85c251eab71f076937b.tar.lz
UXP-3f25d0c8e4d9296f0d45c85c251eab71f076937b.tar.xz
UXP-3f25d0c8e4d9296f0d45c85c251eab71f076937b.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/src/builtin/Module.js')
-rw-r--r--js/src/builtin/Module.js533
1 files changed, 431 insertions, 102 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");