зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1374239 - Store and re-throw module instantiation and evaluation errors r=shu
This commit is contained in:
Родитель
02dc1567cd
Коммит
a634315ceb
|
@ -1,12 +1,13 @@
|
|||
/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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, expectedMinimumState)
|
||||
function CallModuleResolveHook(module, specifier, expectedMinimumStatus)
|
||||
{
|
||||
let requestedModule = HostResolveImportedModule(module, specifier);
|
||||
if (requestedModule.state < expectedMinimumState)
|
||||
ThrowInternalError(JSMSG_BAD_MODULE_STATE);
|
||||
if (requestedModule.status < expectedMinimumStatus)
|
||||
ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
|
||||
|
||||
return requestedModule;
|
||||
}
|
||||
|
@ -52,7 +53,7 @@ function ModuleGetExportedNames(exportStarSet = [])
|
|||
for (let i = 0; i < starExportEntries.length; i++) {
|
||||
let e = starExportEntries[i];
|
||||
let requestedModule = CallModuleResolveHook(module, e.moduleRequest,
|
||||
MODULE_STATE_INSTANTIATED);
|
||||
MODULE_STATUS_INSTANTIATING);
|
||||
let starNames = callFunction(requestedModule.getExportedNames, requestedModule,
|
||||
exportStarSet);
|
||||
for (let j = 0; j < starNames.length; j++) {
|
||||
|
@ -65,7 +66,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,76 +107,94 @@ function ModuleResolveExport(exportName, resolveSet = [])
|
|||
let module = this;
|
||||
|
||||
// Step 2
|
||||
for (let i = 0; i < resolveSet.length; i++) {
|
||||
let r = resolveSet[i];
|
||||
if (r.module === module && r.exportName === exportName)
|
||||
return null;
|
||||
}
|
||||
assert(module.status !== MODULE_STATUS_ERRORED, "Bad module state in ResolveExport");
|
||||
|
||||
// Step 3
|
||||
_DefineDataProperty(resolveSet, resolveSet.length, {module, exportName});
|
||||
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, exportName});
|
||||
|
||||
// Step 5
|
||||
let localExportEntries = module.localExportEntries;
|
||||
for (let i = 0; i < localExportEntries.length; i++) {
|
||||
let e = localExportEntries[i];
|
||||
if (exportName === e.exportName)
|
||||
return {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
|
||||
assert(module.status !== MODULE_STATUS_UNINSTANTIATED &&
|
||||
module.status !== MODULE_STATUS_ERRORED,
|
||||
"Bad module state in GetModuleNamespace");
|
||||
|
||||
// Step 3
|
||||
let namespace = module.namespace;
|
||||
|
||||
// Step 3
|
||||
|
@ -156,9 +204,7 @@ function GetModuleNamespace(module)
|
|||
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 +226,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 +239,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 +249,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)
|
||||
{
|
||||
if (!IsObject(this) || !IsModule(this))
|
||||
return callFunction(CallModuleMethodIfWrapped, this, "ModuleDeclarationInstantiation");
|
||||
|
||||
// Step 1
|
||||
let module = this;
|
||||
|
||||
// Step 5
|
||||
if (GetModuleEnvironment(module) !== undefined)
|
||||
return undefined;
|
||||
|
||||
// Step 7
|
||||
CreateModuleEnvironment(module);
|
||||
let env = GetModuleEnvironment(module);
|
||||
|
||||
SetModuleState(this, MODULE_STATE_INSTANTIATED);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 17.a.iii
|
||||
InstantiateModuleFunctionDeclarations(module);
|
||||
} catch (e) {
|
||||
RecordInstantationFailure(module);
|
||||
throw e;
|
||||
let count = 0;
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (array[i] === value)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
_SetCanonicalName(ModuleDeclarationInstantiation, "ModuleDeclarationInstantiation");
|
||||
|
||||
// 15.2.1.16.5 ModuleEvaluation()
|
||||
function ModuleEvaluation()
|
||||
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, "ModuleEvaluation");
|
||||
return callFunction(CallModuleMethodIfWrapped, this, "ModuleInstantiate");
|
||||
|
||||
// Step 1
|
||||
let module = this;
|
||||
|
||||
if (module.state < MODULE_STATE_INSTANTIATED)
|
||||
ThrowInternalError(JSMSG_BAD_MODULE_STATE);
|
||||
// Step 2
|
||||
if (module.status === MODULE_STATUS_INSTANTIATING ||
|
||||
module.status === MODULE_STATUS_EVALUATING)
|
||||
{
|
||||
ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
|
||||
}
|
||||
|
||||
// Step 4
|
||||
if (module.state == MODULE_STATE_EVALUATED)
|
||||
return undefined;
|
||||
// Step 3
|
||||
let stack = [];
|
||||
|
||||
// Step 5
|
||||
SetModuleState(this, MODULE_STATE_EVALUATED);
|
||||
// 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(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_STATE_INSTANTIATED);
|
||||
callFunction(requiredModule.evaluation, requiredModule);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
return EvaluateModule(module);
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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(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;
|
||||
}
|
||||
_SetCanonicalName(ModuleEvaluation, "ModuleEvaluation");
|
||||
|
|
|
@ -20,10 +20,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
|
||||
|
@ -44,7 +45,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 \
|
||||
|
@ -571,7 +572,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)
|
||||
|
@ -632,6 +633,8 @@ ModuleObject::finalize(js::FreeOp* fop, JSObject* obj)
|
|||
ModuleEnvironmentObject*
|
||||
ModuleObject::environment() const
|
||||
{
|
||||
MOZ_ASSERT(status() != MODULE_STATUS_ERRORED);
|
||||
|
||||
Value value = getReservedSlot(EnvironmentSlot);
|
||||
if (value.isUndefined())
|
||||
return nullptr;
|
||||
|
@ -695,7 +698,7 @@ void
|
|||
ModuleObject::init(HandleScript script)
|
||||
{
|
||||
initReservedSlot(ScriptSlot, PrivateValue(script));
|
||||
initReservedSlot(StateSlot, Int32Value(MODULE_STATE_FAILED));
|
||||
initReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_ERRORED));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -716,7 +719,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
|
||||
|
@ -797,17 +800,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
|
||||
|
@ -915,17 +925,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));
|
||||
|
||||
|
@ -975,44 +976,50 @@ 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
|
||||
};
|
||||
|
||||
static const JSFunctionSpec protoFunctions[] = {
|
||||
JS_SELF_HOSTED_FN("getExportedNames", "ModuleGetExportedNames", 1, 0),
|
||||
JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 2, 0),
|
||||
JS_SELF_HOSTED_FN("declarationInstantiation", "ModuleDeclarationInstantiation", 0, 0),
|
||||
JS_SELF_HOSTED_FN("evaluation", "ModuleEvaluation", 0, 0),
|
||||
JS_SELF_HOSTED_FN("declarationInstantiation", "ModuleInstantiate", 0, 0),
|
||||
JS_SELF_HOSTED_FN("evaluation", "ModuleEvaluate", 0, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -93,12 +93,18 @@
|
|||
#define REGEXP_STICKY_FLAG 0x08
|
||||
#define REGEXP_UNICODE_FLAG 0x10
|
||||
|
||||
#define MODULE_OBJECT_ENVIRONMENT_SLOT 2
|
||||
#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_STATE_FAILED 0
|
||||
#define MODULE_STATE_PARSED 1
|
||||
#define MODULE_STATE_INSTANTIATED 2
|
||||
#define MODULE_STATE_EVALUATED 3
|
||||
#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
|
||||
|
||||
#define STRING_GENERICS_CHAR_AT 0
|
||||
#define STRING_GENERICS_CHAR_CODE_AT 1
|
||||
|
|
|
@ -28,13 +28,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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
|
@ -1,9 +1,5 @@
|
|||
// |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.
|
||||
|
@ -11,14 +7,29 @@
|
|||
// This test exercises the path where the previously instantiated module is
|
||||
// re-instantiated directly.
|
||||
|
||||
let moduleRepo = {};
|
||||
setModuleResolveHook(function(module, specifier) {
|
||||
return moduleRepo[specifier];
|
||||
});
|
||||
let c;
|
||||
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;");
|
||||
c = moduleRepo['c'] = parseModule("export * from 'a'; export * from 'b';");
|
||||
c.declarationInstantiation();
|
||||
} catch (exc) {}
|
||||
c.declarationInstantiation();
|
||||
} catch (exc) {
|
||||
threw = true;
|
||||
e1 = exc;
|
||||
}
|
||||
assertEq(threw, true);
|
||||
assertEq(typeof e1 === "undefined", false);
|
||||
|
||||
threw = false;
|
||||
let e2;
|
||||
try {
|
||||
c.declarationInstantiation();
|
||||
} catch (exc) {
|
||||
threw = true;
|
||||
e2 = exc;
|
||||
}
|
||||
assertEq(threw, true);
|
||||
assertEq(e1, e2);
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
// |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
|
||||
|
@ -12,15 +8,32 @@
|
|||
// This test exercises the path where the previously instantiated module is
|
||||
// encountered as an import.
|
||||
|
||||
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);
|
||||
|
|
|
@ -20,3 +20,4 @@ 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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; }")
|
||||
|
|
|
@ -586,7 +586,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.")
|
||||
|
|
|
@ -4876,7 +4876,7 @@ JS::ModuleDeclarationInstantiation(JSContext* cx, JS::HandleObject moduleArg)
|
|||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, moduleArg);
|
||||
return ModuleObject::DeclarationInstantiation(cx, moduleArg.as<ModuleObject>());
|
||||
return ModuleObject::Instantiate(cx, moduleArg.as<ModuleObject>());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
|
@ -4885,7 +4885,7 @@ JS::ModuleEvaluation(JSContext* cx, JS::HandleObject moduleArg)
|
|||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, moduleArg);
|
||||
return ModuleObject::Evaluation(cx, moduleArg.as<ModuleObject>());
|
||||
return ModuleObject::Evaluate(cx, moduleArg.as<ModuleObject>());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* 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/. */
|
||||
|
|
|
@ -238,8 +238,8 @@
|
|||
macro(mode, mode, "mode") \
|
||||
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") \
|
||||
|
|
|
@ -1982,24 +1982,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
|
||||
|
@ -2566,8 +2554,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),
|
||||
|
|
Загрузка…
Ссылка в новой задаче