Backed out 3 changesets (bug 1809861) for causing bustages in ScriptLoader.cpp. CLOSED TREE

Backed out changeset d8b7cb85d87f (bug 1809861)
Backed out changeset fa4190d9f97e (bug 1809861)
Backed out changeset 15b4b4f318a7 (bug 1809861)
This commit is contained in:
Stanca Serban 2023-01-17 17:56:26 +02:00
Родитель 81b02b3d13
Коммит 6a0d860e76
4 изменённых файлов: 348 добавлений и 325 удалений

Просмотреть файл

@ -37,8 +37,9 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ScriptLoadContext,
JS::loader::LoadContextBase)
MOZ_ASSERT(!tmp->mOffThreadToken);
MOZ_ASSERT(!tmp->mRunnable);
if (Runnable* runnable = tmp->mRunnable.exchange(nullptr)) {
runnable->Release();
}
tmp->MaybeUnblockOnload();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -69,12 +70,16 @@ ScriptLoadContext::ScriptLoadContext()
mUnreportedPreloadError(NS_OK) {}
ScriptLoadContext::~ScriptLoadContext() {
MOZ_ASSERT(NS_IsMainThread());
// Off-thread parsing must have completed by this point.
MOZ_DIAGNOSTIC_ASSERT(!mOffThreadToken && !mRunnable);
// When speculative parsing is enabled, it is possible to off-main-thread
// compile scripts that are never executed. These should be cleaned up here
// if they exist.
mRequest = nullptr;
MOZ_ASSERT_IF(
!StaticPrefs::
dom_script_loader_external_scripts_speculative_omt_parse_enabled(),
!mOffThreadToken);
MaybeCancelOffThreadScript();
MaybeUnblockOnload();
}
@ -99,18 +104,17 @@ void ScriptLoadContext::MaybeCancelOffThreadScript() {
return;
}
// Cancel parse if it hasn't been started yet or wait for it to finish and
// clean up finished parse data.
JSContext* cx = danger::GetJSContext();
JS::CancelOffThreadToken(cx, mOffThreadToken);
mOffThreadToken = nullptr;
// Clear the pointer to the runnable. It may still run later if we didn't
// cancel in time. In this case the runnable is held live by the reference
// passed to Dispatch, which is dropped after it runs.
mRunnable = nullptr;
// Cancellation request above should guarantee removal of the parse task, so
// releasing the runnable should be safe to do here.
if (Runnable* runnable = mRunnable.exchange(nullptr)) {
runnable->Release();
}
MaybeUnblockOnload();
mOffThreadToken = nullptr;
}
void ScriptLoadContext::SetScriptMode(bool aDeferAttr, bool aAsyncAttr,

Просмотреть файл

@ -153,6 +153,9 @@ class ScriptLoadContext : public JS::loader::LoadContextBase,
void MaybeCancelOffThreadScript();
TimeStamp mOffThreadParseStartTime;
TimeStamp mOffThreadParseStopTime;
ScriptMode mScriptMode; // Whether this is a blocking, defer or async script.
bool mScriptFromHead; // Synchronous head script block loading of other non
// js/css content.
@ -169,13 +172,11 @@ class ScriptLoadContext : public JS::loader::LoadContextBase,
bool mWasCompiledOMT; // True if the script has been compiled off main
// thread.
// Off-thread parsing token. Set at the start of off-thread parsing and
// cleared when the result of the parse is used.
JS::OffThreadToken* mOffThreadToken;
JS::OffThreadToken* mOffThreadToken; // Off-thread parsing token.
// Runnable that is dispatched to the main thread when off-thread compilation
// completes.
RefPtr<Runnable> mRunnable;
Atomic<Runnable*> mRunnable; // Runnable created when dispatching off thread
// compile. Tracked here so that it can be
// properly released during cancellation.
int32_t mLineNo;

Просмотреть файл

@ -1384,6 +1384,48 @@ ReferrerPolicy ScriptLoader::GetReferrerPolicy(nsIScriptElement* aElement) {
return mDocument->GetReferrerPolicy();
}
namespace {
class NotifyOffThreadScriptLoadCompletedRunnable : public Runnable {
RefPtr<ScriptLoadRequest> mRequest;
RefPtr<ScriptLoader> mLoader;
nsCOMPtr<nsISerialEventTarget> mEventTarget;
JS::OffThreadToken* mToken;
public:
ScriptLoadRequest* GetScriptLoadRequest() { return mRequest; }
NotifyOffThreadScriptLoadCompletedRunnable(ScriptLoadRequest* aRequest,
ScriptLoader* aLoader)
: Runnable("dom::NotifyOffThreadScriptLoadCompletedRunnable"),
mRequest(aRequest),
mLoader(aLoader),
mToken(nullptr) {
MOZ_ASSERT(NS_IsMainThread());
if (DocGroup* docGroup = aLoader->GetDocGroup()) {
mEventTarget = docGroup->EventTargetFor(TaskCategory::Other);
}
}
virtual ~NotifyOffThreadScriptLoadCompletedRunnable();
void SetToken(JS::OffThreadToken* aToken) {
MOZ_ASSERT(aToken && !mToken);
mToken = aToken;
}
static void Dispatch(
already_AddRefed<NotifyOffThreadScriptLoadCompletedRunnable>&& aSelf) {
RefPtr<NotifyOffThreadScriptLoadCompletedRunnable> self = aSelf;
nsCOMPtr<nsISerialEventTarget> eventTarget = self->mEventTarget;
eventTarget->Dispatch(self.forget());
}
NS_DECL_NSIRUNNABLE
};
} /* anonymous namespace */
void ScriptLoader::CancelScriptLoadRequests() {
// Cancel all requests that have not been executed.
if (mParserBlockingRequest) {
@ -1423,298 +1465,8 @@ void ScriptLoader::CancelScriptLoadRequests() {
mOffThreadCompilingRequests.CancelRequestsAndClear();
}
nsresult ScriptLoader::CompileOffThreadOrProcessRequest(
ScriptLoadRequest* aRequest) {
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
"Processing requests when running scripts is unsafe.");
if (!aRequest->GetScriptLoadContext()->mOffThreadToken &&
!aRequest->GetScriptLoadContext()->CompileStarted()) {
bool couldCompile = false;
nsresult rv = AttemptOffThreadScriptCompile(aRequest, &couldCompile);
if (NS_FAILED(rv)) {
HandleLoadError(aRequest, rv);
return rv;
}
if (couldCompile) {
return NS_OK;
}
}
return ProcessRequest(aRequest);
}
namespace {
class OffThreadCompilationCompleteRunnable : public Runnable {
nsMainThreadPtrHandle<ScriptLoadRequest> mRequest;
nsMainThreadPtrHandle<ScriptLoader> mLoader;
nsCOMPtr<nsISerialEventTarget> mEventTarget;
JS::OffThreadToken* mToken;
TimeStamp mStartTime;
TimeStamp mStopTime;
public:
OffThreadCompilationCompleteRunnable(ScriptLoadRequest* aRequest,
ScriptLoader* aLoader)
: Runnable("dom::OffThreadCompilationCompleteRunnable"),
mRequest(new nsMainThreadPtrHolder("mRequest", aRequest)),
mLoader(new nsMainThreadPtrHolder("mLoader", aLoader)),
mToken(nullptr) {
MOZ_ASSERT(NS_IsMainThread());
if (DocGroup* docGroup = aLoader->GetDocGroup()) {
mEventTarget = docGroup->EventTargetFor(TaskCategory::Other);
}
}
void RecordStartTime() { mStartTime = TimeStamp::Now(); }
void RecordStopTime() { mStopTime = TimeStamp::Now(); }
void SetToken(JS::OffThreadToken* aToken) {
MOZ_ASSERT(aToken && !mToken);
mToken = aToken;
}
static void Dispatch(
already_AddRefed<OffThreadCompilationCompleteRunnable>&& aSelf) {
RefPtr<OffThreadCompilationCompleteRunnable> self = aSelf;
nsCOMPtr<nsISerialEventTarget> eventTarget = self->mEventTarget;
eventTarget->Dispatch(self.forget());
}
NS_DECL_NSIRUNNABLE
};
} /* anonymous namespace */
nsresult ScriptLoader::AttemptOffThreadScriptCompile(
ScriptLoadRequest* aRequest, bool* aCouldCompileOut) {
// If speculative parsing is enabled, the request may not be ready to run if
// the element is not yet available.
MOZ_ASSERT_IF(!SpeculativeOMTParsingEnabled() && !aRequest->IsModuleRequest(),
aRequest->IsReadyToRun());
MOZ_ASSERT(!aRequest->GetScriptLoadContext()->mWasCompiledOMT);
MOZ_ASSERT(aCouldCompileOut && !*aCouldCompileOut);
// Don't off-thread compile inline scripts.
if (aRequest->GetScriptLoadContext()->mIsInline) {
return NS_OK;
}
nsCOMPtr<nsIGlobalObject> globalObject = GetGlobalForRequest(aRequest);
if (!globalObject) {
return NS_ERROR_FAILURE;
}
AutoJSAPI jsapi;
if (!jsapi.Init(globalObject)) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
JS::CompileOptions options(cx);
// Introduction script will actually be computed and set when the script is
// collected from offthread
JS::Rooted<JSScript*> dummyIntroductionScript(cx);
nsresult rv = FillCompileOptionsForRequest(cx, aRequest, &options,
&dummyIntroductionScript);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (aRequest->IsTextSource()) {
if (!JS::CanCompileOffThread(cx, options, aRequest->ScriptTextLength())) {
TRACE_FOR_TEST(aRequest->GetScriptLoadContext()->GetScriptElement(),
"scriptloader_main_thread_compile");
return NS_OK;
}
} else {
MOZ_ASSERT(aRequest->IsBytecode());
size_t length =
aRequest->mScriptBytecode.length() - aRequest->mBytecodeOffset;
JS::DecodeOptions decodeOptions(options);
if (!JS::CanDecodeOffThread(cx, decodeOptions, length)) {
return NS_OK;
}
}
RefPtr<OffThreadCompilationCompleteRunnable> runnable =
new OffThreadCompilationCompleteRunnable(aRequest, this);
// Emulate dispatch. CompileOffThreadModule will call
// OffThreadCompilationCompleteCallback were we will emulate run.
LogRunnable::LogDispatch(runnable);
runnable->RecordStartTime();
JS::OffThreadToken* token = nullptr;
rv = StartOffThreadCompilation(cx, aRequest, options, runnable, &token);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(token);
aRequest->GetScriptLoadContext()->mOffThreadToken = token;
aRequest->GetScriptLoadContext()->mRunnable = runnable;
aRequest->GetScriptLoadContext()->BlockOnload(mDocument);
// Once the compilation is finished, a callback will dispatch the runnable to
// the main thread to call ScriptLoader::ProcessOffThreadRequest for the
// request.
aRequest->mState = ScriptLoadRequest::State::Compiling;
// Requests that are not tracked elsewhere are added to a list while they are
// being compiled off-thread, so we can cancel the compilation later if
// necessary.
//
// Non-top-level modules not tracked because these are cancelled from their
// importing module.
if (aRequest->IsTopLevel() && !aRequest->isInList()) {
mOffThreadCompilingRequests.AppendElement(aRequest);
aRequest->GetScriptLoadContext()->mInCompilingList = true;
}
*aCouldCompileOut = true;
return NS_OK;
}
static inline nsresult CompileResultForToken(void* aToken) {
return aToken ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
nsresult ScriptLoader::StartOffThreadCompilation(
JSContext* aCx, ScriptLoadRequest* aRequest, JS::CompileOptions& aOptions,
Runnable* aRunnable, JS::OffThreadToken** aTokenOut) {
const JS::OffThreadCompileCallback callback =
OffThreadCompilationCompleteCallback;
if (aRequest->IsBytecode()) {
JS::DecodeOptions decodeOptions(aOptions);
*aTokenOut = JS::DecodeStencilOffThread(
aCx, decodeOptions, aRequest->mScriptBytecode,
aRequest->mBytecodeOffset, callback, aRunnable);
return CompileResultForToken(*aTokenOut);
}
MaybeSourceText maybeSource;
nsresult rv = aRequest->GetScriptSource(aCx, &maybeSource);
NS_ENSURE_SUCCESS(rv, rv);
if (aRequest->IsModuleRequest()) {
auto compile = [&](auto& source) {
return JS::CompileModuleToStencilOffThread(aCx, aOptions, source,
callback, aRunnable);
};
MOZ_ASSERT(!maybeSource.empty());
*aTokenOut = maybeSource.mapNonEmpty(compile);
return CompileResultForToken(*aTokenOut);
}
if (ShouldApplyDelazifyStrategy(aRequest)) {
ApplyDelazifyStrategy(&aOptions);
mTotalFullParseSize +=
aRequest->ScriptTextLength() > 0
? static_cast<uint32_t>(aRequest->ScriptTextLength())
: 0;
LOG(
("ScriptLoadRequest (%p): non-on-demand-only Parsing Enabled for "
"url=%s mTotalFullParseSize=%u",
aRequest, aRequest->mURI->GetSpecOrDefault().get(),
mTotalFullParseSize));
}
if (StaticPrefs::dom_expose_test_interfaces()) {
switch (aOptions.eagerDelazificationStrategy()) {
case JS::DelazificationOption::OnDemandOnly:
TRACE_FOR_TEST(aRequest->GetScriptLoadContext()->GetScriptElement(),
"delazification_on_demand_only");
break;
case JS::DelazificationOption::CheckConcurrentWithOnDemand:
case JS::DelazificationOption::ConcurrentDepthFirst:
TRACE_FOR_TEST(aRequest->GetScriptLoadContext()->GetScriptElement(),
"delazification_concurrent_depth_first");
break;
case JS::DelazificationOption::ConcurrentLargeFirst:
TRACE_FOR_TEST(aRequest->GetScriptLoadContext()->GetScriptElement(),
"delazification_concurrent_large_first");
break;
case JS::DelazificationOption::ParseEverythingEagerly:
TRACE_FOR_TEST(aRequest->GetScriptLoadContext()->GetScriptElement(),
"delazification_parse_everything_eagerly");
break;
}
}
auto compile = [&](auto& source) {
return JS::CompileToStencilOffThread(aCx, aOptions, source, callback,
aRunnable);
};
MOZ_ASSERT(!maybeSource.empty());
*aTokenOut = maybeSource.mapNonEmpty(compile);
return CompileResultForToken(*aTokenOut);
}
void ScriptLoader::OffThreadCompilationCompleteCallback(
JS::OffThreadToken* aToken, void* aCallbackData) {
RefPtr<OffThreadCompilationCompleteRunnable> aRunnable =
static_cast<OffThreadCompilationCompleteRunnable*>(aCallbackData);
LogRunnable::Run run(aRunnable);
aRunnable->RecordStopTime();
aRunnable->SetToken(aToken);
OffThreadCompilationCompleteRunnable::Dispatch(aRunnable.forget());
}
NS_IMETHODIMP
OffThreadCompilationCompleteRunnable::Run() {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<ScriptLoadContext> context = mRequest->GetScriptLoadContext();
MOZ_ASSERT_IF(context->mRunnable, context->mRunnable == this);
MOZ_ASSERT_IF(context->mOffThreadToken, context->mOffThreadToken == mToken);
// Clear the pointer to the runnable. The final reference will be released
// when this method returns.
context->mRunnable = nullptr;
if (!context->mOffThreadToken) {
// Request has been cancelled by MaybeCancelOffThreadScript.
return NS_OK;
}
if (profiler_is_active()) {
ProfilerString8View scriptSourceString;
if (mRequest->IsTextSource()) {
scriptSourceString = "ScriptCompileOffThread";
} else {
MOZ_ASSERT(mRequest->IsBytecode());
scriptSourceString = "BytecodeDecodeOffThread";
}
nsAutoCString profilerLabelString;
mRequest->GetScriptLoadContext()->GetProfilerLabel(profilerLabelString);
PROFILER_MARKER_TEXT(scriptSourceString, JS,
MarkerTiming::Interval(mStartTime, mStopTime),
profilerLabelString);
}
nsresult rv = mLoader->ProcessOffThreadRequest(mRequest);
mRequest = nullptr;
mLoader = nullptr;
return rv;
}
nsresult ScriptLoader::ProcessOffThreadRequest(ScriptLoadRequest* aRequest) {
MOZ_ASSERT(aRequest->IsCompiling());
MOZ_ASSERT(aRequest->mState == ScriptLoadRequest::State::Compiling);
MOZ_ASSERT(!aRequest->GetScriptLoadContext()->mWasCompiledOMT);
if (aRequest->IsCanceled()) {
@ -1774,6 +1526,282 @@ nsresult ScriptLoader::ProcessOffThreadRequest(ScriptLoadRequest* aRequest) {
return NS_OK;
}
NotifyOffThreadScriptLoadCompletedRunnable::
~NotifyOffThreadScriptLoadCompletedRunnable() {
if (MOZ_UNLIKELY(mRequest || mLoader) && !NS_IsMainThread()) {
NS_ReleaseOnMainThread(
"NotifyOffThreadScriptLoadCompletedRunnable::mRequest",
mRequest.forget());
NS_ReleaseOnMainThread(
"NotifyOffThreadScriptLoadCompletedRunnable::mLoader",
mLoader.forget());
}
}
NS_IMETHODIMP
NotifyOffThreadScriptLoadCompletedRunnable::Run() {
MOZ_ASSERT(NS_IsMainThread());
// We want these to be dropped on the main thread, once we return from this
// function.
RefPtr<ScriptLoadRequest> request = std::move(mRequest);
// Runnable pointer should have been cleared in the offthread callback.
MOZ_ASSERT(!request->GetScriptLoadContext()->mRunnable);
if (profiler_is_active()) {
ProfilerString8View scriptSourceString;
if (request->IsTextSource()) {
scriptSourceString = "ScriptCompileOffThread";
} else {
MOZ_ASSERT(request->IsBytecode());
scriptSourceString = "BytecodeDecodeOffThread";
}
nsAutoCString profilerLabelString;
request->GetScriptLoadContext()->GetProfilerLabel(profilerLabelString);
PROFILER_MARKER_TEXT(
scriptSourceString, JS,
MarkerTiming::Interval(
request->GetScriptLoadContext()->mOffThreadParseStartTime,
request->GetScriptLoadContext()->mOffThreadParseStopTime),
profilerLabelString);
}
RefPtr<ScriptLoader> loader = std::move(mLoader);
// Request was already cancelled at some earlier point.
if (!request->GetScriptLoadContext()->mOffThreadToken) {
return NS_OK;
}
return loader->ProcessOffThreadRequest(request);
}
static void OffThreadScriptLoaderCallback(JS::OffThreadToken* aToken,
void* aCallbackData) {
RefPtr<NotifyOffThreadScriptLoadCompletedRunnable> aRunnable = dont_AddRef(
static_cast<NotifyOffThreadScriptLoadCompletedRunnable*>(aCallbackData));
MOZ_ASSERT(
aRunnable.get() ==
aRunnable->GetScriptLoadRequest()->GetScriptLoadContext()->mRunnable);
aRunnable->GetScriptLoadRequest()
->GetScriptLoadContext()
->mOffThreadParseStopTime = TimeStamp::Now();
LogRunnable::Run run(aRunnable);
aRunnable->SetToken(aToken);
// If mRunnable was cleared then request was canceled so do nothing.
if (!aRunnable->GetScriptLoadRequest()
->GetScriptLoadContext()
->mRunnable.exchange(nullptr)) {
return;
}
NotifyOffThreadScriptLoadCompletedRunnable::Dispatch(aRunnable.forget());
}
nsresult ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
bool* aCouldCompileOut) {
// If speculative parsing is enabled, the request may not be ready to run if
// the element is not yet available.
MOZ_ASSERT_IF(!SpeculativeOMTParsingEnabled() && !aRequest->IsModuleRequest(),
aRequest->IsReadyToRun());
MOZ_ASSERT(!aRequest->GetScriptLoadContext()->mWasCompiledOMT);
MOZ_ASSERT(aCouldCompileOut && !*aCouldCompileOut);
// Don't off-thread compile inline scripts.
if (aRequest->GetScriptLoadContext()->mIsInline) {
return NS_OK;
}
nsCOMPtr<nsIGlobalObject> globalObject = GetGlobalForRequest(aRequest);
if (!globalObject) {
return NS_ERROR_FAILURE;
}
AutoJSAPI jsapi;
if (!jsapi.Init(globalObject)) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
JS::CompileOptions options(cx);
// Introduction script will actually be computed and set when the script is
// collected from offthread
JS::Rooted<JSScript*> dummyIntroductionScript(cx);
nsresult rv = FillCompileOptionsForRequest(cx, aRequest, &options,
&dummyIntroductionScript);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (aRequest->IsTextSource()) {
if (!JS::CanCompileOffThread(cx, options, aRequest->ScriptTextLength())) {
TRACE_FOR_TEST(aRequest->GetScriptLoadContext()->GetScriptElement(),
"scriptloader_main_thread_compile");
return NS_OK;
}
} else {
MOZ_ASSERT(aRequest->IsBytecode());
size_t length =
aRequest->mScriptBytecode.length() - aRequest->mBytecodeOffset;
JS::DecodeOptions decodeOptions(options);
if (!JS::CanDecodeOffThread(cx, decodeOptions, length)) {
return NS_OK;
}
}
RefPtr<NotifyOffThreadScriptLoadCompletedRunnable> runnable =
new NotifyOffThreadScriptLoadCompletedRunnable(aRequest, this);
// Emulate dispatch. CompileOffThreadModule will call
// OffThreadScriptLoaderCallback were we will emulate run.
LogRunnable::LogDispatch(runnable);
aRequest->GetScriptLoadContext()->mOffThreadParseStartTime = TimeStamp::Now();
// Save the runnable so it can be properly cleared during cancellation.
aRequest->GetScriptLoadContext()->mRunnable = runnable.get();
auto signalOOM = mozilla::MakeScopeExit(
[&aRequest]() { aRequest->GetScriptLoadContext()->mRunnable = nullptr; });
// The conditions should match ScriptLoadContext::MaybeCancelOffThreadScript.
if (aRequest->IsBytecode()) {
JS::DecodeOptions decodeOptions(options);
aRequest->GetScriptLoadContext()->mOffThreadToken =
JS::DecodeStencilOffThread(cx, decodeOptions, aRequest->mScriptBytecode,
aRequest->mBytecodeOffset,
OffThreadScriptLoaderCallback,
static_cast<void*>(runnable));
if (!aRequest->GetScriptLoadContext()->mOffThreadToken) {
return NS_ERROR_OUT_OF_MEMORY;
}
} else if (aRequest->IsModuleRequest()) {
MOZ_ASSERT(aRequest->IsTextSource());
MaybeSourceText maybeSource;
nsresult rv = aRequest->GetScriptSource(cx, &maybeSource);
NS_ENSURE_SUCCESS(rv, rv);
auto compile = [&](auto& source) {
return JS::CompileModuleToStencilOffThread(
cx, options, source, OffThreadScriptLoaderCallback, runnable.get());
};
MOZ_ASSERT(!maybeSource.empty());
JS::OffThreadToken* token = maybeSource.mapNonEmpty(compile);
if (!token) {
return NS_ERROR_OUT_OF_MEMORY;
}
aRequest->GetScriptLoadContext()->mOffThreadToken = token;
} else {
MOZ_ASSERT(aRequest->IsTextSource());
if (ShouldApplyDelazifyStrategy(aRequest)) {
ApplyDelazifyStrategy(&options);
mTotalFullParseSize +=
aRequest->ScriptTextLength() > 0
? static_cast<uint32_t>(aRequest->ScriptTextLength())
: 0;
LOG(
("ScriptLoadRequest (%p): non-on-demand-only Parsing Enabled for "
"url=%s mTotalFullParseSize=%u",
aRequest, aRequest->mURI->GetSpecOrDefault().get(),
mTotalFullParseSize));
}
MaybeSourceText maybeSource;
nsresult rv = aRequest->GetScriptSource(cx, &maybeSource);
NS_ENSURE_SUCCESS(rv, rv);
if (StaticPrefs::dom_expose_test_interfaces()) {
switch (options.eagerDelazificationStrategy()) {
case JS::DelazificationOption::OnDemandOnly:
TRACE_FOR_TEST(aRequest->GetScriptLoadContext()->GetScriptElement(),
"delazification_on_demand_only");
break;
case JS::DelazificationOption::CheckConcurrentWithOnDemand:
case JS::DelazificationOption::ConcurrentDepthFirst:
TRACE_FOR_TEST(aRequest->GetScriptLoadContext()->GetScriptElement(),
"delazification_concurrent_depth_first");
break;
case JS::DelazificationOption::ConcurrentLargeFirst:
TRACE_FOR_TEST(aRequest->GetScriptLoadContext()->GetScriptElement(),
"delazification_concurrent_large_first");
break;
case JS::DelazificationOption::ParseEverythingEagerly:
TRACE_FOR_TEST(aRequest->GetScriptLoadContext()->GetScriptElement(),
"delazification_parse_everything_eagerly");
break;
}
}
auto compile = [&](auto& source) {
return JS::CompileToStencilOffThread(
cx, options, source, OffThreadScriptLoaderCallback, runnable.get());
};
MOZ_ASSERT(!maybeSource.empty());
JS::OffThreadToken* token = maybeSource.mapNonEmpty(compile);
if (!token) {
return NS_ERROR_OUT_OF_MEMORY;
}
aRequest->GetScriptLoadContext()->mOffThreadToken = token;
}
signalOOM.release();
aRequest->GetScriptLoadContext()->BlockOnload(mDocument);
// Once the compilation is finished, an event would be added to the event loop
// to call ScriptLoader::ProcessOffThreadRequest with the same request.
aRequest->mState = ScriptLoadRequest::State::Compiling;
// Requests that are not tracked elsewhere are added to a list while they are
// being compiled off-thread, so we can cancel the compilation later if
// necessary.
//
// Non-top-level modules not tracked because these are cancelled from their
// importing module.
if (aRequest->IsTopLevel() && !aRequest->isInList()) {
mOffThreadCompilingRequests.AppendElement(aRequest);
aRequest->GetScriptLoadContext()->mInCompilingList = true;
}
*aCouldCompileOut = true;
Unused << runnable.forget();
return NS_OK;
}
nsresult ScriptLoader::CompileOffThreadOrProcessRequest(
ScriptLoadRequest* aRequest) {
NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
"Processing requests when running scripts is unsafe.");
if (!aRequest->GetScriptLoadContext()->mOffThreadToken &&
!aRequest->GetScriptLoadContext()->CompileStarted()) {
bool couldCompile = false;
nsresult rv = AttemptAsyncScriptCompile(aRequest, &couldCompile);
if (NS_FAILED(rv)) {
HandleLoadError(aRequest, rv);
return rv;
}
if (couldCompile) {
return NS_OK;
}
}
return ProcessRequest(aRequest);
}
nsresult ScriptLoader::ProcessRequest(ScriptLoadRequest* aRequest) {
LOG(("ScriptLoadRequest (%p): Process request", aRequest));
@ -3446,7 +3474,7 @@ nsresult ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
// Attempt to compile off main thread.
bool couldCompile = false;
rv = AttemptOffThreadScriptCompile(request, &couldCompile);
rv = AttemptAsyncScriptCompile(request, &couldCompile);
NS_ENSURE_SUCCESS(rv, rv);
if (couldCompile) {
return NS_OK;
@ -3465,7 +3493,7 @@ nsresult ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
if (ShouldCompileOffThread(aRequest)) {
MOZ_ASSERT(!aRequest->IsModuleRequest());
bool couldCompile = false;
nsresult rv = AttemptOffThreadScriptCompile(aRequest, &couldCompile);
nsresult rv = AttemptAsyncScriptCompile(aRequest, &couldCompile);
NS_ENSURE_SUCCESS(rv, rv);
if (couldCompile) {
MOZ_ASSERT(aRequest->mState == ScriptLoadRequest::State::Compiling,

Просмотреть файл

@ -576,18 +576,8 @@ class ScriptLoader final : public JS::loader::ScriptLoaderInterface {
void ReportPreloadErrorsToConsole(ScriptLoadRequest* aRequest);
nsresult AttemptOffThreadScriptCompile(ScriptLoadRequest* aRequest,
bool* aCouldCompileOut);
nsresult StartOffThreadCompilation(JSContext* aCx,
ScriptLoadRequest* aRequest,
JS::CompileOptions& aOptions,
Runnable* aRunnable,
JS::OffThreadToken** aTokenOut);
static void OffThreadCompilationCompleteCallback(JS::OffThreadToken* aToken,
void* aCallbackData);
nsresult AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
bool* aCouldCompileOut);
nsresult ProcessRequest(ScriptLoadRequest* aRequest);
nsresult CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest);
void FireScriptAvailable(nsresult aResult, ScriptLoadRequest* aRequest);