Issue #2387 - Collection of fixes related to a crash while canceling a dynamic import. Add AddRef/Release hooks for embedding's script or module private value and set this script source object where appropriate. https://bugzilla.mozilla.org/show_bug.cgi?id=1519140 Partial, no Value passing changes. Clear the list of dynamic import requests after cancelling them in ScriptLoader::ParsingComplete as we do for other requests. https://bugzilla.mozilla.org/show_bug.cgi?id=1291535 ScriptLoader::OnStreamComplete never returns a failure. https://bugzilla.mozilla.org/show_bug.cgi?id=1627275 Also cancel the correct kind of parser for Modules.

This commit is contained in:
Brian Smith 2023-11-27 23:30:25 -06:00 committed by roytam1
commit eef37b2cd5
10 changed files with 100 additions and 54 deletions

View file

@ -62,20 +62,33 @@ void LoadedScript::AssociateWithScript(JSScript* aScript) {
AddRef();
}
void HostFinalizeTopLevelScript(JSFreeOp* aFop, const JS::Value& aPrivate) {
// Decrement the reference count of a LoadedScript object that is
// pointed to by a dying JSScript. The reference count was
// originally incremented by AssociateWithScript() above.
auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
inline void CheckModuleScriptPrivate(LoadedScript* script,
const JS::Value& aPrivate) {
#ifdef DEBUG
if (script->IsModuleScript()) {
JSObject* module = script->AsModuleScript()->mModuleRecord.unbarrieredGet();
MOZ_ASSERT_IF(module, JS::GetModulePrivate(module) == aPrivate);
}
#endif
}
void HostAddRefTopLevelScript(const JS::Value& aPrivate) {
// Increment the reference count of a LoadedScript object that is now pointed
// to by a JSScript. The reference count is decremented by
// HostReleaseTopLevelScript() below.
auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
CheckModuleScriptPrivate(script, aPrivate);
script->AddRef();
}
void HostReleaseTopLevelScript(const JS::Value& aPrivate) {
// Decrement the reference count of a LoadedScript object that was pointed to
// by a JSScript. The reference count was originally incremented by
// HostAddRefTopLevelScript() above.
auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
CheckModuleScriptPrivate(script, aPrivate);
script->Release();
}
@ -132,7 +145,6 @@ ModuleScript::UnlinkModuleRecord()
this);
JS::SetModulePrivate(mModuleRecord, JS::UndefinedValue());
mModuleRecord = nullptr;
Release();
}
}
@ -157,7 +169,6 @@ ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).isUndefined());
JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this));
HoldJSObjects(this);
AddRef();
}
void

View file

@ -18,7 +18,8 @@ namespace dom {
class ScriptLoader;
void HostFinalizeTopLevelScript(JSFreeOp* aFop, const JS::Value& aPrivate);
void HostAddRefTopLevelScript(const JS::Value& aPrivate);
void HostReleaseTopLevelScript(const JS::Value& aPrivate);
class ClassicScript;
class ModuleScript;
@ -63,7 +64,6 @@ class ClassicScript final : public LoadedScript
class ModuleScript final : public LoadedScript
{
JS::Heap<JSObject*> mModuleRecord;
JS::Heap<JS::Value> mParseError;
JS::Heap<JS::Value> mErrorToRethrow;
@ -74,6 +74,8 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ModuleScript,
LoadedScript)
JS::Heap<JSObject*> mModuleRecord;
ModuleScript(ScriptFetchOptions* aFetchOptions, nsIURI* aBaseURL);
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
@ -89,7 +91,7 @@ public:
void UnlinkModuleRecord();
friend void HostFinalizeTopLevelScript(JSFreeOp*, const JS::Value&);
friend void CheckModuleScriptPrivate(LoadedScript*, const JS::Value&);
};
ClassicScript* LoadedScript::AsClassicScript() {

View file

@ -185,7 +185,11 @@ ScriptLoadRequest::MaybeCancelOffThreadScript()
}
JSContext* cx = danger::GetJSContext();
JS::CancelOffThreadScript(cx, mOffThreadToken);
if (IsModuleRequest()) {
JS::CancelOffThreadModule(cx, mOffThreadToken);
} else {
JS::CancelOffThreadScript(cx, mOffThreadToken);
}
mOffThreadToken = nullptr;
}
@ -1109,8 +1113,9 @@ void ScriptLoader::EnsureModuleHooksInitialized() {
JS::SetModuleResolveHook(rt, HostResolveImportedModule);
JS::SetModuleMetadataHook(jsapi.cx(), HostPopulateImportMeta);
JS::SetScriptPrivateFinalizeHook(jsapi.cx(), HostFinalizeTopLevelScript);
JS::SetScriptPrivateReferenceHooks(jsapi.cx(), HostAddRefTopLevelScript,
HostReleaseTopLevelScript);
Preferences::RegisterCallbackAndCall(DynamicImportPrefChangedCallback,
"javascript.options.dynamicImport",
(void*)nullptr);
@ -2648,7 +2653,7 @@ ScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
// Process our request and/or any pending ones
ProcessPendingRequests();
return NS_OK;
return rv;
}
nsresult
@ -2758,6 +2763,9 @@ ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult) {
if (aRequest->isInList()) {
RefPtr<ScriptLoadRequest> req = mDynamicImportRequests.Steal(aRequest);
modReq->Cancel();
// FinishDynamicImport must happen exactly once for each dynamic import
// request. If the load is aborted we do it when we remove the request
// from mDynamicImportRequests.
FinishDynamicImport(modReq, aResult);
}
} else {
@ -2979,8 +2987,12 @@ ScriptLoader::ParsingComplete(bool aTerminated)
for (ScriptLoadRequest* req = mDynamicImportRequests.getFirst(); req;
req = req->getNext()) {
req->Cancel();
// FinishDynamicImport must happen exactly once for each dynamic import
// request. If the load is aborted we do it when we remove the request
// from mDynamicImportRequests.
FinishDynamicImport(req->AsModuleRequest(), NS_ERROR_ABORT);
}
mDynamicImportRequests.Clear();
if (mParserBlockingRequest) {
mParserBlockingRequest->Cancel();