Bug 916255 - Allow script loaders to have multiple in flight off thread parses (r=bz)

This commit is contained in:
Brian Hacket 2013-12-05 14:55:31 -06:00
parent ffa4f41c94
commit f0abb0946d
2 changed files with 45 additions and 45 deletions

View File

@ -717,62 +717,64 @@ namespace {
class NotifyOffThreadScriptLoadCompletedRunnable : public nsRunnable class NotifyOffThreadScriptLoadCompletedRunnable : public nsRunnable
{ {
nsRefPtr<nsScriptLoader> mLoader; nsRefPtr<nsScriptLoadRequest> mRequest;
void *mToken; nsRefPtr<nsScriptLoader> mLoader;
void *mToken;
public: public:
NotifyOffThreadScriptLoadCompletedRunnable(already_AddRefed<nsScriptLoader> aLoader, NotifyOffThreadScriptLoadCompletedRunnable(nsScriptLoadRequest* aRequest,
void *aToken) nsScriptLoader* aLoader)
: mLoader(aLoader), mToken(aToken) : mRequest(aRequest), mLoader(aLoader), mToken(NULL)
{} {}
NS_DECL_NSIRUNNABLE void SetToken(void* aToken) {
MOZ_ASSERT(aToken && !mToken);
mToken = aToken;
}
NS_DECL_NSIRUNNABLE
}; };
} /* anonymous namespace */ } /* anonymous namespace */
nsresult nsresult
nsScriptLoader::ProcessOffThreadRequest(void **aOffThreadToken) nsScriptLoader::ProcessOffThreadRequest(nsScriptLoadRequest* aRequest, void **aOffThreadToken)
{ {
nsCOMPtr<nsScriptLoadRequest> request = mOffThreadScriptRequest; nsresult rv = ProcessRequest(aRequest, aOffThreadToken);
mOffThreadScriptRequest = nullptr; mDocument->UnblockOnload(false);
nsresult rv = ProcessRequest(request, aOffThreadToken); return rv;
mDocument->UnblockOnload(false);
return rv;
} }
NS_IMETHODIMP NS_IMETHODIMP
NotifyOffThreadScriptLoadCompletedRunnable::Run() NotifyOffThreadScriptLoadCompletedRunnable::Run()
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
nsresult rv = mLoader->ProcessOffThreadRequest(&mToken); nsresult rv = mLoader->ProcessOffThreadRequest(mRequest, &mToken);
if (mToken) { if (mToken) {
// The result of the off thread parse was not actually needed to process // The result of the off thread parse was not actually needed to process
// the request (disappearing window, some other error, ...). Finish the // the request (disappearing window, some other error, ...). Finish the
// request to avoid leaks in the JS engine. // request to avoid leaks in the JS engine.
nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1"); nsCOMPtr<nsIJSRuntimeService> svc = do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE); NS_ENSURE_TRUE(svc, NS_ERROR_FAILURE);
JSRuntime *rt; JSRuntime *rt;
svc->GetRuntime(&rt); svc->GetRuntime(&rt);
NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE); NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE);
JS::FinishOffThreadScript(nullptr, rt, mToken); JS::FinishOffThreadScript(nullptr, rt, mToken);
} }
return rv; return rv;
} }
static void static void
OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData) OffThreadScriptLoaderCallback(void *aToken, void *aCallbackData)
{ {
// Be careful not to adjust the refcount on the loader, as this callback NotifyOffThreadScriptLoadCompletedRunnable* aRunnable =
// may be invoked off the main thread. static_cast<NotifyOffThreadScriptLoadCompletedRunnable*>(aCallbackData);
nsScriptLoader* aLoader = static_cast<nsScriptLoader*>(aCallbackData); aRunnable->SetToken(aToken);
nsRefPtr<NotifyOffThreadScriptLoadCompletedRunnable> notify = NS_DispatchToMainThread(aRunnable);
new NotifyOffThreadScriptLoadCompletedRunnable( NS_RELEASE(aRunnable);
already_AddRefed<nsScriptLoader>(aLoader), aToken);
NS_DispatchToMainThread(notify);
} }
nsresult nsresult
@ -782,10 +784,6 @@ nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
if (mOffThreadScriptRequest) {
return NS_ERROR_FAILURE;
}
JSObject *unrootedGlobal; JSObject *unrootedGlobal;
nsCOMPtr<nsIScriptContext> context = GetScriptContext(&unrootedGlobal); nsCOMPtr<nsIScriptContext> context = GetScriptContext(&unrootedGlobal);
if (!context) { if (!context) {
@ -801,17 +799,19 @@ nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
mOffThreadScriptRequest = aRequest; NotifyOffThreadScriptLoadCompletedRunnable* runnable =
new NotifyOffThreadScriptLoadCompletedRunnable(aRequest, this);
// This reference will be consumed by OffThreadScriptLoaderCallback.
NS_ADDREF(runnable);
if (!JS::CompileOffThread(cx, global, options, if (!JS::CompileOffThread(cx, global, options,
aRequest->mScriptText.get(), aRequest->mScriptText.Length(), aRequest->mScriptText.get(), aRequest->mScriptText.Length(),
OffThreadScriptLoaderCallback, OffThreadScriptLoaderCallback,
static_cast<void*>(this))) { static_cast<void*>(runnable))) {
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
// This reference will be consumed by the NotifyOffThreadScriptLoadCompletedRunnable.
NS_ADDREF(this);
mDocument->BlockOnload(); mDocument->BlockOnload();
return NS_OK; return NS_OK;

View File

@ -211,7 +211,8 @@ public:
* Process a request that was deferred so that the script could be compiled * Process a request that was deferred so that the script could be compiled
* off thread. * off thread.
*/ */
nsresult ProcessOffThreadRequest(void **aOffThreadToken); nsresult ProcessOffThreadRequest(nsScriptLoadRequest *aRequest,
void **aOffThreadToken);
private: private:
/** /**
@ -316,7 +317,6 @@ private:
}; };
nsTArray<PreloadInfo> mPreloads; nsTArray<PreloadInfo> mPreloads;
nsCOMPtr<nsScriptLoadRequest> mOffThreadScriptRequest;
nsCOMPtr<nsIScriptElement> mCurrentScript; nsCOMPtr<nsIScriptElement> mCurrentScript;
nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript; nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript;
// XXXbz do we want to cycle-collect these or something? Not sure. // XXXbz do we want to cycle-collect these or something? Not sure.