Implement module type scripting.
parent
68fc602db6
commit
ef217a94a8
|
@ -308,17 +308,18 @@ nsJSUtils::CompileModule(JSContext* aCx,
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsJSUtils::ModuleDeclarationInstantiation(JSContext* aCx, JS::Handle<JSObject*> aModule)
|
nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSObject*> aModule)
|
||||||
{
|
{
|
||||||
PROFILER_LABEL("nsJSUtils", "ModuleDeclarationInstantiation",
|
PROFILER_LABEL("nsJSUtils", "ModuleInstantiate",
|
||||||
js::ProfileEntry::Category::JS);
|
js::ProfileEntry::Category::JS);
|
||||||
|
|
||||||
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
|
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(nsContentUtils::IsInMicroTask());
|
||||||
|
|
||||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
|
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
|
||||||
|
|
||||||
if (!JS::ModuleDeclarationInstantiation(aCx, aModule)) {
|
if (!JS::ModuleInstantiate(aCx, aModule)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,9 +327,9 @@ nsJSUtils::ModuleDeclarationInstantiation(JSContext* aCx, JS::Handle<JSObject*>
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsJSUtils::ModuleEvaluation(JSContext* aCx, JS::Handle<JSObject*> aModule)
|
nsJSUtils::ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule)
|
||||||
{
|
{
|
||||||
PROFILER_LABEL("nsJSUtils", "ModuleEvaluation",
|
PROFILER_LABEL("nsJSUtils", "ModuleEvaluate",
|
||||||
js::ProfileEntry::Category::JS);
|
js::ProfileEntry::Category::JS);
|
||||||
|
|
||||||
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
|
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
|
||||||
|
@ -338,7 +339,7 @@ nsJSUtils::ModuleEvaluation(JSContext* aCx, JS::Handle<JSObject*> aModule)
|
||||||
|
|
||||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
|
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
|
||||||
|
|
||||||
if (!JS::ModuleEvaluation(aCx, aModule)) {
|
if (!JS::ModuleEvaluate(aCx, aModule)) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,11 +116,11 @@ public:
|
||||||
JS::CompileOptions &aCompileOptions,
|
JS::CompileOptions &aCompileOptions,
|
||||||
JS::MutableHandle<JSObject*> aModule);
|
JS::MutableHandle<JSObject*> aModule);
|
||||||
|
|
||||||
static nsresult ModuleDeclarationInstantiation(JSContext* aCx,
|
static nsresult ModuleInstantiate(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aModule);
|
JS::Handle<JSObject*> aModule);
|
||||||
|
|
||||||
static nsresult ModuleEvaluation(JSContext* aCx,
|
static nsresult ModuleEvaluate(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aModule);
|
JS::Handle<JSObject*> aModule);
|
||||||
|
|
||||||
// Returns false if an exception got thrown on aCx. Passing a null
|
// Returns false if an exception got thrown on aCx. Passing a null
|
||||||
// aElement is allowed; that wil produce an empty aScopeChain.
|
// aElement is allowed; that wil produce an empty aScopeChain.
|
||||||
|
|
|
@ -4,20 +4,27 @@
|
||||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var wasRun = false;
|
var wasRun = false;
|
||||||
var hadSyntaxError = false;
|
var errorCount = 0;
|
||||||
|
var syntaxErrorCount = 0;
|
||||||
|
var eventCount = 0;
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
window.onerror = handleError;
|
window.onerror = handleError;
|
||||||
|
|
||||||
function handleError(message, url, line, column, error) {
|
function handleError(message, url, line, column, error) {
|
||||||
hadSyntaxError = error instanceof SyntaxError;
|
errorCount++;
|
||||||
|
if (error instanceof SyntaxError) {
|
||||||
|
syntaxErrorCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function testError() {
|
function testError() {
|
||||||
ok(!wasRun, 'Check script was not run');
|
ok(!wasRun, 'Check script was not run');
|
||||||
ok(hadSyntaxError, 'Check that a SyntaxError was thrown');
|
ok(errorCount == 1, 'Check that an error was reported');
|
||||||
|
ok(syntaxErrorCount == 1, 'Check that a syntax error was reported');
|
||||||
|
ok(eventCount == 0, 'Check that no error event was fired');
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script type="module" src="module_badSyntax.js"></script>
|
<script type="module" src="module_badSyntax.js" onerror="eventCount++"></script>
|
||||||
<body onload='testError()'></body>
|
<body onload='testError()'></body>
|
||||||
|
|
|
@ -4,20 +4,27 @@
|
||||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var wasRun = false;
|
var wasRun = false;
|
||||||
var hadSyntaxError = false;
|
var errorCount = 0;
|
||||||
|
var syntaxErrorCount = 0;
|
||||||
|
var eventCount = 0;
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
window.onerror = handleError;
|
window.onerror = handleError;
|
||||||
|
|
||||||
function handleError(message, url, line, column, error) {
|
function handleError(message, url, line, column, error) {
|
||||||
hadSyntaxError = error instanceof SyntaxError;
|
errorCount++;
|
||||||
|
if (error instanceof SyntaxError) {
|
||||||
|
syntaxErrorCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function testError() {
|
function testError() {
|
||||||
ok(!wasRun, 'Check script was not run');
|
ok(!wasRun, 'Check script was not run');
|
||||||
ok(hadSyntaxError, 'Check that a SyntaxError was thrown');
|
ok(errorCount == 1, 'Check that an error was reported');
|
||||||
|
ok(syntaxErrorCount == 1, 'Check that a syntax error was reported');
|
||||||
|
ok(eventCount == 0, 'Check that no error event was fired');
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script type="module" src="module_badSyntax.js" async></script>
|
<script type="module" src="module_badSyntax.js" async onerror="eventCount++"></script>
|
||||||
<body onload='testError()'></body>
|
<body onload='testError()'></body>
|
||||||
|
|
|
@ -4,22 +4,29 @@
|
||||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var wasRun = false;
|
var wasRun = false;
|
||||||
var hadSyntaxError = false;
|
var errorCount = 0;
|
||||||
|
var syntaxErrorCount = 0;
|
||||||
|
var eventCount = 0;
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
window.onerror = handleError;
|
window.onerror = handleError;
|
||||||
|
|
||||||
function handleError(message, url, line, column, error) {
|
function handleError(message, url, line, column, error) {
|
||||||
hadSyntaxError = error instanceof SyntaxError;
|
errorCount++;
|
||||||
|
if (error instanceof SyntaxError) {
|
||||||
|
syntaxErrorCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function testError() {
|
function testError() {
|
||||||
ok(!wasRun, 'Check script was not run');
|
ok(!wasRun, 'Check script was not run');
|
||||||
ok(hadSyntaxError, 'Check that a SyntaxError was thrown');
|
ok(errorCount == 1, 'Check that an error was reported');
|
||||||
|
ok(syntaxErrorCount == 1, 'Check that a syntax error was reported');
|
||||||
|
ok(eventCount == 0, 'Check that no error event was fired');
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script type="module">
|
<script type="module" onerror="eventCount++">
|
||||||
// Module with a syntax error.
|
// Module with a syntax error.
|
||||||
some invalid js syntax;
|
some invalid js syntax;
|
||||||
wasRun = true;
|
wasRun = true;
|
||||||
|
|
|
@ -4,22 +4,29 @@
|
||||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var wasRun = false;
|
var wasRun = false;
|
||||||
var hadSyntaxError = false;
|
var errorCount = 0;
|
||||||
|
var syntaxErrorCount = 0;
|
||||||
|
var eventCount = 0;
|
||||||
|
|
||||||
SimpleTest.waitForExplicitFinish();
|
SimpleTest.waitForExplicitFinish();
|
||||||
window.onerror = handleError;
|
window.onerror = handleError;
|
||||||
|
|
||||||
function handleError(message, url, line, column, error) {
|
function handleError(message, url, line, column, error) {
|
||||||
hadSyntaxError = error instanceof SyntaxError;
|
errorCount++;
|
||||||
|
if (error instanceof SyntaxError) {
|
||||||
|
syntaxErrorCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function testError() {
|
function testError() {
|
||||||
ok(!wasRun, 'Check script was not run');
|
ok(!wasRun, 'Check script was not run');
|
||||||
ok(hadSyntaxError, 'Check that a SyntaxError was thrown');
|
ok(errorCount == 1, 'Check that an error was reported');
|
||||||
|
ok(syntaxErrorCount == 1, 'Check that a syntax error was reported');
|
||||||
|
ok(eventCount == 0, 'Check that no error event was fired');
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script type="module" async>
|
<script type="module" async onerror="eventCount++">
|
||||||
// Module with a syntax error.
|
// Module with a syntax error.
|
||||||
some invalid js syntax;
|
some invalid js syntax;
|
||||||
wasRun = true;
|
wasRun = true;
|
||||||
|
|
|
@ -43,15 +43,29 @@ void ModuleLoadRequest::Cancel()
|
||||||
ScriptLoadRequest::Cancel();
|
ScriptLoadRequest::Cancel();
|
||||||
mModuleScript = nullptr;
|
mModuleScript = nullptr;
|
||||||
mProgress = ScriptLoadRequest::Progress::Ready;
|
mProgress = ScriptLoadRequest::Progress::Ready;
|
||||||
|
CancelImports();
|
||||||
|
mReady.RejectIfExists(NS_ERROR_DOM_ABORT_ERR, __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModuleLoadRequest::CancelImports()
|
||||||
|
{
|
||||||
for (size_t i = 0; i < mImports.Length(); i++) {
|
for (size_t i = 0; i < mImports.Length(); i++) {
|
||||||
mImports[i]->Cancel();
|
mImports[i]->Cancel();
|
||||||
}
|
}
|
||||||
mReady.RejectIfExists(NS_ERROR_FAILURE, __func__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ModuleLoadRequest::SetReady()
|
ModuleLoadRequest::SetReady()
|
||||||
{
|
{
|
||||||
|
// Mark a module as ready to execute. This means that this module and all it
|
||||||
|
// dependencies have had their source loaded, parsed as a module and the
|
||||||
|
// modules instantiated.
|
||||||
|
//
|
||||||
|
// The mReady promise is used to ensure that when all dependencies of a module
|
||||||
|
// have become ready, DependenciesLoaded is called on that module
|
||||||
|
// request. This is set up in StartFetchingModuleDependencies.
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
for (size_t i = 0; i < mImports.Length(); i++) {
|
for (size_t i = 0; i < mImports.Length(); i++) {
|
||||||
MOZ_ASSERT(mImports[i]->IsReadyToRun());
|
MOZ_ASSERT(mImports[i]->IsReadyToRun());
|
||||||
|
@ -69,30 +83,53 @@ ModuleLoadRequest::ModuleLoaded()
|
||||||
// been loaded.
|
// been loaded.
|
||||||
|
|
||||||
mModuleScript = mLoader->GetFetchedModule(mURI);
|
mModuleScript = mLoader->GetFetchedModule(mURI);
|
||||||
|
if (!mModuleScript || mModuleScript->IsErrored()) {
|
||||||
|
ModuleErrored();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mLoader->StartFetchingModuleDependencies(this);
|
mLoader->StartFetchingModuleDependencies(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModuleLoadRequest::ModuleErrored()
|
||||||
|
{
|
||||||
|
mLoader->CheckModuleDependenciesLoaded(this);
|
||||||
|
MOZ_ASSERT(!mModuleScript || mModuleScript->IsErrored());
|
||||||
|
|
||||||
|
CancelImports();
|
||||||
|
SetReady();
|
||||||
|
LoadFinished();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ModuleLoadRequest::DependenciesLoaded()
|
ModuleLoadRequest::DependenciesLoaded()
|
||||||
{
|
{
|
||||||
// The module and all of its dependencies have been successfully fetched and
|
// The module and all of its dependencies have been successfully fetched and
|
||||||
// compiled.
|
// compiled.
|
||||||
|
|
||||||
if (!mLoader->InstantiateModuleTree(this)) {
|
MOZ_ASSERT(mModuleScript);
|
||||||
LoadFailed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
mLoader->CheckModuleDependenciesLoaded(this);
|
||||||
SetReady();
|
SetReady();
|
||||||
mLoader->ProcessLoadedModuleTree(this);
|
LoadFinished();
|
||||||
mLoader = nullptr;
|
|
||||||
mParent = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ModuleLoadRequest::LoadFailed()
|
ModuleLoadRequest::LoadFailed()
|
||||||
{
|
{
|
||||||
|
// We failed to load the source text or an error occurred unrelated to the
|
||||||
|
// content of the module (e.g. OOM).
|
||||||
|
|
||||||
|
MOZ_ASSERT(!mModuleScript);
|
||||||
|
|
||||||
Cancel();
|
Cancel();
|
||||||
|
LoadFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModuleLoadRequest::LoadFinished()
|
||||||
|
{
|
||||||
mLoader->ProcessLoadedModuleTree(this);
|
mLoader->ProcessLoadedModuleTree(this);
|
||||||
mLoader = nullptr;
|
mLoader = nullptr;
|
||||||
mParent = nullptr;
|
mParent = nullptr;
|
||||||
|
|
|
@ -45,9 +45,15 @@ public:
|
||||||
void Cancel() override;
|
void Cancel() override;
|
||||||
|
|
||||||
void ModuleLoaded();
|
void ModuleLoaded();
|
||||||
|
void ModuleErrored();
|
||||||
void DependenciesLoaded();
|
void DependenciesLoaded();
|
||||||
void LoadFailed();
|
void LoadFailed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void LoadFinished();
|
||||||
|
void CancelImports();
|
||||||
|
|
||||||
|
public:
|
||||||
// Is this a request for a top level module script or an import?
|
// Is this a request for a top level module script or an import?
|
||||||
bool mIsTopLevel;
|
bool mIsTopLevel;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
|
||||||
tmp->UnlinkModuleRecord();
|
tmp->UnlinkModuleRecord();
|
||||||
|
tmp->mError.setUndefined();
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
|
||||||
|
@ -34,28 +35,20 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mException)
|
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mError)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
|
||||||
|
|
||||||
ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL,
|
ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL)
|
||||||
JS::Handle<JSObject*> aModuleRecord)
|
|
||||||
: mLoader(aLoader),
|
: mLoader(aLoader),
|
||||||
mBaseURL(aBaseURL),
|
mBaseURL(aBaseURL)
|
||||||
mModuleRecord(aModuleRecord),
|
|
||||||
mInstantiationState(Uninstantiated)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mLoader);
|
MOZ_ASSERT(mLoader);
|
||||||
MOZ_ASSERT(mBaseURL);
|
MOZ_ASSERT(mBaseURL);
|
||||||
MOZ_ASSERT(mModuleRecord);
|
MOZ_ASSERT(!mModuleRecord);
|
||||||
MOZ_ASSERT(mException.isUndefined());
|
MOZ_ASSERT(mError.isUndefined());
|
||||||
|
|
||||||
// Make module's host defined field point to this module script object.
|
|
||||||
// This is cleared in the UnlinkModuleRecord().
|
|
||||||
JS::SetModuleHostDefinedField(mModuleRecord, JS::PrivateValue(this));
|
|
||||||
HoldJSObjects(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -66,34 +59,63 @@ ModuleScript::UnlinkModuleRecord()
|
||||||
MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
|
MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
|
||||||
this);
|
this);
|
||||||
JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
|
JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
|
||||||
|
mModuleRecord = nullptr;
|
||||||
}
|
}
|
||||||
mModuleRecord = nullptr;
|
|
||||||
mException.setUndefined();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleScript::~ModuleScript()
|
ModuleScript::~ModuleScript()
|
||||||
{
|
{
|
||||||
if (mModuleRecord) {
|
// The object may be destroyed without being unlinked first.
|
||||||
// The object may be destroyed without being unlinked first.
|
UnlinkModuleRecord();
|
||||||
UnlinkModuleRecord();
|
|
||||||
}
|
|
||||||
DropJSObjects(this);
|
DropJSObjects(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ModuleScript::SetInstantiationResult(JS::Handle<JS::Value> aMaybeException)
|
ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mInstantiationState == Uninstantiated);
|
MOZ_ASSERT(!mModuleRecord);
|
||||||
MOZ_ASSERT(mModuleRecord);
|
MOZ_ASSERT(mError.isUndefined());
|
||||||
MOZ_ASSERT(mException.isUndefined());
|
|
||||||
|
|
||||||
if (aMaybeException.isUndefined()) {
|
mModuleRecord = aModuleRecord;
|
||||||
mInstantiationState = Instantiated;
|
|
||||||
} else {
|
// Make module's host defined field point to this module script object.
|
||||||
mModuleRecord = nullptr;
|
// This is cleared in the UnlinkModuleRecord().
|
||||||
mException = aMaybeException;
|
JS::SetModuleHostDefinedField(mModuleRecord, JS::PrivateValue(this));
|
||||||
mInstantiationState = Errored;
|
HoldJSObjects(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ModuleScript::SetPreInstantiationError(const JS::Value& aError)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!aError.isUndefined());
|
||||||
|
|
||||||
|
UnlinkModuleRecord();
|
||||||
|
mError = aError;
|
||||||
|
|
||||||
|
HoldJSObjects(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ModuleScript::IsErrored() const
|
||||||
|
{
|
||||||
|
if (!mModuleRecord) {
|
||||||
|
MOZ_ASSERT(!mError.isUndefined());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return JS::IsModuleErrored(mModuleRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::Value
|
||||||
|
ModuleScript::Error() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(IsErrored());
|
||||||
|
|
||||||
|
if (!mModuleRecord) {
|
||||||
|
return mError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JS::GetModuleError(mModuleRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // dom namespace
|
} // dom namespace
|
||||||
|
|
|
@ -20,17 +20,10 @@ class ScriptLoader;
|
||||||
|
|
||||||
class ModuleScript final : public nsISupports
|
class ModuleScript final : public nsISupports
|
||||||
{
|
{
|
||||||
enum InstantiationState {
|
|
||||||
Uninstantiated,
|
|
||||||
Instantiated,
|
|
||||||
Errored
|
|
||||||
};
|
|
||||||
|
|
||||||
RefPtr<ScriptLoader> mLoader;
|
RefPtr<ScriptLoader> mLoader;
|
||||||
nsCOMPtr<nsIURI> mBaseURL;
|
nsCOMPtr<nsIURI> mBaseURL;
|
||||||
JS::Heap<JSObject*> mModuleRecord;
|
JS::Heap<JSObject*> mModuleRecord;
|
||||||
JS::Heap<JS::Value> mException;
|
JS::Heap<JS::Value> mError;
|
||||||
InstantiationState mInstantiationState;
|
|
||||||
|
|
||||||
~ModuleScript();
|
~ModuleScript();
|
||||||
|
|
||||||
|
@ -39,24 +32,17 @@ public:
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript)
|
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript)
|
||||||
|
|
||||||
ModuleScript(ScriptLoader* aLoader,
|
ModuleScript(ScriptLoader* aLoader,
|
||||||
nsIURI* aBaseURL,
|
nsIURI* aBaseURL);
|
||||||
JS::Handle<JSObject*> aModuleRecord);
|
|
||||||
|
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
|
||||||
|
void SetPreInstantiationError(const JS::Value& aError);
|
||||||
|
|
||||||
ScriptLoader* Loader() const { return mLoader; }
|
ScriptLoader* Loader() const { return mLoader; }
|
||||||
JSObject* ModuleRecord() const { return mModuleRecord; }
|
JSObject* ModuleRecord() const { return mModuleRecord; }
|
||||||
JS::Value Exception() const { return mException; }
|
|
||||||
nsIURI* BaseURL() const { return mBaseURL; }
|
nsIURI* BaseURL() const { return mBaseURL; }
|
||||||
|
|
||||||
void SetInstantiationResult(JS::Handle<JS::Value> aMaybeException);
|
bool IsErrored() const;
|
||||||
bool IsUninstantiated() const {
|
JS::Value Error() const;
|
||||||
return mInstantiationState == Uninstantiated;
|
|
||||||
}
|
|
||||||
bool IsInstantiated() const {
|
|
||||||
return mInstantiationState == Instantiated;
|
|
||||||
}
|
|
||||||
bool InstantiationFailed() const {
|
|
||||||
return mInstantiationState == Errored;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnlinkModuleRecord();
|
void UnlinkModuleRecord();
|
||||||
};
|
};
|
||||||
|
|
|
@ -418,21 +418,23 @@ void
|
||||||
ScriptLoader::SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *aRequest,
|
ScriptLoader::SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *aRequest,
|
||||||
nsresult aResult)
|
nsresult aResult)
|
||||||
{
|
{
|
||||||
// Update module map with the result of fetching a single module script. The
|
// Update module map with the result of fetching a single module script.
|
||||||
// module script pointer is nullptr on error.
|
//
|
||||||
|
// If any requests for the same URL are waiting on this one to complete, they
|
||||||
MOZ_ASSERT(!aRequest->IsReadyToRun());
|
// will have ModuleLoaded or LoadFailed on them when the promise is
|
||||||
|
// resolved/rejected. This is set up in StartLoad.
|
||||||
|
|
||||||
RefPtr<GenericPromise::Private> promise;
|
RefPtr<GenericPromise::Private> promise;
|
||||||
MOZ_ALWAYS_TRUE(mFetchingModules.Get(aRequest->mURI, getter_AddRefs(promise)));
|
MOZ_ALWAYS_TRUE(mFetchingModules.Get(aRequest->mURI, getter_AddRefs(promise)));
|
||||||
mFetchingModules.Remove(aRequest->mURI);
|
mFetchingModules.Remove(aRequest->mURI);
|
||||||
|
|
||||||
RefPtr<ModuleScript> ms(aRequest->mModuleScript);
|
RefPtr<ModuleScript> moduleScript(aRequest->mModuleScript);
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(aResult) == (ms != nullptr));
|
MOZ_ASSERT(NS_FAILED(aResult) == !moduleScript);
|
||||||
mFetchedModules.Put(aRequest->mURI, ms);
|
|
||||||
|
mFetchedModules.Put(aRequest->mURI, moduleScript);
|
||||||
|
|
||||||
if (promise) {
|
if (promise) {
|
||||||
if (ms) {
|
if (moduleScript) {
|
||||||
promise->Resolve(true, __func__);
|
promise->Resolve(true, __func__);
|
||||||
} else {
|
} else {
|
||||||
promise->Reject(aResult, __func__);
|
promise->Reject(aResult, __func__);
|
||||||
|
@ -478,19 +480,29 @@ ScriptLoader::ProcessFetchedModuleSource(ModuleLoadRequest* aRequest)
|
||||||
MOZ_ASSERT(!aRequest->mModuleScript);
|
MOZ_ASSERT(!aRequest->mModuleScript);
|
||||||
|
|
||||||
nsresult rv = CreateModuleScript(aRequest);
|
nsresult rv = CreateModuleScript(aRequest);
|
||||||
|
MOZ_ASSERT(NS_FAILED(rv) == !aRequest->mModuleScript);
|
||||||
|
|
||||||
SetModuleFetchFinishedAndResumeWaitingRequests(aRequest, rv);
|
SetModuleFetchFinishedAndResumeWaitingRequests(aRequest, rv);
|
||||||
|
|
||||||
free(aRequest->mScriptTextBuf);
|
free(aRequest->mScriptTextBuf);
|
||||||
aRequest->mScriptTextBuf = nullptr;
|
aRequest->mScriptTextBuf = nullptr;
|
||||||
aRequest->mScriptTextLength = 0;
|
aRequest->mScriptTextLength = 0;
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
aRequest->LoadFailed();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aRequest->mModuleScript->IsErrored()) {
|
||||||
StartFetchingModuleDependencies(aRequest);
|
StartFetchingModuleDependencies(aRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nsresult
|
||||||
|
ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>& aUrls);
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
||||||
{
|
{
|
||||||
|
@ -544,9 +556,34 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
|
MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
|
||||||
if (module) {
|
RefPtr<ModuleScript> moduleScript = new ModuleScript(this, aRequest->mBaseURL);
|
||||||
aRequest->mModuleScript =
|
aRequest->mModuleScript = moduleScript;
|
||||||
new ModuleScript(this, aRequest->mBaseURL, module);
|
|
||||||
|
if (!module) {
|
||||||
|
// Compilation failed
|
||||||
|
MOZ_ASSERT(aes.HasException());
|
||||||
|
JS::Rooted<JS::Value> error(cx);
|
||||||
|
if (!aes.StealException(&error)) {
|
||||||
|
aRequest->mModuleScript = nullptr;
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleScript->SetPreInstantiationError(error);
|
||||||
|
aRequest->ModuleErrored();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleScript->SetModuleRecord(module);
|
||||||
|
|
||||||
|
// Validate requested modules and treat failure to resolve module specifiers
|
||||||
|
// the same as a parse error.
|
||||||
|
nsCOMArray<nsIURI> urls;
|
||||||
|
rv = ResolveRequestedModules(aRequest, urls);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
// ResolveRequestedModules sets pre-instanitation error on failure.
|
||||||
|
MOZ_ASSERT(moduleScript->IsErrored());
|
||||||
|
aRequest->ModuleErrored();
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,8 +593,8 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
ThrowTypeError(JSContext* aCx, ModuleScript* aScript,
|
CreateTypeError(JSContext* aCx, ModuleScript* aScript, const nsString& aMessage,
|
||||||
const nsString& aMessage)
|
JS::MutableHandle<JS::Value> aError)
|
||||||
{
|
{
|
||||||
JS::Rooted<JSObject*> module(aCx, aScript->ModuleRecord());
|
JS::Rooted<JSObject*> module(aCx, aScript->ModuleRecord());
|
||||||
JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aCx, module));
|
JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aCx, module));
|
||||||
|
@ -572,17 +609,11 @@ ThrowTypeError(JSContext* aCx, ModuleScript* aScript,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Rooted<JS::Value> error(aCx);
|
return JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, filename, 0, 0, nullptr,
|
||||||
if (!JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, filename, 0, 0, nullptr,
|
message, aError);
|
||||||
message, &error)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_SetPendingException(aCx, error);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static nsresult
|
||||||
HandleResolveFailure(JSContext* aCx, ModuleScript* aScript,
|
HandleResolveFailure(JSContext* aCx, ModuleScript* aScript,
|
||||||
const nsAString& aSpecifier)
|
const nsAString& aSpecifier)
|
||||||
{
|
{
|
||||||
|
@ -591,19 +622,13 @@ HandleResolveFailure(JSContext* aCx, ModuleScript* aScript,
|
||||||
nsAutoString message(NS_LITERAL_STRING("Error resolving module specifier: "));
|
nsAutoString message(NS_LITERAL_STRING("Error resolving module specifier: "));
|
||||||
message.Append(aSpecifier);
|
message.Append(aSpecifier);
|
||||||
|
|
||||||
return ThrowTypeError(aCx, aScript, message);
|
JS::Rooted<JS::Value> error(aCx);
|
||||||
}
|
if (!CreateTypeError(aCx, aScript, message, &error)) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
aScript->SetPreInstantiationError(error);
|
||||||
HandleModuleNotFound(JSContext* aCx, ModuleScript* aScript,
|
return NS_OK;
|
||||||
const nsAString& aSpecifier)
|
|
||||||
{
|
|
||||||
// TODO: How can we get the line number of the failed import?
|
|
||||||
|
|
||||||
nsAutoString message(NS_LITERAL_STRING("Resolved module not found in map: "));
|
|
||||||
message.Append(aSpecifier);
|
|
||||||
|
|
||||||
return ThrowTypeError(aCx, aScript, message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static already_AddRefed<nsIURI>
|
static already_AddRefed<nsIURI>
|
||||||
|
@ -701,7 +726,8 @@ ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls)
|
||||||
ModuleScript* ms = aRequest->mModuleScript;
|
ModuleScript* ms = aRequest->mModuleScript;
|
||||||
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(ms, specifier);
|
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(ms, specifier);
|
||||||
if (!uri) {
|
if (!uri) {
|
||||||
HandleResolveFailure(cx, ms, specifier);
|
nsresult rv = HandleResolveFailure(cx, ms, specifier);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,13 +746,15 @@ void
|
||||||
ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest)
|
ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aRequest->mModuleScript);
|
MOZ_ASSERT(aRequest->mModuleScript);
|
||||||
|
MOZ_ASSERT(!aRequest->mModuleScript->IsErrored());
|
||||||
MOZ_ASSERT(!aRequest->IsReadyToRun());
|
MOZ_ASSERT(!aRequest->IsReadyToRun());
|
||||||
|
|
||||||
aRequest->mProgress = ModuleLoadRequest::Progress::FetchingImports;
|
aRequest->mProgress = ModuleLoadRequest::Progress::FetchingImports;
|
||||||
|
|
||||||
nsCOMArray<nsIURI> urls;
|
nsCOMArray<nsIURI> urls;
|
||||||
nsresult rv = ResolveRequestedModules(aRequest, urls);
|
nsresult rv = ResolveRequestedModules(aRequest, urls);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
aRequest->LoadFailed();
|
aRequest->ModuleErrored();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -750,7 +778,7 @@ ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest)
|
||||||
GenericPromise::All(AbstractThread::GetCurrent(), importsReady);
|
GenericPromise::All(AbstractThread::GetCurrent(), importsReady);
|
||||||
allReady->Then(AbstractThread::GetCurrent(), __func__, aRequest,
|
allReady->Then(AbstractThread::GetCurrent(), __func__, aRequest,
|
||||||
&ModuleLoadRequest::DependenciesLoaded,
|
&ModuleLoadRequest::DependenciesLoaded,
|
||||||
&ModuleLoadRequest::LoadFailed);
|
&ModuleLoadRequest::ModuleErrored);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<GenericPromise>
|
RefPtr<GenericPromise>
|
||||||
|
@ -773,6 +801,7 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest,
|
||||||
|
|
||||||
nsresult rv = StartLoad(childRequest, NS_LITERAL_STRING("module"), false);
|
nsresult rv = StartLoad(childRequest, NS_LITERAL_STRING("module"), false);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
MOZ_ASSERT(!childRequest->mModuleScript);
|
||||||
childRequest->mReady.Reject(rv, __func__);
|
childRequest->mReady.Reject(rv, __func__);
|
||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
|
@ -781,6 +810,7 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest,
|
||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier)
|
||||||
bool
|
bool
|
||||||
HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp)
|
HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp)
|
||||||
{
|
{
|
||||||
|
@ -795,31 +825,25 @@ HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp)
|
||||||
MOZ_ASSERT(script->ModuleRecord() == module);
|
MOZ_ASSERT(script->ModuleRecord() == module);
|
||||||
|
|
||||||
// Let url be the result of resolving a module specifier given referencing
|
// Let url be the result of resolving a module specifier given referencing
|
||||||
// module script and specifier. If the result is failure, throw a TypeError
|
// module script and specifier.
|
||||||
// exception and abort these steps.
|
|
||||||
nsAutoJSString string;
|
nsAutoJSString string;
|
||||||
if (!string.init(aCx, specifier)) {
|
if (!string.init(aCx, specifier)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(script, string);
|
nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(script, string);
|
||||||
if (!uri) {
|
|
||||||
return HandleResolveFailure(aCx, script, string);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let resolved module script be the value of the entry in module map whose
|
// This cannot fail because resolving a module specifier must have been
|
||||||
// key is url. If no such entry exists, throw a TypeError exception and abort
|
// previously successful with these same two arguments.
|
||||||
// these steps.
|
MOZ_ASSERT(uri, "Failed to resolve previously-resolved module specifier");
|
||||||
|
|
||||||
|
// Let resolved module script be moduleMap[url]. (This entry must exist for us
|
||||||
|
// to have gotten to this point.)
|
||||||
|
|
||||||
ModuleScript* ms = script->Loader()->GetFetchedModule(uri);
|
ModuleScript* ms = script->Loader()->GetFetchedModule(uri);
|
||||||
if (!ms) {
|
MOZ_ASSERT(ms, "Resolved module not found in module map");
|
||||||
return HandleModuleNotFound(aCx, script, string);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ms->InstantiationFailed()) {
|
MOZ_ASSERT(!ms->IsErrored());
|
||||||
JS::Rooted<JS::Value> exception(aCx, ms->Exception());
|
|
||||||
JS_SetPendingException(aCx, exception);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*vp = JS::ObjectValue(*ms->ModuleRecord());
|
*vp = JS::ObjectValue(*ms->ModuleRecord());
|
||||||
return true;
|
return true;
|
||||||
|
@ -843,10 +867,36 @@ EnsureModuleResolveHook(JSContext* aCx)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ScriptLoader::CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest)
|
||||||
|
{
|
||||||
|
RefPtr<ModuleScript> moduleScript = aRequest->mModuleScript;
|
||||||
|
if (moduleScript && !moduleScript->IsErrored()) {
|
||||||
|
for (auto childRequest : aRequest->mImports) {
|
||||||
|
ModuleScript* childScript = childRequest->mModuleScript;
|
||||||
|
if (!childScript) {
|
||||||
|
// Load error
|
||||||
|
aRequest->mModuleScript = nullptr;
|
||||||
|
return;
|
||||||
|
} else if (childScript->IsErrored()) {
|
||||||
|
// Script error
|
||||||
|
moduleScript->SetPreInstantiationError(childScript->Error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
|
ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
|
||||||
{
|
{
|
||||||
if (aRequest->IsTopLevel()) {
|
if (aRequest->IsTopLevel()) {
|
||||||
|
ModuleScript* moduleScript = aRequest->mModuleScript;
|
||||||
|
if (moduleScript && !moduleScript->IsErrored()) {
|
||||||
|
if (!InstantiateModuleTree(aRequest)) {
|
||||||
|
aRequest->mModuleScript = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
MaybeMoveToLoadedList(aRequest);
|
MaybeMoveToLoadedList(aRequest);
|
||||||
ProcessPendingRequests();
|
ProcessPendingRequests();
|
||||||
}
|
}
|
||||||
|
@ -859,60 +909,35 @@ ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest)
|
||||||
bool
|
bool
|
||||||
ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest)
|
ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest)
|
||||||
{
|
{
|
||||||
// Perform eager instantiation of the loaded module tree.
|
// Instantiate a top-level module and record any error.
|
||||||
|
|
||||||
MOZ_ASSERT(aRequest);
|
MOZ_ASSERT(aRequest);
|
||||||
|
MOZ_ASSERT(aRequest->IsTopLevel());
|
||||||
|
|
||||||
ModuleScript* ms = aRequest->mModuleScript;
|
ModuleScript* moduleScript = aRequest->mModuleScript;
|
||||||
MOZ_ASSERT(ms);
|
MOZ_ASSERT(moduleScript);
|
||||||
if (!ms || !ms->ModuleRecord()) {
|
MOZ_ASSERT(moduleScript->ModuleRecord());
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
nsAutoMicroTask mt;
|
||||||
AutoJSAPI jsapi;
|
AutoJSAPI jsapi;
|
||||||
if (NS_WARN_IF(!jsapi.Init(ms->ModuleRecord()))) {
|
if (NS_WARN_IF(!jsapi.Init(moduleScript->ModuleRecord()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = EnsureModuleResolveHook(jsapi.cx());
|
nsresult rv = EnsureModuleResolveHook(jsapi.cx());
|
||||||
NS_ENSURE_SUCCESS(rv, false);
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
|
||||||
JS::Rooted<JSObject*> module(jsapi.cx(), ms->ModuleRecord());
|
JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord());
|
||||||
bool ok = NS_SUCCEEDED(nsJSUtils::ModuleDeclarationInstantiation(jsapi.cx(), module));
|
bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module));
|
||||||
|
|
||||||
JS::RootedValue exception(jsapi.cx());
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
MOZ_ASSERT(jsapi.HasException());
|
MOZ_ASSERT(jsapi.HasException());
|
||||||
|
JS::RootedValue exception(jsapi.cx());
|
||||||
if (!jsapi.StealException(&exception)) {
|
if (!jsapi.StealException(&exception)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(!exception.isUndefined());
|
MOZ_ASSERT(!exception.isUndefined());
|
||||||
}
|
// Ignore the exception. It will be recorded in the module record.
|
||||||
|
|
||||||
// Mark this module and any uninstantiated dependencies found via depth-first
|
|
||||||
// search as instantiated and record any error.
|
|
||||||
|
|
||||||
mozilla::Vector<ModuleLoadRequest*, 1> requests;
|
|
||||||
if (!requests.append(aRequest)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!requests.empty()) {
|
|
||||||
ModuleLoadRequest* request = requests.popCopy();
|
|
||||||
ModuleScript* ms = request->mModuleScript;
|
|
||||||
if (!ms->IsUninstantiated()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ms->SetInstantiationResult(exception);
|
|
||||||
|
|
||||||
for (auto import : request->mImports) {
|
|
||||||
if (import->mModuleScript->IsUninstantiated() &&
|
|
||||||
!requests.append(import))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1427,13 +1452,19 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||||
ModuleLoadRequest* modReq = request->AsModuleRequest();
|
ModuleLoadRequest* modReq = request->AsModuleRequest();
|
||||||
modReq->mBaseURL = mDocument->GetDocBaseURI();
|
modReq->mBaseURL = mDocument->GetDocBaseURI();
|
||||||
rv = CreateModuleScript(modReq);
|
rv = CreateModuleScript(modReq);
|
||||||
NS_ENSURE_SUCCESS(rv, false);
|
MOZ_ASSERT(NS_FAILED(rv) == !modReq->mModuleScript);
|
||||||
StartFetchingModuleDependencies(modReq);
|
if (NS_FAILED(rv)) {
|
||||||
|
modReq->LoadFailed();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (aElement->GetScriptAsync()) {
|
if (aElement->GetScriptAsync()) {
|
||||||
mLoadingAsyncRequests.AppendElement(request);
|
mLoadingAsyncRequests.AppendElement(request);
|
||||||
} else {
|
} else {
|
||||||
AddDeferRequest(request);
|
AddDeferRequest(request);
|
||||||
}
|
}
|
||||||
|
if (!modReq->mModuleScript->IsErrored()) {
|
||||||
|
StartFetchingModuleDependencies(modReq);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
request->mProgress = ScriptLoadRequest::Progress::Ready;
|
request->mProgress = ScriptLoadRequest::Progress::Ready;
|
||||||
|
@ -1511,11 +1542,7 @@ ScriptLoader::ProcessOffThreadRequest(ScriptLoadRequest* aRequest)
|
||||||
if (aRequest->IsModuleRequest()) {
|
if (aRequest->IsModuleRequest()) {
|
||||||
MOZ_ASSERT(aRequest->mOffThreadToken);
|
MOZ_ASSERT(aRequest->mOffThreadToken);
|
||||||
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
||||||
nsresult rv = ProcessFetchedModuleSource(request);
|
return ProcessFetchedModuleSource(request);
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
request->LoadFailed();
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aRequest->SetReady();
|
aRequest->SetReady();
|
||||||
|
@ -1687,7 +1714,7 @@ ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest)
|
||||||
if (aRequest->IsModuleRequest() &&
|
if (aRequest->IsModuleRequest() &&
|
||||||
!aRequest->AsModuleRequest()->mModuleScript)
|
!aRequest->AsModuleRequest()->mModuleScript)
|
||||||
{
|
{
|
||||||
// There was an error parsing a module script. Nothing to do here.
|
// There was an error fetching a module script. Nothing to do here.
|
||||||
FireScriptAvailable(NS_ERROR_FAILURE, aRequest);
|
FireScriptAvailable(NS_ERROR_FAILURE, aRequest);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -1909,8 +1936,8 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
||||||
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
|
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
|
||||||
nsAutoMicroTask mt;
|
nsAutoMicroTask mt;
|
||||||
AutoEntryScript aes(globalObject, "<script> element", true);
|
AutoEntryScript aes(globalObject, "<script> element", true);
|
||||||
JS::Rooted<JSObject*> global(aes.cx(),
|
JSContext* cx = aes.cx();
|
||||||
globalObject->GetGlobalJSObject());
|
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||||
|
|
||||||
bool oldProcessingScriptTag = context->GetProcessingScriptTag();
|
bool oldProcessingScriptTag = context->GetProcessingScriptTag();
|
||||||
context->SetProcessingScriptTag(true);
|
context->SetProcessingScriptTag(true);
|
||||||
|
@ -1931,28 +1958,38 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aRequest->IsModuleRequest()) {
|
if (aRequest->IsModuleRequest()) {
|
||||||
|
rv = EnsureModuleResolveHook(cx);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
ModuleLoadRequest* request = aRequest->AsModuleRequest();
|
||||||
MOZ_ASSERT(request->mModuleScript);
|
MOZ_ASSERT(request->mModuleScript);
|
||||||
MOZ_ASSERT(!request->mOffThreadToken);
|
MOZ_ASSERT(!request->mOffThreadToken);
|
||||||
ModuleScript* ms = request->mModuleScript;
|
|
||||||
MOZ_ASSERT(!ms->IsUninstantiated());
|
ModuleScript* moduleScript = request->mModuleScript;
|
||||||
if (ms->InstantiationFailed()) {
|
if (moduleScript->IsErrored()) {
|
||||||
JS::Rooted<JS::Value> exception(aes.cx(), ms->Exception());
|
// Module has an error status
|
||||||
JS_SetPendingException(aes.cx(), exception);
|
JS::Rooted<JS::Value> error(cx, moduleScript->Error());
|
||||||
rv = NS_ERROR_FAILURE;
|
JS_SetPendingException(cx, error);
|
||||||
} else {
|
return NS_OK; // An error is reported by AutoEntryScript.
|
||||||
JS::Rooted<JSObject*> module(aes.cx(), ms->ModuleRecord());
|
}
|
||||||
MOZ_ASSERT(module);
|
|
||||||
rv = nsJSUtils::ModuleEvaluation(aes.cx(), module);
|
JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord());
|
||||||
|
MOZ_ASSERT(module);
|
||||||
|
|
||||||
|
rv = nsJSUtils::ModuleEvaluate(cx, module);
|
||||||
|
MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
// Evaluation failed
|
||||||
|
rv = NS_OK; // An error is reported by AutoEntryScript.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
JS::CompileOptions options(aes.cx());
|
JS::CompileOptions options(cx);
|
||||||
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
|
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
nsAutoString inlineData;
|
nsAutoString inlineData;
|
||||||
SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData);
|
SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData);
|
||||||
rv = nsJSUtils::EvaluateString(aes.cx(), srcBuf, global, options,
|
rv = nsJSUtils::EvaluateString(cx, srcBuf, global, options,
|
||||||
aRequest->OffThreadTokenPtr());
|
aRequest->OffThreadTokenPtr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -580,6 +580,7 @@ private:
|
||||||
|
|
||||||
nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
|
nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
|
||||||
nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest);
|
nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest);
|
||||||
|
void CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest);
|
||||||
void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest);
|
void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest);
|
||||||
bool InstantiateModuleTree(ModuleLoadRequest* aRequest);
|
bool InstantiateModuleTree(ModuleLoadRequest* aRequest);
|
||||||
void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest);
|
void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest);
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* 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);
|
let requestedModule = HostResolveImportedModule(module, specifier);
|
||||||
if (requestedModule.state < expectedMinimumState)
|
if (requestedModule.state < expectedMinimumStatus)
|
||||||
ThrowInternalError(JSMSG_BAD_MODULE_STATE);
|
ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
|
||||||
|
|
||||||
return requestedModule;
|
return requestedModule;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,36 @@ function ModuleGetExportedNames(exportStarSet = [])
|
||||||
return exportedNames;
|
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)
|
// 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 = [])
|
function ModuleResolveExport(exportName, resolveSet = [])
|
||||||
{
|
{
|
||||||
if (!IsObject(this) || !IsModule(this)) {
|
if (!IsObject(this) || !IsModule(this)) {
|
||||||
|
@ -77,88 +106,104 @@ function ModuleResolveExport(exportName, resolveSet = [])
|
||||||
let module = this;
|
let module = this;
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
|
assert(module.status !== MODULE_STATUS_ERRORED, "Bad module status in ResolveExport");
|
||||||
|
|
||||||
|
// Step 3
|
||||||
for (let i = 0; i < resolveSet.length; i++) {
|
for (let i = 0; i < resolveSet.length; i++) {
|
||||||
let r = resolveSet[i];
|
let r = resolveSet[i];
|
||||||
if (r.module === module && r.exportName === exportName)
|
if (r.module === module && r.exportName === exportName) {
|
||||||
return null;
|
// 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});
|
_DefineDataProperty(resolveSet, resolveSet.length, {module: module, exportName: exportName});
|
||||||
|
|
||||||
// Step 4
|
// Step 5
|
||||||
let localExportEntries = module.localExportEntries;
|
let localExportEntries = module.localExportEntries;
|
||||||
for (let i = 0; i < localExportEntries.length; i++) {
|
for (let i = 0; i < localExportEntries.length; i++) {
|
||||||
let e = localExportEntries[i];
|
let e = localExportEntries[i];
|
||||||
if (exportName === e.exportName)
|
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;
|
let indirectExportEntries = module.indirectExportEntries;
|
||||||
for (let i = 0; i < indirectExportEntries.length; i++) {
|
for (let i = 0; i < indirectExportEntries.length; i++) {
|
||||||
let e = indirectExportEntries[i];
|
let e = indirectExportEntries[i];
|
||||||
if (exportName === e.exportName) {
|
if (exportName === e.exportName) {
|
||||||
let importedModule = CallModuleResolveHook(module, e.moduleRequest,
|
let importedModule = CallModuleResolveHook(module, e.moduleRequest,
|
||||||
MODULE_STATE_PARSED);
|
MODULE_STATUS_UNINSTANTIATED);
|
||||||
return callFunction(importedModule.resolveExport, importedModule, e.importName,
|
let resolution = callFunction(importedModule.resolveExport, importedModule, e.importName,
|
||||||
resolveSet);
|
resolveSet);
|
||||||
|
if (!resolution.resolved && !resolution.module)
|
||||||
|
resolution.module = module;
|
||||||
|
return resolution;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 6
|
// Step 7
|
||||||
if (exportName === "default") {
|
if (exportName === "default") {
|
||||||
// A default export cannot be provided by an export *.
|
// 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;
|
let starResolution = null;
|
||||||
|
|
||||||
// Step 8
|
// Step 9
|
||||||
let starExportEntries = module.starExportEntries;
|
let starExportEntries = module.starExportEntries;
|
||||||
for (let i = 0; i < starExportEntries.length; i++) {
|
for (let i = 0; i < starExportEntries.length; i++) {
|
||||||
let e = starExportEntries[i];
|
let e = starExportEntries[i];
|
||||||
let importedModule = CallModuleResolveHook(module, e.moduleRequest,
|
let importedModule = CallModuleResolveHook(module, e.moduleRequest,
|
||||||
MODULE_STATE_PARSED);
|
MODULE_STATUS_UNINSTANTIATED);
|
||||||
let resolution = callFunction(importedModule.resolveExport, importedModule,
|
let resolution = callFunction(importedModule.resolveExport, importedModule, exportName,
|
||||||
exportName, resolveSet);
|
resolveSet);
|
||||||
if (resolution === "ambiguous")
|
if (!resolution.resolved && (resolution.module || resolution.ambiguous))
|
||||||
return resolution;
|
return resolution;
|
||||||
|
|
||||||
if (resolution !== null) {
|
if (resolution.resolved) {
|
||||||
if (starResolution === null) {
|
if (starResolution === null) {
|
||||||
starResolution = resolution;
|
starResolution = resolution;
|
||||||
} else {
|
} else {
|
||||||
if (resolution.module !== starResolution.module ||
|
if (resolution.module !== starResolution.module ||
|
||||||
resolution.exportName !== starResolution.exportName)
|
resolution.bindingName !== starResolution.bindingName)
|
||||||
{
|
{
|
||||||
return "ambiguous";
|
return {resolved: false, module: null, ambiguous: true};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 9
|
// Step 10
|
||||||
return starResolution;
|
if (starResolution !== null)
|
||||||
|
return starResolution;
|
||||||
|
|
||||||
|
return {resolved: false, module: null, ambiguous: false};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 15.2.1.18 GetModuleNamespace(module)
|
// 15.2.1.18 GetModuleNamespace(module)
|
||||||
function GetModuleNamespace(module)
|
function GetModuleNamespace(module)
|
||||||
{
|
{
|
||||||
|
// Step 1
|
||||||
|
assert(IsModule(module), "GetModuleNamespace called with non-module");
|
||||||
|
|
||||||
// Step 2
|
// Step 2
|
||||||
let namespace = module.namespace;
|
assert(module.status !== MODULE_STATUS_UNINSTANTIATED &&
|
||||||
|
module.status !== MODULE_STATUS_ERRORED,
|
||||||
|
"Bad module status in GetModuleNamespace");
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
|
let namespace = module.namespace;
|
||||||
|
|
||||||
if (typeof namespace === "undefined") {
|
if (typeof namespace === "undefined") {
|
||||||
let exportedNames = callFunction(module.getExportedNames, module);
|
let exportedNames = callFunction(module.getExportedNames, module);
|
||||||
let unambiguousNames = [];
|
let unambiguousNames = [];
|
||||||
for (let i = 0; i < exportedNames.length; i++) {
|
for (let i = 0; i < exportedNames.length; i++) {
|
||||||
let name = exportedNames[i];
|
let name = exportedNames[i];
|
||||||
let resolution = callFunction(module.resolveExport, module, name);
|
let resolution = callFunction(module.resolveExport, module, name);
|
||||||
if (resolution === null)
|
if (resolution.resolved)
|
||||||
ThrowSyntaxError(JSMSG_MISSING_NAMESPACE_EXPORT);
|
|
||||||
if (resolution !== "ambiguous")
|
|
||||||
_DefineDataProperty(unambiguousNames, unambiguousNames.length, name);
|
_DefineDataProperty(unambiguousNames, unambiguousNames.length, name);
|
||||||
}
|
}
|
||||||
namespace = ModuleNamespaceCreate(module, unambiguousNames);
|
namespace = ModuleNamespaceCreate(module, unambiguousNames);
|
||||||
|
@ -180,7 +225,7 @@ function ModuleNamespaceCreate(module, exports)
|
||||||
for (let i = 0; i < exports.length; i++) {
|
for (let i = 0; i < exports.length; i++) {
|
||||||
let name = exports[i];
|
let name = exports[i];
|
||||||
let binding = callFunction(module.resolveExport, module, name);
|
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);
|
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
|
// Check for a previous failed attempt to instantiate this module. This can
|
||||||
// only happen due to a bug in the module loader.
|
// only happen due to a bug in the module loader.
|
||||||
if (module.state == MODULE_STATE_FAILED)
|
if (module.status === MODULE_STATUS_ERRORED)
|
||||||
ThrowInternalError(JSMSG_MODULE_INSTANTIATE_FAILED);
|
ThrowInternalError(JSMSG_MODULE_INSTANTIATE_FAILED, module.status);
|
||||||
|
|
||||||
let env = UnsafeGetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT);
|
let env = UnsafeGetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT);
|
||||||
assert(env === undefined || IsModuleEnvironment(env),
|
assert(env === undefined || IsModuleEnvironment(env),
|
||||||
|
@ -203,112 +248,401 @@ function GetModuleEnvironment(module)
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
function RecordInstantationFailure(module)
|
function RecordModuleError(module, error)
|
||||||
{
|
{
|
||||||
// Set the module's state to 'failed' to indicate a failed module
|
// Set the module's status to 'errored' to indicate a failed module
|
||||||
// instantiation and reset the environment slot to 'undefined'.
|
// instantiation and record the exception. The environment slot is also
|
||||||
assert(IsModule(module), "Non-module passed to RecordInstantationFailure");
|
// reset to 'undefined'.
|
||||||
SetModuleState(module, MODULE_STATE_FAILED);
|
|
||||||
|
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);
|
UnsafeSetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 15.2.1.16.4 ModuleDeclarationInstantiation()
|
function CountArrayValues(array, value)
|
||||||
function ModuleDeclarationInstantiation()
|
|
||||||
{
|
{
|
||||||
if (!IsObject(this) || !IsModule(this))
|
let count = 0;
|
||||||
return callFunction(CallModuleMethodIfWrapped, this, "ModuleDeclarationInstantiation");
|
for (let i = 0; i < array.length; i++) {
|
||||||
|
if (array[i] === value)
|
||||||
// Step 1
|
count++;
|
||||||
let module = this;
|
|
||||||
|
|
||||||
// Step 5
|
|
||||||
if (GetModuleEnvironment(module) !== undefined)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
_SetCanonicalName(ModuleDeclarationInstantiation, "ModuleDeclarationInstantiation");
|
|
||||||
|
|
||||||
// 15.2.1.16.5 ModuleEvaluation()
|
function ArrayContains(array, value)
|
||||||
function ModuleEvaluation()
|
{
|
||||||
|
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))
|
if (!IsObject(this) || !IsModule(this))
|
||||||
return callFunction(CallModuleMethodIfWrapped, this, "ModuleEvaluation");
|
return callFunction(CallModuleMethodIfWrapped, this, "ModuleInstantiate");
|
||||||
|
|
||||||
// Step 1
|
// Step 1
|
||||||
let module = this;
|
let module = this;
|
||||||
|
|
||||||
if (module.state < MODULE_STATE_INSTANTIATED)
|
// Step 2
|
||||||
ThrowInternalError(JSMSG_BAD_MODULE_STATE);
|
if (module.status === MODULE_STATUS_INSTANTIATING ||
|
||||||
|
module.status === MODULE_STATUS_EVALUATING)
|
||||||
|
{
|
||||||
|
ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 4
|
// Step 3
|
||||||
if (module.state == MODULE_STATE_EVALUATED)
|
let stack = [];
|
||||||
return undefined;
|
|
||||||
|
|
||||||
// Step 5
|
// Steps 4-5
|
||||||
SetModuleState(this, MODULE_STATE_EVALUATED);
|
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
|
// 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;
|
let requestedModules = module.requestedModules;
|
||||||
for (let i = 0; i < requestedModules.length; i++) {
|
for (let i = 0; i < requestedModules.length; i++) {
|
||||||
let required = requestedModules[i];
|
let required = requestedModules[i];
|
||||||
let requiredModule = CallModuleResolveHook(module, required, MODULE_STATE_INSTANTIATED);
|
let requiredModule = CallModuleResolveHook(module, required, MODULE_STATUS_ERRORED);
|
||||||
callFunction(requiredModule.evaluation, requiredModule);
|
|
||||||
|
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,
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
_SetCanonicalName(ModuleEvaluation, "ModuleEvaluation");
|
|
||||||
|
|
|
@ -18,10 +18,11 @@
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::frontend;
|
using namespace js::frontend;
|
||||||
|
|
||||||
static_assert(MODULE_STATE_FAILED < MODULE_STATE_PARSED &&
|
static_assert(MODULE_STATUS_ERRORED < MODULE_STATUS_UNINSTANTIATED &&
|
||||||
MODULE_STATE_PARSED < MODULE_STATE_INSTANTIATED &&
|
MODULE_STATUS_UNINSTANTIATED < MODULE_STATUS_INSTANTIATING &&
|
||||||
MODULE_STATE_INSTANTIATED < MODULE_STATE_EVALUATED,
|
MODULE_STATUS_INSTANTIATING < MODULE_STATUS_INSTANTIATED &&
|
||||||
"Module states are ordered incorrectly");
|
MODULE_STATUS_INSTANTIATED < MODULE_STATUS_EVALUATED,
|
||||||
|
"Module statuses are ordered incorrectly");
|
||||||
|
|
||||||
template<typename T, Value ValueGetter(const T* obj)>
|
template<typename T, Value ValueGetter(const T* obj)>
|
||||||
static bool
|
static bool
|
||||||
|
@ -42,7 +43,7 @@ ModuleValueGetter(JSContext* cx, unsigned argc, Value* vp)
|
||||||
#define DEFINE_GETTER_FUNCTIONS(cls, name, slot) \
|
#define DEFINE_GETTER_FUNCTIONS(cls, name, slot) \
|
||||||
static Value \
|
static Value \
|
||||||
cls##_##name##Value(const cls* obj) { \
|
cls##_##name##Value(const cls* obj) { \
|
||||||
return obj->getFixedSlot(cls::slot); \
|
return obj->getReservedSlot(cls::slot); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static bool \
|
static bool \
|
||||||
|
@ -69,6 +70,15 @@ ModuleValueGetter(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return &value.toString()->asAtom(); \
|
return &value.toString()->asAtom(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DEFINE_UINT32_ACCESSOR_METHOD(cls, name) \
|
||||||
|
uint32_t \
|
||||||
|
cls::name() const \
|
||||||
|
{ \
|
||||||
|
Value value = cls##_##name##Value(this); \
|
||||||
|
MOZ_ASSERT(value.toInt32() >= 0); \
|
||||||
|
return value.toInt32(); \
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// ImportEntryObject
|
// ImportEntryObject
|
||||||
|
|
||||||
|
@ -82,10 +92,14 @@ ImportEntryObject::class_ = {
|
||||||
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, moduleRequest, ModuleRequestSlot)
|
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, moduleRequest, ModuleRequestSlot)
|
||||||
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, importName, ImportNameSlot)
|
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, importName, ImportNameSlot)
|
||||||
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, localName, LocalNameSlot)
|
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, localName, LocalNameSlot)
|
||||||
|
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, lineNumber, LineNumberSlot)
|
||||||
|
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, columnNumber, ColumnNumberSlot)
|
||||||
|
|
||||||
DEFINE_ATOM_ACCESSOR_METHOD(ImportEntryObject, moduleRequest)
|
DEFINE_ATOM_ACCESSOR_METHOD(ImportEntryObject, moduleRequest)
|
||||||
DEFINE_ATOM_ACCESSOR_METHOD(ImportEntryObject, importName)
|
DEFINE_ATOM_ACCESSOR_METHOD(ImportEntryObject, importName)
|
||||||
DEFINE_ATOM_ACCESSOR_METHOD(ImportEntryObject, localName)
|
DEFINE_ATOM_ACCESSOR_METHOD(ImportEntryObject, localName)
|
||||||
|
DEFINE_UINT32_ACCESSOR_METHOD(ImportEntryObject, lineNumber)
|
||||||
|
DEFINE_UINT32_ACCESSOR_METHOD(ImportEntryObject, columnNumber)
|
||||||
|
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
ImportEntryObject::isInstance(HandleValue value)
|
ImportEntryObject::isInstance(HandleValue value)
|
||||||
|
@ -100,6 +114,8 @@ GlobalObject::initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global)
|
||||||
JS_PSG("moduleRequest", ImportEntryObject_moduleRequestGetter, 0),
|
JS_PSG("moduleRequest", ImportEntryObject_moduleRequestGetter, 0),
|
||||||
JS_PSG("importName", ImportEntryObject_importNameGetter, 0),
|
JS_PSG("importName", ImportEntryObject_importNameGetter, 0),
|
||||||
JS_PSG("localName", ImportEntryObject_localNameGetter, 0),
|
JS_PSG("localName", ImportEntryObject_localNameGetter, 0),
|
||||||
|
JS_PSG("lineNumber", ImportEntryObject_lineNumberGetter, 0),
|
||||||
|
JS_PSG("columnNumber", ImportEntryObject_columnNumberGetter, 0),
|
||||||
JS_PS_END
|
JS_PS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -118,8 +134,12 @@ GlobalObject::initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global)
|
||||||
ImportEntryObject::create(ExclusiveContext* cx,
|
ImportEntryObject::create(ExclusiveContext* cx,
|
||||||
HandleAtom moduleRequest,
|
HandleAtom moduleRequest,
|
||||||
HandleAtom importName,
|
HandleAtom importName,
|
||||||
HandleAtom localName)
|
HandleAtom localName,
|
||||||
|
uint32_t lineNumber,
|
||||||
|
uint32_t columnNumber)
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(lineNumber > 0);
|
||||||
|
|
||||||
RootedObject proto(cx, cx->global()->getImportEntryPrototype());
|
RootedObject proto(cx, cx->global()->getImportEntryPrototype());
|
||||||
RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
|
RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
|
||||||
if (!obj)
|
if (!obj)
|
||||||
|
@ -129,6 +149,8 @@ ImportEntryObject::create(ExclusiveContext* cx,
|
||||||
self->initReservedSlot(ModuleRequestSlot, StringValue(moduleRequest));
|
self->initReservedSlot(ModuleRequestSlot, StringValue(moduleRequest));
|
||||||
self->initReservedSlot(ImportNameSlot, StringValue(importName));
|
self->initReservedSlot(ImportNameSlot, StringValue(importName));
|
||||||
self->initReservedSlot(LocalNameSlot, StringValue(localName));
|
self->initReservedSlot(LocalNameSlot, StringValue(localName));
|
||||||
|
self->initReservedSlot(LineNumberSlot, Int32Value(lineNumber));
|
||||||
|
self->initReservedSlot(ColumnNumberSlot, Int32Value(columnNumber));
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,11 +168,15 @@ DEFINE_GETTER_FUNCTIONS(ExportEntryObject, exportName, ExportNameSlot)
|
||||||
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, moduleRequest, ModuleRequestSlot)
|
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, moduleRequest, ModuleRequestSlot)
|
||||||
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, importName, ImportNameSlot)
|
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, importName, ImportNameSlot)
|
||||||
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, localName, LocalNameSlot)
|
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, localName, LocalNameSlot)
|
||||||
|
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, lineNumber, LineNumberSlot)
|
||||||
|
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, columnNumber, ColumnNumberSlot)
|
||||||
|
|
||||||
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, exportName)
|
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, exportName)
|
||||||
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, moduleRequest)
|
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, moduleRequest)
|
||||||
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, importName)
|
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, importName)
|
||||||
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, localName)
|
DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ExportEntryObject, localName)
|
||||||
|
DEFINE_UINT32_ACCESSOR_METHOD(ExportEntryObject, lineNumber)
|
||||||
|
DEFINE_UINT32_ACCESSOR_METHOD(ExportEntryObject, columnNumber)
|
||||||
|
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
ExportEntryObject::isInstance(HandleValue value)
|
ExportEntryObject::isInstance(HandleValue value)
|
||||||
|
@ -166,6 +192,8 @@ GlobalObject::initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global)
|
||||||
JS_PSG("moduleRequest", ExportEntryObject_moduleRequestGetter, 0),
|
JS_PSG("moduleRequest", ExportEntryObject_moduleRequestGetter, 0),
|
||||||
JS_PSG("importName", ExportEntryObject_importNameGetter, 0),
|
JS_PSG("importName", ExportEntryObject_importNameGetter, 0),
|
||||||
JS_PSG("localName", ExportEntryObject_localNameGetter, 0),
|
JS_PSG("localName", ExportEntryObject_localNameGetter, 0),
|
||||||
|
JS_PSG("lineNumber", ExportEntryObject_lineNumberGetter, 0),
|
||||||
|
JS_PSG("columnNumber", ExportEntryObject_columnNumberGetter, 0),
|
||||||
JS_PS_END
|
JS_PS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -191,8 +219,13 @@ ExportEntryObject::create(ExclusiveContext* cx,
|
||||||
HandleAtom maybeExportName,
|
HandleAtom maybeExportName,
|
||||||
HandleAtom maybeModuleRequest,
|
HandleAtom maybeModuleRequest,
|
||||||
HandleAtom maybeImportName,
|
HandleAtom maybeImportName,
|
||||||
HandleAtom maybeLocalName)
|
HandleAtom maybeLocalName,
|
||||||
|
uint32_t lineNumber,
|
||||||
|
uint32_t columnNumber)
|
||||||
{
|
{
|
||||||
|
// Line and column numbers are optional for export entries since direct
|
||||||
|
// entries are checked at parse time.
|
||||||
|
|
||||||
RootedObject proto(cx, cx->global()->getExportEntryPrototype());
|
RootedObject proto(cx, cx->global()->getExportEntryPrototype());
|
||||||
RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
|
RootedObject obj(cx, NewObjectWithGivenProto(cx, &class_, proto));
|
||||||
if (!obj)
|
if (!obj)
|
||||||
|
@ -203,6 +236,8 @@ ExportEntryObject::create(ExclusiveContext* cx,
|
||||||
self->initReservedSlot(ModuleRequestSlot, StringOrNullValue(maybeModuleRequest));
|
self->initReservedSlot(ModuleRequestSlot, StringOrNullValue(maybeModuleRequest));
|
||||||
self->initReservedSlot(ImportNameSlot, StringOrNullValue(maybeImportName));
|
self->initReservedSlot(ImportNameSlot, StringOrNullValue(maybeImportName));
|
||||||
self->initReservedSlot(LocalNameSlot, StringOrNullValue(maybeLocalName));
|
self->initReservedSlot(LocalNameSlot, StringOrNullValue(maybeLocalName));
|
||||||
|
self->initReservedSlot(LineNumberSlot, Int32Value(lineNumber));
|
||||||
|
self->initReservedSlot(ColumnNumberSlot, Int32Value(columnNumber));
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,7 +599,7 @@ ModuleObject::class_ = {
|
||||||
ArrayObject& \
|
ArrayObject& \
|
||||||
cls::name() const \
|
cls::name() const \
|
||||||
{ \
|
{ \
|
||||||
return getFixedSlot(cls::slot).toObject().as<ArrayObject>(); \
|
return getReservedSlot(cls::slot).toObject().as<ArrayObject>(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, requestedModules, RequestedModulesSlot)
|
DEFINE_ARRAY_SLOT_ACCESSOR(ModuleObject, requestedModules, RequestedModulesSlot)
|
||||||
|
@ -688,7 +723,7 @@ void
|
||||||
ModuleObject::init(HandleScript script)
|
ModuleObject::init(HandleScript script)
|
||||||
{
|
{
|
||||||
initReservedSlot(ScriptSlot, PrivateValue(script));
|
initReservedSlot(ScriptSlot, PrivateValue(script));
|
||||||
initReservedSlot(StateSlot, Int32Value(MODULE_STATE_FAILED));
|
initReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_ERRORED));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -709,7 +744,7 @@ ModuleObject::initImportExportData(HandleArrayObject requestedModules,
|
||||||
initReservedSlot(LocalExportEntriesSlot, ObjectValue(*localExportEntries));
|
initReservedSlot(LocalExportEntriesSlot, ObjectValue(*localExportEntries));
|
||||||
initReservedSlot(IndirectExportEntriesSlot, ObjectValue(*indirectExportEntries));
|
initReservedSlot(IndirectExportEntriesSlot, ObjectValue(*indirectExportEntries));
|
||||||
initReservedSlot(StarExportEntriesSlot, ObjectValue(*starExportEntries));
|
initReservedSlot(StarExportEntriesSlot, ObjectValue(*starExportEntries));
|
||||||
setReservedSlot(StateSlot, Int32Value(MODULE_STATE_PARSED));
|
setReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_UNINSTANTIATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -790,17 +825,24 @@ ModuleObject::script() const
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
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
|
ModuleStatus
|
||||||
ModuleObject::state() const
|
ModuleObject::status() const
|
||||||
{
|
{
|
||||||
ModuleState state = getReservedSlot(StateSlot).toInt32();
|
ModuleStatus status = getReservedSlot(StatusSlot).toInt32();
|
||||||
AssertValidModuleState(state);
|
AssertValidModuleStatus(status);
|
||||||
return state;
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value
|
||||||
|
ModuleObject::error() const
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(status() == MODULE_STATUS_ERRORED);
|
||||||
|
return getReservedSlot(ErrorSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value
|
Value
|
||||||
|
@ -899,17 +941,8 @@ ModuleObject::instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject
|
||||||
return true;
|
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
|
/* static */ bool
|
||||||
ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValue rval)
|
ModuleObject::execute(JSContext* cx, HandleModuleObject self, MutableHandleValue rval)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsFrozen(cx, self));
|
MOZ_ASSERT(IsFrozen(cx, self));
|
||||||
|
|
||||||
|
@ -959,44 +992,50 @@ InvokeSelfHostedMethod(JSContext* cx, HandleModuleObject self, HandlePropertyNam
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ bool
|
/* 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
|
/* 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, 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, requestedModules, RequestedModulesSlot)
|
||||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, importEntries, ImportEntriesSlot)
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, importEntries, ImportEntriesSlot)
|
||||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, localExportEntries, LocalExportEntriesSlot)
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, localExportEntries, LocalExportEntriesSlot)
|
||||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, indirectExportEntries, IndirectExportEntriesSlot)
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, indirectExportEntries, IndirectExportEntriesSlot)
|
||||||
DEFINE_GETTER_FUNCTIONS(ModuleObject, starExportEntries, StarExportEntriesSlot)
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, starExportEntries, StarExportEntriesSlot)
|
||||||
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, dfsIndex, DFSIndexSlot)
|
||||||
|
DEFINE_GETTER_FUNCTIONS(ModuleObject, dfsAncestorIndex, DFSAncestorIndexSlot)
|
||||||
|
|
||||||
/* static */ bool
|
/* static */ bool
|
||||||
GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global)
|
GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global)
|
||||||
{
|
{
|
||||||
static const JSPropertySpec protoAccessors[] = {
|
static const JSPropertySpec protoAccessors[] = {
|
||||||
JS_PSG("namespace", ModuleObject_namespace_Getter, 0),
|
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("requestedModules", ModuleObject_requestedModulesGetter, 0),
|
||||||
JS_PSG("importEntries", ModuleObject_importEntriesGetter, 0),
|
JS_PSG("importEntries", ModuleObject_importEntriesGetter, 0),
|
||||||
JS_PSG("localExportEntries", ModuleObject_localExportEntriesGetter, 0),
|
JS_PSG("localExportEntries", ModuleObject_localExportEntriesGetter, 0),
|
||||||
JS_PSG("indirectExportEntries", ModuleObject_indirectExportEntriesGetter, 0),
|
JS_PSG("indirectExportEntries", ModuleObject_indirectExportEntriesGetter, 0),
|
||||||
JS_PSG("starExportEntries", ModuleObject_starExportEntriesGetter, 0),
|
JS_PSG("starExportEntries", ModuleObject_starExportEntriesGetter, 0),
|
||||||
|
JS_PSG("dfsIndex", ModuleObject_dfsIndexGetter, 0),
|
||||||
|
JS_PSG("dfsAncestorIndex", ModuleObject_dfsAncestorIndexGetter, 0),
|
||||||
JS_PS_END
|
JS_PS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
static const JSFunctionSpec protoFunctions[] = {
|
static const JSFunctionSpec protoFunctions[] = {
|
||||||
JS_SELF_HOSTED_FN("getExportedNames", "ModuleGetExportedNames", 1, 0),
|
JS_SELF_HOSTED_FN("getExportedNames", "ModuleGetExportedNames", 1, 0),
|
||||||
JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 2, 0),
|
JS_SELF_HOSTED_FN("resolveExport", "ModuleResolveExport", 2, 0),
|
||||||
JS_SELF_HOSTED_FN("declarationInstantiation", "ModuleDeclarationInstantiation", 0, 0),
|
JS_SELF_HOSTED_FN("declarationInstantiation", "ModuleInstantiate", 0, 0),
|
||||||
JS_SELF_HOSTED_FN("evaluation", "ModuleEvaluation", 0, 0),
|
JS_SELF_HOSTED_FN("evaluation", "ModuleEvaluate", 0, 0),
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1018,9 +1057,11 @@ GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global)
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// ModuleBuilder
|
// ModuleBuilder
|
||||||
|
|
||||||
ModuleBuilder::ModuleBuilder(ExclusiveContext* cx, HandleModuleObject module)
|
ModuleBuilder::ModuleBuilder(ExclusiveContext* cx, HandleModuleObject module,
|
||||||
|
const frontend::TokenStream& tokenStream)
|
||||||
: cx_(cx),
|
: cx_(cx),
|
||||||
module_(cx, module),
|
module_(cx, module),
|
||||||
|
tokenStream_(tokenStream),
|
||||||
requestedModules_(cx, AtomVector(cx)),
|
requestedModules_(cx, AtomVector(cx)),
|
||||||
importedBoundNames_(cx, AtomVector(cx)),
|
importedBoundNames_(cx, AtomVector(cx)),
|
||||||
importEntries_(cx, ImportEntryVector(cx)),
|
importEntries_(cx, ImportEntryVector(cx)),
|
||||||
|
@ -1045,6 +1086,7 @@ ModuleBuilder::buildTables()
|
||||||
if (!localExportEntries_.append(exp))
|
if (!localExportEntries_.append(exp))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
MOZ_ASSERT(exp->lineNumber());
|
||||||
RootedAtom exportName(cx_, exp->exportName());
|
RootedAtom exportName(cx_, exp->exportName());
|
||||||
RootedAtom moduleRequest(cx_, importEntry->moduleRequest());
|
RootedAtom moduleRequest(cx_, importEntry->moduleRequest());
|
||||||
RootedAtom importName(cx_, importEntry->importName());
|
RootedAtom importName(cx_, importEntry->importName());
|
||||||
|
@ -1053,7 +1095,9 @@ ModuleBuilder::buildTables()
|
||||||
exportName,
|
exportName,
|
||||||
moduleRequest,
|
moduleRequest,
|
||||||
importName,
|
importName,
|
||||||
nullptr);
|
nullptr,
|
||||||
|
exp->lineNumber(),
|
||||||
|
exp->columnNumber());
|
||||||
if (!exportEntry || !indirectExportEntries_.append(exportEntry))
|
if (!exportEntry || !indirectExportEntries_.append(exportEntry))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1062,6 +1106,7 @@ ModuleBuilder::buildTables()
|
||||||
if (!starExportEntries_.append(exp))
|
if (!starExportEntries_.append(exp))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
MOZ_ASSERT(exp->lineNumber());
|
||||||
if (!indirectExportEntries_.append(exp))
|
if (!indirectExportEntries_.append(exp))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1126,8 +1171,12 @@ ModuleBuilder::processImport(frontend::ParseNode* pn)
|
||||||
if (!importedBoundNames_.append(localName))
|
if (!importedBoundNames_.append(localName))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
uint32_t line;
|
||||||
|
uint32_t column;
|
||||||
|
tokenStream_.srcCoords.lineNumAndColumnIndex(spec->pn_left->pn_pos.begin, &line, &column);
|
||||||
|
|
||||||
RootedImportEntryObject importEntry(cx_);
|
RootedImportEntryObject importEntry(cx_);
|
||||||
importEntry = ImportEntryObject::create(cx_, module, importName, localName);
|
importEntry = ImportEntryObject::create(cx_, module, importName, localName, line, column);
|
||||||
if (!importEntry || !importEntries_.append(importEntry))
|
if (!importEntry || !importEntries_.append(importEntry))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1158,7 +1207,7 @@ ModuleBuilder::processExport(frontend::ParseNode* pn)
|
||||||
MOZ_ASSERT(spec->isKind(PNK_EXPORT_SPEC));
|
MOZ_ASSERT(spec->isKind(PNK_EXPORT_SPEC));
|
||||||
RootedAtom localName(cx_, spec->pn_left->pn_atom);
|
RootedAtom localName(cx_, spec->pn_left->pn_atom);
|
||||||
RootedAtom exportName(cx_, spec->pn_right->pn_atom);
|
RootedAtom exportName(cx_, spec->pn_right->pn_atom);
|
||||||
if (!appendExportEntry(exportName, localName))
|
if (!appendExportEntry(exportName, localName, spec))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1223,12 +1272,12 @@ ModuleBuilder::processExportFrom(frontend::ParseNode* pn)
|
||||||
if (spec->isKind(PNK_EXPORT_SPEC)) {
|
if (spec->isKind(PNK_EXPORT_SPEC)) {
|
||||||
RootedAtom bindingName(cx_, spec->pn_left->pn_atom);
|
RootedAtom bindingName(cx_, spec->pn_left->pn_atom);
|
||||||
RootedAtom exportName(cx_, spec->pn_right->pn_atom);
|
RootedAtom exportName(cx_, spec->pn_right->pn_atom);
|
||||||
if (!appendExportFromEntry(exportName, module, bindingName))
|
if (!appendExportFromEntry(exportName, module, bindingName, spec->pn_left))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(spec->isKind(PNK_EXPORT_BATCH_SPEC));
|
MOZ_ASSERT(spec->isKind(PNK_EXPORT_BATCH_SPEC));
|
||||||
RootedAtom importName(cx_, cx_->names().star);
|
RootedAtom importName(cx_, cx_->names().star);
|
||||||
if (!appendExportFromEntry(nullptr, module, importName))
|
if (!appendExportFromEntry(nullptr, module, importName, spec))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1257,19 +1306,30 @@ ModuleBuilder::hasExportedName(JSAtom* name) const
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ModuleBuilder::appendExportEntry(HandleAtom exportName, HandleAtom localName)
|
ModuleBuilder::appendExportEntry(HandleAtom exportName, HandleAtom localName, ParseNode* node)
|
||||||
{
|
{
|
||||||
|
uint32_t line = 0;
|
||||||
|
uint32_t column = 0;
|
||||||
|
if (node)
|
||||||
|
tokenStream_.srcCoords.lineNumAndColumnIndex(node->pn_pos.begin, &line, &column);
|
||||||
|
|
||||||
Rooted<ExportEntryObject*> exportEntry(cx_);
|
Rooted<ExportEntryObject*> exportEntry(cx_);
|
||||||
exportEntry = ExportEntryObject::create(cx_, exportName, nullptr, nullptr, localName);
|
exportEntry = ExportEntryObject::create(cx_, exportName, nullptr, nullptr, localName,
|
||||||
|
line, column);
|
||||||
return exportEntry && exportEntries_.append(exportEntry);
|
return exportEntry && exportEntries_.append(exportEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ModuleBuilder::appendExportFromEntry(HandleAtom exportName, HandleAtom moduleRequest,
|
ModuleBuilder::appendExportFromEntry(HandleAtom exportName, HandleAtom moduleRequest,
|
||||||
HandleAtom importName)
|
HandleAtom importName, ParseNode* node)
|
||||||
{
|
{
|
||||||
|
uint32_t line;
|
||||||
|
uint32_t column;
|
||||||
|
tokenStream_.srcCoords.lineNumAndColumnIndex(node->pn_pos.begin, &line, &column);
|
||||||
|
|
||||||
Rooted<ExportEntryObject*> exportEntry(cx_);
|
Rooted<ExportEntryObject*> exportEntry(cx_);
|
||||||
exportEntry = ExportEntryObject::create(cx_, exportName, moduleRequest, importName, nullptr);
|
exportEntry = ExportEntryObject::create(cx_, exportName, moduleRequest, importName, nullptr,
|
||||||
|
line, column);
|
||||||
return exportEntry && exportEntries_.append(exportEntry);
|
return exportEntry && exportEntries_.append(exportEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ class ModuleObject;
|
||||||
|
|
||||||
namespace frontend {
|
namespace frontend {
|
||||||
class ParseNode;
|
class ParseNode;
|
||||||
|
class TokenStream;
|
||||||
} /* namespace frontend */
|
} /* namespace frontend */
|
||||||
|
|
||||||
typedef Rooted<ModuleObject*> RootedModuleObject;
|
typedef Rooted<ModuleObject*> RootedModuleObject;
|
||||||
|
@ -39,6 +40,8 @@ class ImportEntryObject : public NativeObject
|
||||||
ModuleRequestSlot = 0,
|
ModuleRequestSlot = 0,
|
||||||
ImportNameSlot,
|
ImportNameSlot,
|
||||||
LocalNameSlot,
|
LocalNameSlot,
|
||||||
|
LineNumberSlot,
|
||||||
|
ColumnNumberSlot,
|
||||||
SlotCount
|
SlotCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,10 +51,14 @@ class ImportEntryObject : public NativeObject
|
||||||
static ImportEntryObject* create(ExclusiveContext* cx,
|
static ImportEntryObject* create(ExclusiveContext* cx,
|
||||||
HandleAtom moduleRequest,
|
HandleAtom moduleRequest,
|
||||||
HandleAtom importName,
|
HandleAtom importName,
|
||||||
HandleAtom localName);
|
HandleAtom localName,
|
||||||
|
uint32_t lineNumber,
|
||||||
|
uint32_t columnNumber);
|
||||||
JSAtom* moduleRequest() const;
|
JSAtom* moduleRequest() const;
|
||||||
JSAtom* importName() const;
|
JSAtom* importName() const;
|
||||||
JSAtom* localName() const;
|
JSAtom* localName() const;
|
||||||
|
uint32_t lineNumber() const;
|
||||||
|
uint32_t columnNumber() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Rooted<ImportEntryObject*> RootedImportEntryObject;
|
typedef Rooted<ImportEntryObject*> RootedImportEntryObject;
|
||||||
|
@ -66,6 +73,8 @@ class ExportEntryObject : public NativeObject
|
||||||
ModuleRequestSlot,
|
ModuleRequestSlot,
|
||||||
ImportNameSlot,
|
ImportNameSlot,
|
||||||
LocalNameSlot,
|
LocalNameSlot,
|
||||||
|
LineNumberSlot,
|
||||||
|
ColumnNumberSlot,
|
||||||
SlotCount
|
SlotCount
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,11 +85,15 @@ class ExportEntryObject : public NativeObject
|
||||||
HandleAtom maybeExportName,
|
HandleAtom maybeExportName,
|
||||||
HandleAtom maybeModuleRequest,
|
HandleAtom maybeModuleRequest,
|
||||||
HandleAtom maybeImportName,
|
HandleAtom maybeImportName,
|
||||||
HandleAtom maybeLocalName);
|
HandleAtom maybeLocalName,
|
||||||
|
uint32_t lineNumber,
|
||||||
|
uint32_t columnNumber);
|
||||||
JSAtom* exportName() const;
|
JSAtom* exportName() const;
|
||||||
JSAtom* moduleRequest() const;
|
JSAtom* moduleRequest() const;
|
||||||
JSAtom* importName() const;
|
JSAtom* importName() const;
|
||||||
JSAtom* localName() const;
|
JSAtom* localName() const;
|
||||||
|
uint32_t lineNumber() const;
|
||||||
|
uint32_t columnNumber() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Rooted<ExportEntryObject*> RootedExportEntryObject;
|
typedef Rooted<ExportEntryObject*> RootedExportEntryObject;
|
||||||
|
@ -192,8 +205,8 @@ struct FunctionDeclaration
|
||||||
|
|
||||||
using FunctionDeclarationVector = GCVector<FunctionDeclaration, 0, ZoneAllocPolicy>;
|
using FunctionDeclarationVector = GCVector<FunctionDeclaration, 0, ZoneAllocPolicy>;
|
||||||
|
|
||||||
// Possible values for ModuleState are defined in SelfHostingDefines.h.
|
// Possible values for ModuleStatus are defined in SelfHostingDefines.h.
|
||||||
using ModuleState = int32_t;
|
using ModuleStatus = int32_t;
|
||||||
|
|
||||||
class ModuleObject : public NativeObject
|
class ModuleObject : public NativeObject
|
||||||
{
|
{
|
||||||
|
@ -204,7 +217,8 @@ class ModuleObject : public NativeObject
|
||||||
InitialEnvironmentSlot,
|
InitialEnvironmentSlot,
|
||||||
EnvironmentSlot,
|
EnvironmentSlot,
|
||||||
NamespaceSlot,
|
NamespaceSlot,
|
||||||
StateSlot,
|
StatusSlot,
|
||||||
|
ErrorSlot,
|
||||||
HostDefinedSlot,
|
HostDefinedSlot,
|
||||||
RequestedModulesSlot,
|
RequestedModulesSlot,
|
||||||
ImportEntriesSlot,
|
ImportEntriesSlot,
|
||||||
|
@ -215,11 +229,21 @@ class ModuleObject : public NativeObject
|
||||||
NamespaceExportsSlot,
|
NamespaceExportsSlot,
|
||||||
NamespaceBindingsSlot,
|
NamespaceBindingsSlot,
|
||||||
FunctionDeclarationsSlot,
|
FunctionDeclarationsSlot,
|
||||||
|
DFSIndexSlot,
|
||||||
|
DFSAncestorIndexSlot,
|
||||||
SlotCount
|
SlotCount
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(EnvironmentSlot == MODULE_OBJECT_ENVIRONMENT_SLOT,
|
static_assert(EnvironmentSlot == MODULE_OBJECT_ENVIRONMENT_SLOT,
|
||||||
"EnvironmentSlot must match self-hosting define");
|
"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_;
|
static const Class class_;
|
||||||
|
|
||||||
|
@ -244,7 +268,8 @@ class ModuleObject : public NativeObject
|
||||||
ModuleEnvironmentObject& initialEnvironment() const;
|
ModuleEnvironmentObject& initialEnvironment() const;
|
||||||
ModuleEnvironmentObject* environment() const;
|
ModuleEnvironmentObject* environment() const;
|
||||||
ModuleNamespaceObject* namespace_();
|
ModuleNamespaceObject* namespace_();
|
||||||
ModuleState state() const;
|
ModuleStatus status() const;
|
||||||
|
Value error() const;
|
||||||
Value hostDefinedField() const;
|
Value hostDefinedField() const;
|
||||||
ArrayObject& requestedModules() const;
|
ArrayObject& requestedModules() const;
|
||||||
ArrayObject& importEntries() const;
|
ArrayObject& importEntries() const;
|
||||||
|
@ -255,8 +280,8 @@ class ModuleObject : public NativeObject
|
||||||
JSObject* namespaceExports();
|
JSObject* namespaceExports();
|
||||||
IndirectBindingMap* namespaceBindings();
|
IndirectBindingMap* namespaceBindings();
|
||||||
|
|
||||||
static bool DeclarationInstantiation(JSContext* cx, HandleModuleObject self);
|
static bool Instantiate(JSContext* cx, HandleModuleObject self);
|
||||||
static bool Evaluation(JSContext* cx, HandleModuleObject self);
|
static bool Evaluate(JSContext* cx, HandleModuleObject self);
|
||||||
|
|
||||||
void setHostDefinedField(const JS::Value& value);
|
void setHostDefinedField(const JS::Value& value);
|
||||||
|
|
||||||
|
@ -269,10 +294,8 @@ class ModuleObject : public NativeObject
|
||||||
// For intrinsic_InstantiateModuleFunctionDeclarations.
|
// For intrinsic_InstantiateModuleFunctionDeclarations.
|
||||||
static bool instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject self);
|
static bool instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject self);
|
||||||
|
|
||||||
void setState(ModuleState newState);
|
// For intrinsic_ExecuteModule.
|
||||||
|
static bool execute(JSContext* cx, HandleModuleObject self, MutableHandleValue rval);
|
||||||
// For intrinsic_EvaluateModule.
|
|
||||||
static bool evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValue rval);
|
|
||||||
|
|
||||||
// For intrinsic_NewModuleNamespace.
|
// For intrinsic_NewModuleNamespace.
|
||||||
static ModuleNamespaceObject* createNamespace(JSContext* cx, HandleModuleObject self,
|
static ModuleNamespaceObject* createNamespace(JSContext* cx, HandleModuleObject self,
|
||||||
|
@ -294,7 +317,8 @@ class ModuleObject : public NativeObject
|
||||||
class MOZ_STACK_CLASS ModuleBuilder
|
class MOZ_STACK_CLASS ModuleBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ModuleBuilder(ExclusiveContext* cx, HandleModuleObject module);
|
explicit ModuleBuilder(ExclusiveContext* cx, HandleModuleObject module,
|
||||||
|
const frontend::TokenStream& tokenStream);
|
||||||
|
|
||||||
bool processImport(frontend::ParseNode* pn);
|
bool processImport(frontend::ParseNode* pn);
|
||||||
bool processExport(frontend::ParseNode* pn);
|
bool processExport(frontend::ParseNode* pn);
|
||||||
|
@ -319,6 +343,7 @@ class MOZ_STACK_CLASS ModuleBuilder
|
||||||
|
|
||||||
ExclusiveContext* cx_;
|
ExclusiveContext* cx_;
|
||||||
RootedModuleObject module_;
|
RootedModuleObject module_;
|
||||||
|
const frontend::TokenStream& tokenStream_;
|
||||||
RootedAtomVector requestedModules_;
|
RootedAtomVector requestedModules_;
|
||||||
RootedAtomVector importedBoundNames_;
|
RootedAtomVector importedBoundNames_;
|
||||||
RootedImportEntryVector importEntries_;
|
RootedImportEntryVector importEntries_;
|
||||||
|
@ -329,9 +354,10 @@ class MOZ_STACK_CLASS ModuleBuilder
|
||||||
|
|
||||||
ImportEntryObject* importEntryFor(JSAtom* localName) const;
|
ImportEntryObject* importEntryFor(JSAtom* localName) const;
|
||||||
|
|
||||||
bool appendExportEntry(HandleAtom exportName, HandleAtom localName);
|
bool appendExportEntry(HandleAtom exportName, HandleAtom localName,
|
||||||
|
frontend::ParseNode* node = nullptr);
|
||||||
bool appendExportFromEntry(HandleAtom exportName, HandleAtom moduleRequest,
|
bool appendExportFromEntry(HandleAtom exportName, HandleAtom moduleRequest,
|
||||||
HandleAtom importName);
|
HandleAtom importName, frontend::ParseNode* node);
|
||||||
|
|
||||||
bool maybeAppendRequestedModule(HandleAtom module);
|
bool maybeAppendRequestedModule(HandleAtom module);
|
||||||
|
|
||||||
|
|
|
@ -3741,7 +3741,7 @@ reflect_parse(JSContext* cx, uint32_t argc, Value* vp)
|
||||||
if (!module)
|
if (!module)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ModuleBuilder builder(cx, module);
|
ModuleBuilder builder(cx, module, parser.tokenStream);
|
||||||
ModuleSharedContext modulesc(cx, module, &cx->global()->emptyGlobalScope(), builder);
|
ModuleSharedContext modulesc(cx, module, &cx->global()->emptyGlobalScope(), builder);
|
||||||
pn = parser.moduleBody(&modulesc);
|
pn = parser.moduleBody(&modulesc);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
|
|
|
@ -97,11 +97,17 @@
|
||||||
#define REGEXP_STRING_ITERATOR_FLAGS_SLOT 2
|
#define REGEXP_STRING_ITERATOR_FLAGS_SLOT 2
|
||||||
#define REGEXP_STRING_ITERATOR_DONE_SLOT 3
|
#define REGEXP_STRING_ITERATOR_DONE_SLOT 3
|
||||||
|
|
||||||
#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_STATUS_ERRORED 0
|
||||||
#define MODULE_STATE_PARSED 1
|
#define MODULE_STATUS_UNINSTANTIATED 1
|
||||||
#define MODULE_STATE_INSTANTIATED 2
|
#define MODULE_STATUS_INSTANTIATING 2
|
||||||
#define MODULE_STATE_EVALUATED 3
|
#define MODULE_STATUS_INSTANTIATED 3
|
||||||
|
#define MODULE_STATUS_EVALUATING 4
|
||||||
|
#define MODULE_STATUS_EVALUATED 5
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -27,13 +27,20 @@
|
||||||
// Assertions and debug printing, defined here instead of in the header above
|
// Assertions and debug printing, defined here instead of in the header above
|
||||||
// to make `assert` invisible to C++.
|
// to make `assert` invisible to C++.
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define assert(b, info) if (!(b)) AssertionFailed(__FILE__ + ":" + __LINE__ + ": " + info)
|
#define assert(b, info) \
|
||||||
#define dbg(msg) DumpMessage(callFunction(std_Array_pop, \
|
do { \
|
||||||
StringSplitString(__FILE__, '/')) \
|
if (!(b)) \
|
||||||
+ '#' + __LINE__ + ': ' + msg)
|
AssertionFailed(__FILE__ + ":" + __LINE__ + ": " + info) \
|
||||||
|
} while (false)
|
||||||
|
#define dbg(msg) \
|
||||||
|
do { \
|
||||||
|
DumpMessage(callFunction(std_Array_pop, \
|
||||||
|
StringSplitString(__FILE__, '/')) + \
|
||||||
|
'#' + __LINE__ + ': ' + msg) \
|
||||||
|
} while (false)
|
||||||
#else
|
#else
|
||||||
#define assert(b, info) // Elided assertion.
|
#define assert(b, info) do {} while (false) // Elided assertion.
|
||||||
#define dbg(msg) // Elided debugging output.
|
#define dbg(msg) do {} while (false) // Elided debugging output.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// All C++-implemented standard builtins library functions used in self-hosted
|
// All C++-implemented standard builtins library functions used in self-hosted
|
||||||
|
|
|
@ -405,7 +405,7 @@ BytecodeCompiler::compileModule()
|
||||||
|
|
||||||
module->init(script);
|
module->init(script);
|
||||||
|
|
||||||
ModuleBuilder builder(cx, module);
|
ModuleBuilder builder(cx, module, parser->tokenStream);
|
||||||
ModuleSharedContext modulesc(cx, module, enclosingScope, builder);
|
ModuleSharedContext modulesc(cx, module, enclosingScope, builder);
|
||||||
ParseNode* pn = parser->moduleBody(&modulesc);
|
ParseNode* pn = parser->moduleBody(&modulesc);
|
||||||
if (!pn)
|
if (!pn)
|
||||||
|
|
|
@ -8261,7 +8261,7 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
||||||
if (topLevelFunction) {
|
if (topLevelFunction) {
|
||||||
if (sc->isModuleContext()) {
|
if (sc->isModuleContext()) {
|
||||||
// For modules, we record the function and instantiate the binding
|
// For modules, we record the function and instantiate the binding
|
||||||
// during ModuleDeclarationInstantiation(), before the script is run.
|
// during ModuleInstantiate(), before the script is run.
|
||||||
|
|
||||||
RootedModuleObject module(cx, sc->asModuleContext()->module());
|
RootedModuleObject module(cx, sc->asModuleContext()->module());
|
||||||
if (!module->noteFunctionDeclaration(cx, name, fun))
|
if (!module->noteFunctionDeclaration(cx, name, fun))
|
||||||
|
|
|
@ -5038,7 +5038,7 @@ Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node impor
|
||||||
// Namespace imports are are not indirect bindings but lexical
|
// Namespace imports are are not indirect bindings but lexical
|
||||||
// definitions that hold a module namespace object. They are treated
|
// definitions that hold a module namespace object. They are treated
|
||||||
// as const variables which are initialized during the
|
// as const variables which are initialized during the
|
||||||
// ModuleDeclarationInstantiation step.
|
// ModuleInstantiate step.
|
||||||
RootedPropertyName bindingName(context, importedBinding());
|
RootedPropertyName bindingName(context, importedBinding());
|
||||||
if (!bindingName)
|
if (!bindingName)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
load(libdir + "asserts.js");
|
load(libdir + "asserts.js");
|
||||||
load(libdir + "dummyModuleResolveHook.js");
|
load(libdir + "dummyModuleResolveHook.js");
|
||||||
|
|
||||||
function checkModuleEval(source, result) {
|
function checkModuleEval(source) {
|
||||||
let m = parseModule(source);
|
let m = parseModule(source);
|
||||||
m.declarationInstantiation();
|
m.declarationInstantiation();
|
||||||
assertEq(m.evaluation(), result);
|
m.evaluation();
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkModuleSyntaxError(source) {
|
function checkModuleSyntaxError(source) {
|
||||||
|
@ -23,17 +24,19 @@ c.declarationInstantiation();
|
||||||
c.evaluation();
|
c.evaluation();
|
||||||
|
|
||||||
// Check importing/exporting non-ambiguous name works.
|
// Check importing/exporting non-ambiguous name works.
|
||||||
checkModuleEval("import { a } from 'c'; a;", 1);
|
let d = checkModuleEval("import { a } from 'c';");
|
||||||
checkModuleEval("export { a } from 'c';", undefined);
|
assertEq(getModuleEnvironmentValue(d, "a"), 1);
|
||||||
|
checkModuleEval("export { a } from 'c';");
|
||||||
|
|
||||||
// Check importing/exporting ambiguous name is a syntax error.
|
// Check importing/exporting ambiguous name is a syntax error.
|
||||||
checkModuleSyntaxError("import { b } from 'c';");
|
checkModuleSyntaxError("import { b } from 'c';");
|
||||||
checkModuleSyntaxError("export { b } from 'c';");
|
checkModuleSyntaxError("export { b } from 'c';");
|
||||||
|
|
||||||
// Check that namespace objects include only non-ambiguous names.
|
// 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();
|
m.declarationInstantiation();
|
||||||
let ns = m.evaluation();
|
m.evaluation();
|
||||||
|
let ns = c.namespace;
|
||||||
let names = Object.keys(ns);
|
let names = Object.keys(ns);
|
||||||
assertEq(names.length, 2);
|
assertEq(names.length, 2);
|
||||||
assertEq('a' in ns, true);
|
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,23 +1,36 @@
|
||||||
// |jit-test| error: InternalError
|
|
||||||
|
|
||||||
// This tests that attempting to perform ModuleDeclarationInstantation a second
|
// 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
|
// time after a failure re-throws the same error.
|
||||||
// loader, which is expected to throw away modules if there is an error
|
|
||||||
// instantiating them.
|
|
||||||
//
|
//
|
||||||
// The first attempt fails becuase module 'a' is not available. The second
|
// The first attempt fails becuase module 'a' is not available. The second
|
||||||
// attempt fails because of the previous failure (it would otherwise succeed as
|
// attempt fails because of the previous failure (it would otherwise succeed as
|
||||||
// 'a' is now available).
|
// 'a' is now available).
|
||||||
|
|
||||||
let moduleRepo = {};
|
load(libdir + "dummyModuleResolveHook.js");
|
||||||
setModuleResolveHook(function(module, specifier) {
|
|
||||||
return moduleRepo[specifier];
|
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 {
|
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();
|
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 a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;");
|
||||||
let d = moduleRepo['d'] = parseModule("import { a } from 'c'; a;");
|
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,5 @@ let d = moduleRepo['d'] = parseModule("import { a } from 'c'; a;");
|
||||||
// Attempting to instantiate 'd' throws an error because depdency 'a' of
|
// Attempting to instantiate 'd' throws an error because depdency 'a' of
|
||||||
// instantiated module 'c' is not instantiated.
|
// instantiated module 'c' is not instantiated.
|
||||||
d.declarationInstantiation();
|
d.declarationInstantiation();
|
||||||
|
d.evaluation();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
// |jit-test| error: NaN
|
||||||
|
let m = parseModule(`
|
||||||
|
throw i => { return 5; }, m-1;
|
||||||
|
`);
|
||||||
|
m.declarationInstantiation();
|
||||||
|
m.evaluation();
|
|
@ -1,32 +1,34 @@
|
||||||
// Test interaction with global object and global lexical scope.
|
// Test interaction with global object and global lexical scope.
|
||||||
|
|
||||||
function parseAndEvaluate(source) {
|
function evalModuleAndCheck(source, expected) {
|
||||||
let m = parseModule(source);
|
let m = parseModule(source);
|
||||||
m.declarationInstantiation();
|
m.declarationInstantiation();
|
||||||
return m.evaluation();
|
m.evaluation();
|
||||||
|
assertEq(getModuleEnvironmentValue(m, "r"), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
var x = 1;
|
var x = 1;
|
||||||
assertEq(parseAndEvaluate("let r = x; x = 2; r"), 1);
|
evalModuleAndCheck("export let r = x; x = 2;", 1);
|
||||||
assertEq(x, 2);
|
assertEq(x, 2);
|
||||||
|
|
||||||
let y = 3;
|
let y = 3;
|
||||||
assertEq(parseAndEvaluate("let r = y; y = 4; r"), 3);
|
evalModuleAndCheck("export let r = y; y = 4;", 3);
|
||||||
assertEq(y, 4);
|
assertEq(y, 4);
|
||||||
|
|
||||||
if (helperThreadCount() == 0)
|
if (helperThreadCount() == 0)
|
||||||
quit();
|
quit();
|
||||||
|
|
||||||
function offThreadParseAndEvaluate(source) {
|
function offThreadEvalModuleAndCheck(source, expected) {
|
||||||
offThreadCompileModule(source);
|
offThreadCompileModule(source);
|
||||||
let m = finishOffThreadModule();
|
let m = finishOffThreadModule();
|
||||||
print("compiled");
|
print("compiled");
|
||||||
m.declarationInstantiation();
|
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(x, 5);
|
||||||
|
|
||||||
assertEq(offThreadParseAndEvaluate("let r = y; y = 6; r"), 4);
|
offThreadEvalModuleAndCheck("export let r = y; y = 6;", 4);
|
||||||
assertEq(y, 6);
|
assertEq(y, 6);
|
||||||
|
|
|
@ -6,16 +6,17 @@ load(libdir + "dummyModuleResolveHook.js");
|
||||||
function parseAndEvaluate(source) {
|
function parseAndEvaluate(source) {
|
||||||
let m = parseModule(source);
|
let m = parseModule(source);
|
||||||
m.declarationInstantiation();
|
m.declarationInstantiation();
|
||||||
return m.evaluation();
|
m.evaluation();
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the evaluation of an empty module succeeds.
|
// Check the evaluation of an empty module succeeds.
|
||||||
assertEq(typeof parseAndEvaluate(""), "undefined");
|
parseAndEvaluate("");
|
||||||
|
|
||||||
// Check evaluation returns evaluation result the first time, then undefined.
|
// Check evaluation returns evaluation result the first time, then undefined.
|
||||||
let m = parseModule("1");
|
let m = parseModule("1");
|
||||||
m.declarationInstantiation();
|
m.declarationInstantiation();
|
||||||
assertEq(m.evaluation(), 1);
|
assertEq(m.evaluation(), undefined);
|
||||||
assertEq(typeof m.evaluation(), "undefined");
|
assertEq(typeof m.evaluation(), "undefined");
|
||||||
|
|
||||||
// Check top level variables are initialized by evaluation.
|
// Check top level variables are initialized by evaluation.
|
||||||
|
@ -60,31 +61,35 @@ parseAndEvaluate("export default class { constructor() {} };");
|
||||||
parseAndEvaluate("export default class foo { constructor() {} };");
|
parseAndEvaluate("export default class foo { constructor() {} };");
|
||||||
|
|
||||||
// Test default import
|
// Test default import
|
||||||
m = parseModule("import a from 'a'; a;")
|
m = parseModule("import a from 'a'; export { a };")
|
||||||
m.declarationInstantiation();
|
m.declarationInstantiation();
|
||||||
assertEq(m.evaluation(), 2);
|
m.evaluation();
|
||||||
|
assertEq(getModuleEnvironmentValue(m, "a"), 2);
|
||||||
|
|
||||||
// Test named import
|
// Test named import
|
||||||
m = parseModule("import { x as y } from 'a'; y;")
|
m = parseModule("import { x as y } from 'a'; export { y };")
|
||||||
m.declarationInstantiation();
|
m.declarationInstantiation();
|
||||||
assertEq(m.evaluation(), 1);
|
m.evaluation();
|
||||||
|
assertEq(getModuleEnvironmentValue(m, "y"), 1);
|
||||||
|
|
||||||
// Call exported function
|
// Call exported function
|
||||||
m = parseModule("import { f } from 'a'; f(3);")
|
m = parseModule("import { f } from 'a'; export let x = f(3);")
|
||||||
m.declarationInstantiation();
|
m.declarationInstantiation();
|
||||||
assertEq(m.evaluation(), 4);
|
m.evaluation();
|
||||||
|
assertEq(getModuleEnvironmentValue(m, "x"), 4);
|
||||||
|
|
||||||
// Test importing an indirect export
|
// Test importing an indirect export
|
||||||
moduleRepo['b'] = parseModule("export { x as z } from 'a';");
|
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
|
// Test cyclic dependencies
|
||||||
moduleRepo['c1'] = parseModule("export var x = 1; export {y} from 'c2'");
|
moduleRepo['c1'] = parseModule("export var x = 1; export {y} from 'c2'");
|
||||||
moduleRepo['c2'] = parseModule("export var y = 2; export {x} from 'c1'");
|
moduleRepo['c2'] = parseModule("export var y = 2; export {x} from 'c1'");
|
||||||
assertDeepEq(parseAndEvaluate(`import { x as x1, y as y1 } from 'c1';
|
m = parseAndEvaluate(`import { x as x1, y as y1 } from 'c1';
|
||||||
import { x as x2, y as y2 } from 'c2';
|
import { x as x2, y as y2 } from 'c2';
|
||||||
[x1, y1, x2, y2]`),
|
export let z = [x1, y1, x2, y2]`),
|
||||||
[1, 2, 1, 2]);
|
assertDeepEq(getModuleEnvironmentValue(m, "z"), [1, 2, 1, 2]);
|
||||||
|
|
||||||
// Import access in functions
|
// Import access in functions
|
||||||
m = parseModule("import { x } from 'a'; function f() { return x; }")
|
m = parseModule("import { x } from 'a'; function f() { return x; }")
|
||||||
|
|
|
@ -573,14 +573,14 @@ MSG_DEF(JSMSG_REINIT_THIS, 0, JSEXN_REFERENCEERR, "super() called twice in
|
||||||
|
|
||||||
// Modules
|
// Modules
|
||||||
MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT, 0, JSEXN_SYNTAXERR, "default export cannot be provided by export *")
|
MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT, 0, JSEXN_SYNTAXERR, "default export cannot be provided by export *")
|
||||||
MSG_DEF(JSMSG_MISSING_INDIRECT_EXPORT, 1, JSEXN_SYNTAXERR, "indirect export '{0}' not found")
|
MSG_DEF(JSMSG_MISSING_INDIRECT_EXPORT, 0, JSEXN_SYNTAXERR, "indirect export not found")
|
||||||
MSG_DEF(JSMSG_AMBIGUOUS_INDIRECT_EXPORT, 1, JSEXN_SYNTAXERR, "ambiguous indirect export '{0}'")
|
MSG_DEF(JSMSG_AMBIGUOUS_INDIRECT_EXPORT, 0, JSEXN_SYNTAXERR, "ambiguous indirect export")
|
||||||
MSG_DEF(JSMSG_MISSING_IMPORT, 1, JSEXN_SYNTAXERR, "import '{0}' not found")
|
MSG_DEF(JSMSG_MISSING_IMPORT, 0, JSEXN_SYNTAXERR, "import not found")
|
||||||
MSG_DEF(JSMSG_AMBIGUOUS_IMPORT, 1, JSEXN_SYNTAXERR, "ambiguous import '{0}'")
|
MSG_DEF(JSMSG_AMBIGUOUS_IMPORT, 0, JSEXN_SYNTAXERR, "ambiguous import")
|
||||||
MSG_DEF(JSMSG_MISSING_NAMESPACE_EXPORT, 0, JSEXN_SYNTAXERR, "export not found for namespace")
|
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_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_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
|
// Promise
|
||||||
MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.")
|
MSG_DEF(JSMSG_CANNOT_RESOLVE_PROMISE_WITH_ITSELF, 0, JSEXN_TYPEERR, "A promise cannot be resolved with itself.")
|
||||||
|
|
|
@ -4704,21 +4704,21 @@ JS::GetModuleHostDefinedField(JSObject* module)
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(bool)
|
JS_PUBLIC_API(bool)
|
||||||
JS::ModuleDeclarationInstantiation(JSContext* cx, JS::HandleObject moduleArg)
|
JS::ModuleInstantiate(JSContext* cx, JS::HandleObject moduleArg)
|
||||||
{
|
{
|
||||||
AssertHeapIsIdle(cx);
|
AssertHeapIsIdle(cx);
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
assertSameCompartment(cx, moduleArg);
|
assertSameCompartment(cx, moduleArg);
|
||||||
return ModuleObject::DeclarationInstantiation(cx, moduleArg.as<ModuleObject>());
|
return ModuleObject::Instantiate(cx, moduleArg.as<ModuleObject>());
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(bool)
|
JS_PUBLIC_API(bool)
|
||||||
JS::ModuleEvaluation(JSContext* cx, JS::HandleObject moduleArg)
|
JS::ModuleEvaluate(JSContext* cx, JS::HandleObject moduleArg)
|
||||||
{
|
{
|
||||||
AssertHeapIsIdle(cx);
|
AssertHeapIsIdle(cx);
|
||||||
CHECK_REQUEST(cx);
|
CHECK_REQUEST(cx);
|
||||||
assertSameCompartment(cx, moduleArg);
|
assertSameCompartment(cx, moduleArg);
|
||||||
return ModuleObject::Evaluation(cx, moduleArg.as<ModuleObject>());
|
return ModuleObject::Evaluate(cx, moduleArg.as<ModuleObject>());
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject*)
|
JS_PUBLIC_API(JSObject*)
|
||||||
|
@ -4739,6 +4739,18 @@ JS::GetModuleScript(JSContext* cx, JS::HandleObject moduleArg)
|
||||||
return moduleArg->as<ModuleObject>().script();
|
return moduleArg->as<ModuleObject>().script();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(bool)
|
||||||
|
JS::IsModuleErrored(JSObject* moduleArg)
|
||||||
|
{
|
||||||
|
return moduleArg->as<ModuleObject>().status() == MODULE_STATUS_ERRORED;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_PUBLIC_API(JS::Value)
|
||||||
|
JS::GetModuleError(JSObject* moduleArg)
|
||||||
|
{
|
||||||
|
return moduleArg->as<ModuleObject>().error();
|
||||||
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject*)
|
JS_PUBLIC_API(JSObject*)
|
||||||
JS_New(JSContext* cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
|
JS_New(JSContext* cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4356,28 +4356,27 @@ extern JS_PUBLIC_API(JS::Value)
|
||||||
GetModuleHostDefinedField(JSObject* module);
|
GetModuleHostDefinedField(JSObject* module);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform the ModuleDeclarationInstantiation operation on on the give source
|
* Perform the ModuleInstantiate operation on the given source text module
|
||||||
* text module record.
|
* record.
|
||||||
*
|
*
|
||||||
* This transitively resolves all module dependencies (calling the
|
* This transitively resolves all module dependencies (calling the
|
||||||
* HostResolveImportedModule hook) and initializes the environment record for
|
* HostResolveImportedModule hook) and initializes the environment record for
|
||||||
* the module.
|
* the module.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API(bool)
|
extern JS_PUBLIC_API(bool)
|
||||||
ModuleDeclarationInstantiation(JSContext* cx, JS::HandleObject moduleRecord);
|
ModuleInstantiate(JSContext* cx, JS::HandleObject moduleRecord);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform the ModuleEvaluation operation on on the give source text module
|
* Perform the ModuleEvaluate operation on the given source text module record.
|
||||||
* record.
|
|
||||||
*
|
*
|
||||||
* This does nothing if this module has already been evaluated. Otherwise, it
|
* This does nothing if this module has already been evaluated. Otherwise, it
|
||||||
* transitively evaluates all dependences of this module and then evaluates this
|
* transitively evaluates all dependences of this module and then evaluates this
|
||||||
* module.
|
* module.
|
||||||
*
|
*
|
||||||
* ModuleDeclarationInstantiation must have completed prior to calling this.
|
* ModuleInstantiate must have completed prior to calling this.
|
||||||
*/
|
*/
|
||||||
extern JS_PUBLIC_API(bool)
|
extern JS_PUBLIC_API(bool)
|
||||||
ModuleEvaluation(JSContext* cx, JS::HandleObject moduleRecord);
|
ModuleEvaluate(JSContext* cx, JS::HandleObject moduleRecord);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a list of the module specifiers used by a source text module
|
* Get a list of the module specifiers used by a source text module
|
||||||
|
@ -4396,6 +4395,12 @@ GetRequestedModules(JSContext* cx, JS::HandleObject moduleRecord);
|
||||||
extern JS_PUBLIC_API(JSScript*)
|
extern JS_PUBLIC_API(JSScript*)
|
||||||
GetModuleScript(JSContext* cx, JS::HandleObject moduleRecord);
|
GetModuleScript(JSContext* cx, JS::HandleObject moduleRecord);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(bool)
|
||||||
|
IsModuleErrored(JSObject* moduleRecord);
|
||||||
|
|
||||||
|
extern JS_PUBLIC_API(JS::Value)
|
||||||
|
GetModuleError(JSObject* moduleRecord);
|
||||||
|
|
||||||
} /* namespace JS */
|
} /* namespace JS */
|
||||||
|
|
||||||
extern JS_PUBLIC_API(bool)
|
extern JS_PUBLIC_API(bool)
|
||||||
|
|
|
@ -227,8 +227,8 @@
|
||||||
macro(missingArguments, missingArguments, "missingArguments") \
|
macro(missingArguments, missingArguments, "missingArguments") \
|
||||||
macro(module, module, "module") \
|
macro(module, module, "module") \
|
||||||
macro(Module, Module, "Module") \
|
macro(Module, Module, "Module") \
|
||||||
macro(ModuleDeclarationInstantiation, ModuleDeclarationInstantiation, "ModuleDeclarationInstantiation") \
|
macro(ModuleInstantiate, ModuleInstantiate, "ModuleInstantiate") \
|
||||||
macro(ModuleEvaluation, ModuleEvaluation, "ModuleEvaluation") \
|
macro(ModuleEvaluate, ModuleEvaluate, "ModuleEvaluate") \
|
||||||
macro(month, month, "month") \
|
macro(month, month, "month") \
|
||||||
macro(multiline, multiline, "multiline") \
|
macro(multiline, multiline, "multiline") \
|
||||||
macro(name, name, "name") \
|
macro(name, name, "name") \
|
||||||
|
|
|
@ -345,6 +345,50 @@ intrinsic_ThrowInternalError(JSContext* cx, unsigned argc, Value* vp)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
intrinsic_GetErrorMessage(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
MOZ_ASSERT(args.length() == 1);
|
||||||
|
MOZ_ASSERT(args[0].isInt32());
|
||||||
|
|
||||||
|
const JSErrorFormatString* errorString = GetErrorMessage(nullptr, args[0].toInt32());
|
||||||
|
MOZ_ASSERT(errorString);
|
||||||
|
|
||||||
|
MOZ_ASSERT(errorString->argCount == 0);
|
||||||
|
RootedString message(cx, JS_NewStringCopyZ(cx, errorString->format));
|
||||||
|
if (!message)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
args.rval().setString(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
intrinsic_CreateModuleSyntaxError(JSContext* cx, unsigned argc, Value* vp)
|
||||||
|
{
|
||||||
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
|
MOZ_ASSERT(args.length() == 4);
|
||||||
|
MOZ_ASSERT(args[0].isObject());
|
||||||
|
MOZ_ASSERT(args[1].isInt32());
|
||||||
|
MOZ_ASSERT(args[2].isInt32());
|
||||||
|
MOZ_ASSERT(args[3].isString());
|
||||||
|
|
||||||
|
RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
|
||||||
|
RootedString filename(cx, JS_NewStringCopyZ(cx, module->script()->filename()));
|
||||||
|
RootedString message(cx, args[3].toString());
|
||||||
|
|
||||||
|
RootedValue error(cx);
|
||||||
|
if (!JS::CreateError(cx, JSEXN_SYNTAXERR, nullptr, filename, args[1].toInt32(),
|
||||||
|
args[2].toInt32(), nullptr, message, &error))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.rval().set(error);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles an assertion failure in self-hosted code just like an assertion
|
* Handles an assertion failure in self-hosted code just like an assertion
|
||||||
* failure in C++ code. Information about the failure can be provided in args[0].
|
* failure in C++ code. Information about the failure can be provided in args[0].
|
||||||
|
@ -2060,24 +2104,12 @@ intrinsic_InstantiateModuleFunctionDeclarations(JSContext* cx, unsigned argc, Va
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
intrinsic_SetModuleState(JSContext* cx, unsigned argc, Value* vp)
|
intrinsic_ExecuteModule(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)
|
|
||||||
{
|
{
|
||||||
CallArgs args = CallArgsFromVp(argc, vp);
|
CallArgs args = CallArgsFromVp(argc, vp);
|
||||||
MOZ_ASSERT(args.length() == 1);
|
MOZ_ASSERT(args.length() == 1);
|
||||||
RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
|
RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
|
||||||
return ModuleObject::evaluate(cx, module, args.rval());
|
return ModuleObject::execute(cx, module, args.rval());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -2351,6 +2383,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||||
JS_FN("ThrowTypeError", intrinsic_ThrowTypeError, 4,0),
|
JS_FN("ThrowTypeError", intrinsic_ThrowTypeError, 4,0),
|
||||||
JS_FN("ThrowSyntaxError", intrinsic_ThrowSyntaxError, 4,0),
|
JS_FN("ThrowSyntaxError", intrinsic_ThrowSyntaxError, 4,0),
|
||||||
JS_FN("ThrowInternalError", intrinsic_ThrowInternalError, 4,0),
|
JS_FN("ThrowInternalError", intrinsic_ThrowInternalError, 4,0),
|
||||||
|
JS_FN("GetErrorMessage", intrinsic_GetErrorMessage, 1,0),
|
||||||
|
JS_FN("CreateModuleSyntaxError", intrinsic_CreateModuleSyntaxError, 4,0),
|
||||||
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1,0),
|
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1,0),
|
||||||
JS_FN("DumpMessage", intrinsic_DumpMessage, 1,0),
|
JS_FN("DumpMessage", intrinsic_DumpMessage, 1,0),
|
||||||
JS_FN("OwnPropertyKeys", intrinsic_OwnPropertyKeys, 1,0),
|
JS_FN("OwnPropertyKeys", intrinsic_OwnPropertyKeys, 1,0),
|
||||||
|
@ -2630,8 +2664,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||||
JS_FN("CreateNamespaceBinding", intrinsic_CreateNamespaceBinding, 3, 0),
|
JS_FN("CreateNamespaceBinding", intrinsic_CreateNamespaceBinding, 3, 0),
|
||||||
JS_FN("InstantiateModuleFunctionDeclarations",
|
JS_FN("InstantiateModuleFunctionDeclarations",
|
||||||
intrinsic_InstantiateModuleFunctionDeclarations, 1, 0),
|
intrinsic_InstantiateModuleFunctionDeclarations, 1, 0),
|
||||||
JS_FN("SetModuleState", intrinsic_SetModuleState, 1, 0),
|
JS_FN("ExecuteModule", intrinsic_ExecuteModule, 1, 0),
|
||||||
JS_FN("EvaluateModule", intrinsic_EvaluateModule, 1, 0),
|
|
||||||
JS_FN("NewModuleNamespace", intrinsic_NewModuleNamespace, 2, 0),
|
JS_FN("NewModuleNamespace", intrinsic_NewModuleNamespace, 2, 0),
|
||||||
JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
|
JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
|
||||||
JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
|
JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
|
||||||
|
|
Loading…
Reference in New Issue