Skip to content

Commit 8054f6d

Browse files
committed
Bug 1820594 - Part 23: Error handling when module fetching failed. r=jonco
Differential Revision: https://phabricator.services.mozilla.com/D228860
1 parent f793f2b commit 8054f6d

File tree

3 files changed

+95
-1
lines changed

3 files changed

+95
-1
lines changed

js/loader/ModuleLoadRequest.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "ModuleLoadRequest.h"
88

9+
#include "mozilla/DebugOnly.h"
910
#include "mozilla/HoldDropJSObjects.h"
1011
#include "mozilla/dom/ScriptLoadContext.h"
1112

@@ -168,7 +169,12 @@ void ModuleLoadRequest::ModuleErrored() {
168169
MOZ_ASSERT(!IsFinished());
169170

170171
CheckModuleDependenciesLoaded();
171-
MOZ_ASSERT(IsErrored());
172+
mozilla::DebugOnly<bool> hasRethrow =
173+
mModuleScript && mModuleScript->HasErrorToRethrow();
174+
175+
// When LoadRequestedModules fails, we will set error to rethrow to the module
176+
// script and call ModuleErrored().
177+
MOZ_ASSERT(IsErrored() || hasRethrow);
172178

173179
CancelImports();
174180
if (IsFinished()) {

js/loader/ModuleLoaderBase.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,8 @@ void ModuleLoaderBase::ResumeWaitingRequest(ModuleLoadRequest* aRequest,
720720

721721
if (!aRequest->IsErrored()) {
722722
OnFetchSucceeded(aRequest);
723+
} else {
724+
OnFetchFailed(aRequest);
723725
}
724726
}
725727

@@ -789,6 +791,8 @@ nsresult ModuleLoaderBase::OnFetchComplete(ModuleLoadRequest* aRequest,
789791

790792
if (!aRequest->IsErrored()) {
791793
OnFetchSucceeded(aRequest);
794+
} else {
795+
OnFetchFailed(aRequest);
792796
}
793797

794798
if (!waitingRequests) {
@@ -816,6 +820,71 @@ void ModuleLoaderBase::OnFetchSucceeded(ModuleLoadRequest* aRequest) {
816820
}
817821
}
818822

823+
void ModuleLoaderBase::OnFetchFailed(ModuleLoadRequest* aRequest) {
824+
MOZ_ASSERT(aRequest->IsErrored());
825+
// For dynamic import, the error handling is done in ProcessDynamicImport
826+
if (aRequest->IsDynamicImport()) {
827+
return;
828+
}
829+
830+
if (aRequest->IsTopLevel()) {
831+
// https://html.spec.whatwg.org/#fetch-the-descendants-of-and-link-a-module-script
832+
// Step 2. If record is null, then:
833+
// Step 2.1. Set moduleScript's error to rethrow to moduleScript's parse
834+
// error.
835+
if (aRequest->mModuleScript && !aRequest->mModuleScript->ModuleRecord()) {
836+
MOZ_ASSERT(aRequest->mModuleScript->HasParseError());
837+
JS::Value parseError = aRequest->mModuleScript->ParseError();
838+
LOG(("ScriptLoadRequest (%p): found parse error", aRequest));
839+
aRequest->mModuleScript->SetErrorToRethrow(parseError);
840+
}
841+
} else {
842+
// The remaining case is static import.
843+
AutoJSAPI jsapi;
844+
if (!jsapi.Init(mGlobalObject)) {
845+
return;
846+
}
847+
JSContext* cx = jsapi.cx();
848+
849+
MOZ_ASSERT(!aRequest->mStatePrivate.isUndefined());
850+
JS::Rooted<JS::Value> statePrivate(cx, aRequest->mStatePrivate);
851+
JS::Rooted<JS::Value> error(cx);
852+
853+
// https://html.spec.whatwg.org/#hostloadimportedmodule
854+
//
855+
// Step 14.2. If moduleScript is null, then set completion to Completion
856+
// Record { [[Type]]: throw, [[Value]]: a new TypeError,
857+
// [[Target]]: empty }.
858+
//
859+
// Impl note:
860+
// When moduleScript is null, the ScriptLoader will call onerror handler.
861+
// So we don't actually create a TypeError for this.
862+
if (!aRequest->mModuleScript) {
863+
error = UndefinedValue();
864+
} else {
865+
// Step 14.3. Otherwise, if moduleScript's parse error is not null, then:
866+
// 1. Let parseError be moduleScript's parse error.
867+
// 2. Set completion to Completion Record { [[Type]]: throw,
868+
// [[Value]]: parseError, [[Target]]: empty }.
869+
// 3. If loadState is not undefined and loadState.[[ErrorToRethrow]]
870+
// is null, set loadState.[[ErrorToRethrow]] to parseError.
871+
MOZ_ASSERT(aRequest->mModuleScript->HasParseError());
872+
error = aRequest->mModuleScript->ParseError();
873+
}
874+
875+
LOG(("ScriptLoadRequest (%p): FinishLoadingImportedModuleFailed",
876+
aRequest));
877+
// Step 14.5. Perform FinishLoadingImportedModule(referrer, moduleRequest,
878+
// payload, completion).
879+
JS::FinishLoadingImportedModuleFailed(cx, statePrivate, nullptr, error);
880+
881+
aRequest->mReferrerObj = nullptr;
882+
aRequest->mReferencingPrivate.setUndefined();
883+
aRequest->mModuleRequestObj = nullptr;
884+
aRequest->mStatePrivate.setUndefined();
885+
}
886+
}
887+
819888
nsresult ModuleLoaderBase::CreateModuleScript(ModuleLoadRequest* aRequest) {
820889
MOZ_ASSERT(!aRequest->mModuleScript);
821890
MOZ_ASSERT(aRequest->mBaseURL);
@@ -1081,6 +1150,22 @@ static bool OnLoadRequestedModulesResolvedImpl(ModuleLoadRequest* aRequest) {
10811150
static bool OnLoadRequestedModulesRejectedImpl(ModuleLoadRequest* aRequest,
10821151
Handle<JS::Value> error) {
10831152
LOG(("ScriptLoadRequest (%p): LoadRequestedModules rejected", aRequest));
1153+
ModuleScript* moduleScript = aRequest->mModuleScript;
1154+
// https://html.spec.whatwg.org/#fetch-the-descendants-of-and-link-a-module-script
1155+
// Step 7. Upon rejection of loadingPromise, run the following
1156+
// steps:
1157+
// Step 7.1. If state.[[ErrorToRethrow]] is not null, set moduleScript's
1158+
// error to rethrow to state.[[ErrorToRethrow]] and run
1159+
// onComplete given moduleScript.
1160+
if (moduleScript && !error.isUndefined()) {
1161+
moduleScript->SetErrorToRethrow(error);
1162+
} else {
1163+
// Step 7.2. Otherwise, run onComplete given null.
1164+
aRequest->mModuleScript = nullptr;
1165+
}
1166+
1167+
aRequest->ModuleErrored();
1168+
10841169
// Decrease the reference 'AddRef'ed when converting the hostDefined.
10851170
aRequest->Release();
10861171
return true;
@@ -1275,6 +1360,7 @@ void ModuleLoaderBase::StartFetchingModuleAndDependencies(
12751360
MOZ_ASSERT(!childRequest->mModuleScript);
12761361
mLoader->ReportErrorToConsole(childRequest, rv);
12771362
childRequest->LoadFailed();
1363+
OnFetchFailed(childRequest);
12781364
}
12791365
}
12801366

@@ -1440,6 +1526,7 @@ bool ModuleLoaderBase::HasPendingDynamicImports() const {
14401526
return !mDynamicImportRequests.isEmpty();
14411527
}
14421528

1529+
// TODO: Bug 1968890 : Update error handling for dynamic import
14431530
void ModuleLoaderBase::CancelDynamicImport(ModuleLoadRequest* aRequest,
14441531
nsresult aResult) {
14451532
// aRequest may have already been unlinked by CC.

js/loader/ModuleLoaderBase.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ class ModuleLoaderBase : public nsISupports {
567567
bool IsFetchingAndHasWaitingRequest(ModuleLoadRequest* aRequest);
568568

569569
void OnFetchSucceeded(ModuleLoadRequest* aRequest);
570+
void OnFetchFailed(ModuleLoadRequest* aRequest);
570571

571572
// The slot stored in ImportMetaResolve function.
572573
enum class ImportMetaSlots : uint32_t { ModulePrivateSlot = 0, SlotCount };

0 commit comments

Comments
 (0)