diff options
author | Moonchild <moonchild@palemoon.org> | 2020-07-06 20:31:14 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2020-07-06 20:31:14 +0000 |
commit | c053de708817a3b7c90edcd53fe3742007b8a41e (patch) | |
tree | d616be09d75333065416cb35432eac7b821c4aa9 /dom/script | |
parent | fd602fbffbaf8e7d7e58c9ffe9b0b188cb7c65de (diff) | |
parent | 2dff89b658d6ab2592865c226f3f1078f418151d (diff) | |
download | UXP-c053de708817a3b7c90edcd53fe3742007b8a41e.tar UXP-c053de708817a3b7c90edcd53fe3742007b8a41e.tar.gz UXP-c053de708817a3b7c90edcd53fe3742007b8a41e.tar.lz UXP-c053de708817a3b7c90edcd53fe3742007b8a41e.tar.xz UXP-c053de708817a3b7c90edcd53fe3742007b8a41e.zip |
Merge branch 'es-modules-work'
Diffstat (limited to 'dom/script')
-rw-r--r-- | dom/script/ModuleLoadRequest.cpp | 53 | ||||
-rw-r--r-- | dom/script/ModuleLoadRequest.h | 6 | ||||
-rw-r--r-- | dom/script/ModuleScript.cpp | 80 | ||||
-rw-r--r-- | dom/script/ModuleScript.h | 28 | ||||
-rw-r--r-- | dom/script/ScriptLoader.cpp | 263 | ||||
-rw-r--r-- | dom/script/ScriptLoader.h | 1 |
6 files changed, 260 insertions, 171 deletions
diff --git a/dom/script/ModuleLoadRequest.cpp b/dom/script/ModuleLoadRequest.cpp index e72edca2e..d62214304 100644 --- a/dom/script/ModuleLoadRequest.cpp +++ b/dom/script/ModuleLoadRequest.cpp @@ -43,15 +43,29 @@ void ModuleLoadRequest::Cancel() ScriptLoadRequest::Cancel(); mModuleScript = nullptr; 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++) { mImports[i]->Cancel(); } - mReady.RejectIfExists(NS_ERROR_FAILURE, __func__); } void 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 for (size_t i = 0; i < mImports.Length(); i++) { MOZ_ASSERT(mImports[i]->IsReadyToRun()); @@ -69,30 +83,53 @@ ModuleLoadRequest::ModuleLoaded() // been loaded. mModuleScript = mLoader->GetFetchedModule(mURI); + if (!mModuleScript || mModuleScript->IsErrored()) { + ModuleErrored(); + return; + } + mLoader->StartFetchingModuleDependencies(this); } void +ModuleLoadRequest::ModuleErrored() +{ + mLoader->CheckModuleDependenciesLoaded(this); + MOZ_ASSERT(!mModuleScript || mModuleScript->IsErrored()); + + CancelImports(); + SetReady(); + LoadFinished(); +} + +void ModuleLoadRequest::DependenciesLoaded() { // The module and all of its dependencies have been successfully fetched and // compiled. - if (!mLoader->InstantiateModuleTree(this)) { - LoadFailed(); - return; - } + MOZ_ASSERT(mModuleScript); + mLoader->CheckModuleDependenciesLoaded(this); SetReady(); - mLoader->ProcessLoadedModuleTree(this); - mLoader = nullptr; - mParent = nullptr; + LoadFinished(); } void 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(); + LoadFinished(); +} + +void +ModuleLoadRequest::LoadFinished() +{ mLoader->ProcessLoadedModuleTree(this); mLoader = nullptr; mParent = nullptr; diff --git a/dom/script/ModuleLoadRequest.h b/dom/script/ModuleLoadRequest.h index 0119fad38..7b06dd2cf 100644 --- a/dom/script/ModuleLoadRequest.h +++ b/dom/script/ModuleLoadRequest.h @@ -45,9 +45,15 @@ public: void Cancel() override; void ModuleLoaded(); + void ModuleErrored(); void DependenciesLoaded(); void LoadFailed(); +private: + void LoadFinished(); + void CancelImports(); + +public: // Is this a request for a top level module script or an import? bool mIsTopLevel; diff --git a/dom/script/ModuleScript.cpp b/dom/script/ModuleScript.cpp index 34ef4dec4..28b97a3cb 100644 --- a/dom/script/ModuleScript.cpp +++ b/dom/script/ModuleScript.cpp @@ -26,6 +26,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript) NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader) NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL) tmp->UnlinkModuleRecord(); + tmp->mError.setUndefined(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END 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_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_COLLECTING_ADDREF(ModuleScript) NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript) -ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL, - JS::Handle<JSObject*> aModuleRecord) +ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL) : mLoader(aLoader), - mBaseURL(aBaseURL), - mModuleRecord(aModuleRecord), - mInstantiationState(Uninstantiated) + mBaseURL(aBaseURL) { MOZ_ASSERT(mLoader); MOZ_ASSERT(mBaseURL); - MOZ_ASSERT(mModuleRecord); - MOZ_ASSERT(mException.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); + MOZ_ASSERT(!mModuleRecord); + MOZ_ASSERT(mError.isUndefined()); } void @@ -66,34 +59,63 @@ ModuleScript::UnlinkModuleRecord() MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() == this); JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue()); + mModuleRecord = nullptr; } - mModuleRecord = nullptr; - mException.setUndefined(); } ModuleScript::~ModuleScript() { - if (mModuleRecord) { - // The object may be destroyed without being unlinked first. - UnlinkModuleRecord(); - } + // The object may be destroyed without being unlinked first. + UnlinkModuleRecord(); DropJSObjects(this); } void -ModuleScript::SetInstantiationResult(JS::Handle<JS::Value> aMaybeException) +ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord) { - MOZ_ASSERT(mInstantiationState == Uninstantiated); - MOZ_ASSERT(mModuleRecord); - MOZ_ASSERT(mException.isUndefined()); + MOZ_ASSERT(!mModuleRecord); + MOZ_ASSERT(mError.isUndefined()); - if (aMaybeException.isUndefined()) { - mInstantiationState = Instantiated; - } else { - mModuleRecord = nullptr; - mException = aMaybeException; - mInstantiationState = Errored; + mModuleRecord = aModuleRecord; + + // 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 +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 diff --git a/dom/script/ModuleScript.h b/dom/script/ModuleScript.h index dd0d07e84..571359859 100644 --- a/dom/script/ModuleScript.h +++ b/dom/script/ModuleScript.h @@ -20,17 +20,10 @@ class ScriptLoader; class ModuleScript final : public nsISupports { - enum InstantiationState { - Uninstantiated, - Instantiated, - Errored - }; - RefPtr<ScriptLoader> mLoader; nsCOMPtr<nsIURI> mBaseURL; JS::Heap<JSObject*> mModuleRecord; - JS::Heap<JS::Value> mException; - InstantiationState mInstantiationState; + JS::Heap<JS::Value> mError; ~ModuleScript(); @@ -39,24 +32,17 @@ public: NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript) ModuleScript(ScriptLoader* aLoader, - nsIURI* aBaseURL, - JS::Handle<JSObject*> aModuleRecord); + nsIURI* aBaseURL); + + void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord); + void SetPreInstantiationError(const JS::Value& aError); ScriptLoader* Loader() const { return mLoader; } JSObject* ModuleRecord() const { return mModuleRecord; } - JS::Value Exception() const { return mException; } nsIURI* BaseURL() const { return mBaseURL; } - void SetInstantiationResult(JS::Handle<JS::Value> aMaybeException); - bool IsUninstantiated() const { - return mInstantiationState == Uninstantiated; - } - bool IsInstantiated() const { - return mInstantiationState == Instantiated; - } - bool InstantiationFailed() const { - return mInstantiationState == Errored; - } + bool IsErrored() const; + JS::Value Error() const; void UnlinkModuleRecord(); }; diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp index adc046b7c..a53098974 100644 --- a/dom/script/ScriptLoader.cpp +++ b/dom/script/ScriptLoader.cpp @@ -418,21 +418,23 @@ void ScriptLoader::SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *aRequest, nsresult aResult) { - // Update module map with the result of fetching a single module script. The - // module script pointer is nullptr on error. - - MOZ_ASSERT(!aRequest->IsReadyToRun()); + // Update module map with the result of fetching a single module script. + // + // If any requests for the same URL are waiting on this one to complete, they + // will have ModuleLoaded or LoadFailed on them when the promise is + // resolved/rejected. This is set up in StartLoad. RefPtr<GenericPromise::Private> promise; MOZ_ALWAYS_TRUE(mFetchingModules.Get(aRequest->mURI, getter_AddRefs(promise))); mFetchingModules.Remove(aRequest->mURI); - RefPtr<ModuleScript> ms(aRequest->mModuleScript); - MOZ_ASSERT(NS_SUCCEEDED(aResult) == (ms != nullptr)); - mFetchedModules.Put(aRequest->mURI, ms); + RefPtr<ModuleScript> moduleScript(aRequest->mModuleScript); + MOZ_ASSERT(NS_FAILED(aResult) == !moduleScript); + + mFetchedModules.Put(aRequest->mURI, moduleScript); if (promise) { - if (ms) { + if (moduleScript) { promise->Resolve(true, __func__); } else { promise->Reject(aResult, __func__); @@ -478,19 +480,29 @@ ScriptLoader::ProcessFetchedModuleSource(ModuleLoadRequest* aRequest) MOZ_ASSERT(!aRequest->mModuleScript); nsresult rv = CreateModuleScript(aRequest); + MOZ_ASSERT(NS_FAILED(rv) == !aRequest->mModuleScript); + SetModuleFetchFinishedAndResumeWaitingRequests(aRequest, rv); free(aRequest->mScriptTextBuf); aRequest->mScriptTextBuf = nullptr; aRequest->mScriptTextLength = 0; - if (NS_SUCCEEDED(rv)) { + if (NS_FAILED(rv)) { + aRequest->LoadFailed(); + return rv; + } + + if (!aRequest->mModuleScript->IsErrored()) { StartFetchingModuleDependencies(aRequest); } - return rv; + return NS_OK; } +static nsresult +ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>& aUrls); + nsresult ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest) { @@ -544,9 +556,34 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest) } } MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr)); - if (module) { - aRequest->mModuleScript = - new ModuleScript(this, aRequest->mBaseURL, module); + RefPtr<ModuleScript> moduleScript = new ModuleScript(this, aRequest->mBaseURL); + aRequest->mModuleScript = moduleScript; + + 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 -ThrowTypeError(JSContext* aCx, ModuleScript* aScript, - const nsString& aMessage) +CreateTypeError(JSContext* aCx, ModuleScript* aScript, const nsString& aMessage, + JS::MutableHandle<JS::Value> aError) { JS::Rooted<JSObject*> module(aCx, aScript->ModuleRecord()); JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aCx, module)); @@ -572,17 +609,11 @@ ThrowTypeError(JSContext* aCx, ModuleScript* aScript, return false; } - JS::Rooted<JS::Value> error(aCx); - if (!JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, filename, 0, 0, nullptr, - message, &error)) { - return false; - } - - JS_SetPendingException(aCx, error); - return false; + return JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, filename, 0, 0, nullptr, + message, aError); } -static bool +static nsresult HandleResolveFailure(JSContext* aCx, ModuleScript* aScript, const nsAString& aSpecifier) { @@ -591,19 +622,13 @@ HandleResolveFailure(JSContext* aCx, ModuleScript* aScript, nsAutoString message(NS_LITERAL_STRING("Error resolving module specifier: ")); message.Append(aSpecifier); - return ThrowTypeError(aCx, aScript, message); -} - -static bool -HandleModuleNotFound(JSContext* aCx, ModuleScript* aScript, - 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); + JS::Rooted<JS::Value> error(aCx); + if (!CreateTypeError(aCx, aScript, message, &error)) { + return NS_ERROR_OUT_OF_MEMORY; + } - return ThrowTypeError(aCx, aScript, message); + aScript->SetPreInstantiationError(error); + return NS_OK; } static already_AddRefed<nsIURI> @@ -701,7 +726,8 @@ ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI> &aUrls) ModuleScript* ms = aRequest->mModuleScript; nsCOMPtr<nsIURI> uri = ResolveModuleSpecifier(ms, specifier); if (!uri) { - HandleResolveFailure(cx, ms, specifier); + nsresult rv = HandleResolveFailure(cx, ms, specifier); + NS_ENSURE_SUCCESS(rv, rv); return NS_ERROR_FAILURE; } @@ -720,13 +746,15 @@ void ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest) { MOZ_ASSERT(aRequest->mModuleScript); + MOZ_ASSERT(!aRequest->mModuleScript->IsErrored()); MOZ_ASSERT(!aRequest->IsReadyToRun()); + aRequest->mProgress = ModuleLoadRequest::Progress::FetchingImports; nsCOMArray<nsIURI> urls; nsresult rv = ResolveRequestedModules(aRequest, urls); if (NS_FAILED(rv)) { - aRequest->LoadFailed(); + aRequest->ModuleErrored(); return; } @@ -750,7 +778,7 @@ ScriptLoader::StartFetchingModuleDependencies(ModuleLoadRequest* aRequest) GenericPromise::All(AbstractThread::GetCurrent(), importsReady); allReady->Then(AbstractThread::GetCurrent(), __func__, aRequest, &ModuleLoadRequest::DependenciesLoaded, - &ModuleLoadRequest::LoadFailed); + &ModuleLoadRequest::ModuleErrored); } RefPtr<GenericPromise> @@ -773,6 +801,7 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest, nsresult rv = StartLoad(childRequest, NS_LITERAL_STRING("module"), false); if (NS_FAILED(rv)) { + MOZ_ASSERT(!childRequest->mModuleScript); childRequest->mReady.Reject(rv, __func__); return ready; } @@ -781,6 +810,7 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest, return ready; } +// 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier) bool 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); // Let url be the result of resolving a module specifier given referencing - // module script and specifier. If the result is failure, throw a TypeError - // exception and abort these steps. + // module script and specifier. nsAutoJSString string; if (!string.init(aCx, specifier)) { return false; } 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 - // key is url. If no such entry exists, throw a TypeError exception and abort - // these steps. + // This cannot fail because resolving a module specifier must have been + // previously successful with these same two arguments. + 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); - if (!ms) { - return HandleModuleNotFound(aCx, script, string); - } + MOZ_ASSERT(ms, "Resolved module not found in module map"); - if (ms->InstantiationFailed()) { - JS::Rooted<JS::Value> exception(aCx, ms->Exception()); - JS_SetPendingException(aCx, exception); - return false; - } + MOZ_ASSERT(!ms->IsErrored()); *vp = JS::ObjectValue(*ms->ModuleRecord()); return true; @@ -844,9 +868,35 @@ EnsureModuleResolveHook(JSContext* aCx) } 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 ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest) { if (aRequest->IsTopLevel()) { + ModuleScript* moduleScript = aRequest->mModuleScript; + if (moduleScript && !moduleScript->IsErrored()) { + if (!InstantiateModuleTree(aRequest)) { + aRequest->mModuleScript = nullptr; + } + } MaybeMoveToLoadedList(aRequest); ProcessPendingRequests(); } @@ -859,60 +909,35 @@ ScriptLoader::ProcessLoadedModuleTree(ModuleLoadRequest* aRequest) bool 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->IsTopLevel()); - ModuleScript* ms = aRequest->mModuleScript; - MOZ_ASSERT(ms); - if (!ms || !ms->ModuleRecord()) { - return false; - } + ModuleScript* moduleScript = aRequest->mModuleScript; + MOZ_ASSERT(moduleScript); + MOZ_ASSERT(moduleScript->ModuleRecord()); + nsAutoMicroTask mt; AutoJSAPI jsapi; - if (NS_WARN_IF(!jsapi.Init(ms->ModuleRecord()))) { + if (NS_WARN_IF(!jsapi.Init(moduleScript->ModuleRecord()))) { return false; } nsresult rv = EnsureModuleResolveHook(jsapi.cx()); NS_ENSURE_SUCCESS(rv, false); - JS::Rooted<JSObject*> module(jsapi.cx(), ms->ModuleRecord()); - bool ok = NS_SUCCEEDED(nsJSUtils::ModuleDeclarationInstantiation(jsapi.cx(), module)); + JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord()); + bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module)); - JS::RootedValue exception(jsapi.cx()); if (!ok) { MOZ_ASSERT(jsapi.HasException()); + JS::RootedValue exception(jsapi.cx()); if (!jsapi.StealException(&exception)) { return false; } MOZ_ASSERT(!exception.isUndefined()); - } - - // 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; - } - } + // Ignore the exception. It will be recorded in the module record. } return true; @@ -1427,13 +1452,19 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) ModuleLoadRequest* modReq = request->AsModuleRequest(); modReq->mBaseURL = mDocument->GetDocBaseURI(); rv = CreateModuleScript(modReq); - NS_ENSURE_SUCCESS(rv, false); - StartFetchingModuleDependencies(modReq); + MOZ_ASSERT(NS_FAILED(rv) == !modReq->mModuleScript); + if (NS_FAILED(rv)) { + modReq->LoadFailed(); + return false; + } if (aElement->GetScriptAsync()) { mLoadingAsyncRequests.AppendElement(request); } else { AddDeferRequest(request); } + if (!modReq->mModuleScript->IsErrored()) { + StartFetchingModuleDependencies(modReq); + } return false; } request->mProgress = ScriptLoadRequest::Progress::Ready; @@ -1511,11 +1542,7 @@ ScriptLoader::ProcessOffThreadRequest(ScriptLoadRequest* aRequest) if (aRequest->IsModuleRequest()) { MOZ_ASSERT(aRequest->mOffThreadToken); ModuleLoadRequest* request = aRequest->AsModuleRequest(); - nsresult rv = ProcessFetchedModuleSource(request); - if (NS_FAILED(rv)) { - request->LoadFailed(); - } - return rv; + return ProcessFetchedModuleSource(request); } aRequest->SetReady(); @@ -1687,7 +1714,7 @@ ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest) if (aRequest->IsModuleRequest() && !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); return NS_OK; } @@ -1909,8 +1936,8 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) // http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block nsAutoMicroTask mt; AutoEntryScript aes(globalObject, "<script> element", true); - JS::Rooted<JSObject*> global(aes.cx(), - globalObject->GetGlobalJSObject()); + JSContext* cx = aes.cx(); + JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject()); bool oldProcessingScriptTag = context->GetProcessingScriptTag(); context->SetProcessingScriptTag(true); @@ -1931,28 +1958,38 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) } if (aRequest->IsModuleRequest()) { + rv = EnsureModuleResolveHook(cx); + NS_ENSURE_SUCCESS(rv, rv); + ModuleLoadRequest* request = aRequest->AsModuleRequest(); MOZ_ASSERT(request->mModuleScript); MOZ_ASSERT(!request->mOffThreadToken); - ModuleScript* ms = request->mModuleScript; - MOZ_ASSERT(!ms->IsUninstantiated()); - if (ms->InstantiationFailed()) { - JS::Rooted<JS::Value> exception(aes.cx(), ms->Exception()); - JS_SetPendingException(aes.cx(), exception); - rv = NS_ERROR_FAILURE; - } else { - JS::Rooted<JSObject*> module(aes.cx(), ms->ModuleRecord()); - MOZ_ASSERT(module); - rv = nsJSUtils::ModuleEvaluation(aes.cx(), module); + + ModuleScript* moduleScript = request->mModuleScript; + if (moduleScript->IsErrored()) { + // Module has an error status + JS::Rooted<JS::Value> error(cx, moduleScript->Error()); + JS_SetPendingException(cx, error); + return NS_OK; // An error is reported by AutoEntryScript. + } + + 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 { - JS::CompileOptions options(aes.cx()); + JS::CompileOptions options(cx); rv = FillCompileOptionsForRequest(aes, aRequest, global, &options); if (NS_SUCCEEDED(rv)) { nsAutoString inlineData; SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData); - rv = nsJSUtils::EvaluateString(aes.cx(), srcBuf, global, options, + rv = nsJSUtils::EvaluateString(cx, srcBuf, global, options, aRequest->OffThreadTokenPtr()); } } diff --git a/dom/script/ScriptLoader.h b/dom/script/ScriptLoader.h index 3c428deea..e6b75bf3b 100644 --- a/dom/script/ScriptLoader.h +++ b/dom/script/ScriptLoader.h @@ -580,6 +580,7 @@ private: nsresult CreateModuleScript(ModuleLoadRequest* aRequest); nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest); + void CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest); void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest); bool InstantiateModuleTree(ModuleLoadRequest* aRequest); void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest); |