649 lines
22 KiB
JavaScript
649 lines
22 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* 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, expectedMinimumStatus)
|
|
{
|
|
let requestedModule = HostResolveImportedModule(module, specifier);
|
|
if (requestedModule.state < expectedMinimumStatus)
|
|
ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
|
|
|
|
return requestedModule;
|
|
}
|
|
|
|
// 15.2.1.16.2 GetExportedNames(exportStarSet)
|
|
function ModuleGetExportedNames(exportStarSet = [])
|
|
{
|
|
if (!IsObject(this) || !IsModule(this)) {
|
|
return callFunction(CallModuleMethodIfWrapped, this, exportStarSet,
|
|
"ModuleGetExportedNames");
|
|
}
|
|
|
|
// Step 1
|
|
let module = this;
|
|
|
|
// Step 2
|
|
if (callFunction(ArrayIncludes, exportStarSet, module))
|
|
return [];
|
|
|
|
// Step 3
|
|
_DefineDataProperty(exportStarSet, exportStarSet.length, module);
|
|
|
|
// Step 4
|
|
let exportedNames = [];
|
|
let namesCount = 0;
|
|
|
|
// Step 5
|
|
let localExportEntries = module.localExportEntries;
|
|
for (let i = 0; i < localExportEntries.length; i++) {
|
|
let e = localExportEntries[i];
|
|
_DefineDataProperty(exportedNames, namesCount++, e.exportName);
|
|
}
|
|
|
|
// Step 6
|
|
let indirectExportEntries = module.indirectExportEntries;
|
|
for (let i = 0; i < indirectExportEntries.length; i++) {
|
|
let e = indirectExportEntries[i];
|
|
_DefineDataProperty(exportedNames, namesCount++, e.exportName);
|
|
}
|
|
|
|
// Step 7
|
|
let starExportEntries = module.starExportEntries;
|
|
for (let i = 0; i < starExportEntries.length; i++) {
|
|
let e = starExportEntries[i];
|
|
let requestedModule = CallModuleResolveHook(module, e.moduleRequest,
|
|
MODULE_STATE_INSTANTIATED);
|
|
let starNames = callFunction(requestedModule.getExportedNames, requestedModule,
|
|
exportStarSet);
|
|
for (let j = 0; j < starNames.length; j++) {
|
|
let n = starNames[j];
|
|
if (n !== "default" && !callFunction(ArrayIncludes, exportedNames, n))
|
|
_DefineDataProperty(exportedNames, namesCount++, n);
|
|
}
|
|
}
|
|
|
|
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)) {
|
|
return callFunction(CallModuleMethodIfWrapped, this, exportName, resolveSet,
|
|
"ModuleResolveExport");
|
|
}
|
|
|
|
// Step 1
|
|
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) {
|
|
// This is a circular import request.
|
|
return {resolved: false, module: null, ambiguous: false};
|
|
}
|
|
}
|
|
|
|
// Step 4
|
|
_DefineDataProperty(resolveSet, resolveSet.length, {module: module, exportName: exportName});
|
|
|
|
// Step 5
|
|
let localExportEntries = module.localExportEntries;
|
|
for (let i = 0; i < localExportEntries.length; i++) {
|
|
let e = localExportEntries[i];
|
|
if (exportName === e.exportName)
|
|
return {resolved: true, module, bindingName: e.localName};
|
|
}
|
|
|
|
// 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_STATUS_UNINSTANTIATED);
|
|
let resolution = callFunction(importedModule.resolveExport, importedModule, e.importName,
|
|
resolveSet);
|
|
if (!resolution.resolved && !resolution.module)
|
|
resolution.module = module;
|
|
return resolution;
|
|
}
|
|
}
|
|
|
|
// Step 7
|
|
if (exportName === "default") {
|
|
// A default export cannot be provided by an export *.
|
|
return {resolved: false, module: null, ambiguous: false};
|
|
}
|
|
|
|
// Step 8
|
|
let starResolution = null;
|
|
|
|
// 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_STATUS_UNINSTANTIATED);
|
|
let resolution = callFunction(importedModule.resolveExport, importedModule, exportName,
|
|
resolveSet);
|
|
if (!resolution.resolved && (resolution.module || resolution.ambiguous))
|
|
return resolution;
|
|
|
|
if (resolution.resolved) {
|
|
if (starResolution === null) {
|
|
starResolution = resolution;
|
|
} else {
|
|
if (resolution.module !== starResolution.module ||
|
|
resolution.bindingName !== starResolution.bindingName)
|
|
{
|
|
return {resolved: false, module: null, ambiguous: true};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
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.resolved)
|
|
_DefineDataProperty(unambiguousNames, unambiguousNames.length, name);
|
|
}
|
|
namespace = ModuleNamespaceCreate(module, unambiguousNames);
|
|
}
|
|
|
|
// Step 4
|
|
return namespace;
|
|
}
|
|
|
|
// 9.4.6.13 ModuleNamespaceCreate(module, exports)
|
|
function ModuleNamespaceCreate(module, exports)
|
|
{
|
|
callFunction(std_Array_sort, exports);
|
|
|
|
let ns = NewModuleNamespace(module, exports);
|
|
|
|
// Pre-compute all bindings now rather than calling ResolveExport() on every
|
|
// access.
|
|
for (let i = 0; i < exports.length; i++) {
|
|
let name = exports[i];
|
|
let binding = callFunction(module.resolveExport, module, name);
|
|
assert(binding.resolved, "Failed to resolve binding");
|
|
AddModuleNamespaceBinding(ns, name, binding.module, binding.bindingName);
|
|
}
|
|
|
|
return ns;
|
|
}
|
|
|
|
function GetModuleEnvironment(module)
|
|
{
|
|
assert(IsModule(module), "Non-module passed to GetModuleEnvironment");
|
|
|
|
// Check for a previous failed attempt to instantiate this module. This can
|
|
// only happen due to a bug in the module loader.
|
|
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),
|
|
"Module environment slot contains unexpected value");
|
|
|
|
return env;
|
|
}
|
|
|
|
function RecordModuleError(module, error)
|
|
{
|
|
// 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);
|
|
}
|
|
|
|
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, "ModuleInstantiate");
|
|
|
|
// Step 1
|
|
let module = this;
|
|
|
|
// Step 2
|
|
if (module.status === MODULE_STATUS_INSTANTIATING ||
|
|
module.status === MODULE_STATUS_EVALUATING)
|
|
{
|
|
ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
|
|
}
|
|
|
|
// Step 3
|
|
let stack = [];
|
|
|
|
// Steps 4-5
|
|
try {
|
|
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);
|
|
}
|
|
|
|
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 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,
|
|
e.lineNumber, e.columnNumber)
|
|
}
|
|
}
|
|
|
|
// 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,
|
|
imp.lineNumber, imp.columnNumber);
|
|
}
|
|
|
|
CreateImportBinding(env, imp.localName, resolution.module, resolution.bindingName);
|
|
}
|
|
}
|
|
|
|
InstantiateModuleFunctionDeclarations(module);
|
|
}
|
|
|
|
// 15.2.1.16.4.3 ResolutionError(module)
|
|
function ResolutionError(resolution, kind, name, line, column)
|
|
{
|
|
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");
|
|
|
|
assert(line > 0,
|
|
"Line number should be present for all imports and indirect exports");
|
|
|
|
let errorNumber;
|
|
if (kind === "import") {
|
|
errorNumber = resolution.ambiguous ? JSMSG_AMBIGUOUS_IMPORT
|
|
: JSMSG_MISSING_IMPORT;
|
|
} else {
|
|
errorNumber = resolution.ambiguous ? JSMSG_AMBIGUOUS_INDIRECT_EXPORT
|
|
: JSMSG_MISSING_INDIRECT_EXPORT;
|
|
}
|
|
|
|
let message = GetErrorMessage(errorNumber) + ": " + name;
|
|
let error = CreateModuleSyntaxError(module, line, column, message);
|
|
RecordModuleError(module, error);
|
|
throw error;
|
|
}
|
|
|
|
// 15.2.1.16.5 ModuleEvaluate()
|
|
function ModuleEvaluate()
|
|
{
|
|
if (!IsObject(this) || !IsModule(this))
|
|
return callFunction(CallModuleMethodIfWrapped, this, "ModuleEvaluate");
|
|
|
|
// Step 1
|
|
let module = this;
|
|
|
|
// 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
|
|
assert(module.status === MODULE_STATUS_INSTANTIATED,
|
|
"Bad module status in ModuleEvaluation");
|
|
|
|
// Step 5
|
|
ModuleSetStatus(module, MODULE_STATUS_EVALUATING);
|
|
|
|
// 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_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);
|
|
}
|
|
|
|
// Step 15
|
|
return index;
|
|
}
|