diff --git a/content/base/src/nsScriptLoader.cpp b/content/base/src/nsScriptLoader.cpp index 616d8c787da7..99e5aa9db7ea 100644 --- a/content/base/src/nsScriptLoader.cpp +++ b/content/base/src/nsScriptLoader.cpp @@ -697,64 +697,62 @@ namespace { class NotifyOffThreadScriptLoadCompletedRunnable : public nsRunnable { - nsRefPtr mRequest; - nsRefPtr mLoader; - void *mToken; + nsRefPtr mLoader; + void *mToken; public: - NotifyOffThreadScriptLoadCompletedRunnable(nsScriptLoadRequest* aRequest, - nsScriptLoader* aLoader) - : mRequest(aRequest), mLoader(aLoader), mToken(NULL) - {} + NotifyOffThreadScriptLoadCompletedRunnable(already_AddRefed aLoader, + void *aToken) + : mLoader(aLoader), mToken(aToken) + {} - void SetToken(void* aToken) { - MOZ_ASSERT(aToken && !mToken); - mToken = aToken; - } - - NS_DECL_NSIRUNNABLE + NS_DECL_NSIRUNNABLE }; } /* anonymous namespace */ nsresult -nsScriptLoader::ProcessOffThreadRequest(nsScriptLoadRequest* aRequest, void **aOffThreadToken) +nsScriptLoader::ProcessOffThreadRequest(void **aOffThreadToken) { - nsresult rv = ProcessRequest(aRequest, aOffThreadToken); - mDocument->UnblockOnload(false); - return rv; + nsCOMPtr request = mOffThreadScriptRequest; + mOffThreadScriptRequest = nullptr; + mDocument->UnblockOnload(false); + + return ProcessRequest(request, aOffThreadToken); } NS_IMETHODIMP NotifyOffThreadScriptLoadCompletedRunnable::Run() { - MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(NS_IsMainThread()); - nsresult rv = mLoader->ProcessOffThreadRequest(mRequest, &mToken); + nsresult rv = mLoader->ProcessOffThreadRequest(&mToken); - if (mToken) { - // The result of the off thread parse was not actually needed to process - // the request (disappearing window, some other error, ...). Finish the - // request to avoid leaks in the JS engine. - nsCOMPtr svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1"); - NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE); - JSRuntime *rt; - svc->GetRuntime(&rt); - NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE); - JS::FinishOffThreadScript(nullptr, rt, mToken); - } + if (mToken) { + // The result of the off thread parse was not actually needed to process + // the request (disappearing window, some other error, ...). Finish the + // request to avoid leaks in the JS engine. + nsCOMPtr svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1"); + NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE); + JSRuntime *rt; + svc->GetRuntime(&rt); + NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE); + JS::FinishOffThreadScript(nullptr, rt, mToken); + } - return rv; + return rv; } static void OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData) { - NotifyOffThreadScriptLoadCompletedRunnable* aRunnable = - static_cast(aCallbackData); - aRunnable->SetToken(aToken); - NS_DispatchToMainThread(aRunnable); - NS_RELEASE(aRunnable); + // Be careful not to adjust the refcount on the loader, as this callback + // may be invoked off the main thread. + nsScriptLoader* aLoader = static_cast(aCallbackData); + nsRefPtr notify = + new NotifyOffThreadScriptLoadCompletedRunnable( + already_AddRefed(aLoader), aToken); + NS_DispatchToMainThread(notify); } nsresult @@ -764,6 +762,10 @@ nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest) return NS_ERROR_FAILURE; } + if (mOffThreadScriptRequest) { + return NS_ERROR_FAILURE; + } + JSObject *unrootedGlobal; nsCOMPtr context = GetScriptContext(&unrootedGlobal); if (!context) { @@ -779,18 +781,16 @@ nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest) return NS_ERROR_FAILURE; } - nsRefPtr runnable = - new NotifyOffThreadScriptLoadCompletedRunnable(aRequest, this); - + mOffThreadScriptRequest = aRequest; if (!JS::CompileOffThread(cx, global, options, aRequest->mScriptText.get(), aRequest->mScriptText.Length(), OffThreadScriptLoaderCallback, - static_cast(runnable))) { + static_cast(this))) { return NS_ERROR_OUT_OF_MEMORY; } - // This reference will be consumed by OffThreadScriptLoaderCallback. - runnable.forget(); + // This reference will be consumed by the NotifyOffThreadScriptLoadCompletedRunnable. + NS_ADDREF(this); mDocument->BlockOnload(); diff --git a/content/base/src/nsScriptLoader.h b/content/base/src/nsScriptLoader.h index a54009dfc8b4..1fee28c9db67 100644 --- a/content/base/src/nsScriptLoader.h +++ b/content/base/src/nsScriptLoader.h @@ -211,8 +211,7 @@ public: * Process a request that was deferred so that the script could be compiled * off thread. */ - nsresult ProcessOffThreadRequest(nsScriptLoadRequest *aRequest, - void **aOffThreadToken); + nsresult ProcessOffThreadRequest(void **aOffThreadToken); private: /** @@ -317,6 +316,7 @@ private: }; nsTArray mPreloads; + nsCOMPtr mOffThreadScriptRequest; nsCOMPtr mCurrentScript; nsCOMPtr mCurrentParserInsertedScript; // XXXbz do we want to cycle-collect these or something? Not sure.