Confirmed users
770
edits
| Line 80: | Line 80: | ||
return worker.forget(); | return worker.forget(); | ||
} | } | ||
NS_IMETHODIMP | |||
WorkerRunnable::Run() | |||
{ | |||
bool targetIsWorkerThread = mBehavior == WorkerThreadModifyBusyCount || | |||
mBehavior == WorkerThreadUnchangedBusyCount; | |||
#ifdef DEBUG | |||
MOZ_ASSERT_IF(mCallingCancelWithinRun, targetIsWorkerThread); | |||
if (targetIsWorkerThread) { | |||
mWorkerPrivate->AssertIsOnWorkerThread(); | |||
} | |||
else { | |||
MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount); | |||
mWorkerPrivate->AssertIsOnParentThread(); | |||
} | |||
#endif | |||
if (IsCanceled() && !mCallingCancelWithinRun) { | |||
return NS_OK; | |||
} | |||
if (targetIsWorkerThread && | |||
mWorkerPrivate->AllPendingRunnablesShouldBeCanceled() && | |||
!IsCanceled() && !mCallingCancelWithinRun) { | |||
// Prevent recursion. | |||
mCallingCancelWithinRun = true; | |||
Cancel(); | |||
MOZ_ASSERT(mCallingCancelWithinRun); | |||
mCallingCancelWithinRun = false; | |||
MOZ_ASSERT(IsCanceled(), "Subclass Cancel() didn't set IsCanceled()!"); | |||
return NS_OK; | |||
} | |||
// Track down the appropriate global to use for the AutoJSAPI/AutoEntryScript. | |||
nsCOMPtr<nsIGlobalObject> globalObject; | |||
bool isMainThread = !targetIsWorkerThread && !mWorkerPrivate->GetParent(); | |||
MOZ_ASSERT(isMainThread == NS_IsMainThread()); | |||
nsRefPtr<WorkerPrivate> kungFuDeathGrip; | |||
if (targetIsWorkerThread) { | |||
globalObject = mWorkerPrivate->GlobalScope(); | |||
} | |||
else { | |||
kungFuDeathGrip = mWorkerPrivate; | |||
if (isMainThread) { | |||
globalObject = static_cast<nsGlobalWindow*>(mWorkerPrivate->GetWindow()); | |||
} else { | |||
globalObject = mWorkerPrivate->GetParent()->GlobalScope(); | |||
} | |||
} | |||
// We might run script as part of WorkerRun, so we need an AutoEntryScript. | |||
// This is part of the HTML spec for workers at: | |||
// http://www.whatwg.org/specs/web-apps/current-work/#run-a-worker | |||
// If we don't have a globalObject we have to use an AutoJSAPI instead, but | |||
// this is OK as we won't be running script in these circumstances. | |||
// It's important that aes is declared after jsapi, because if WorkerRun | |||
// creates a global then we construct aes before PostRun and we need them to | |||
// be destroyed in the correct order. | |||
mozilla::dom::AutoJSAPI jsapi; | |||
Maybe<mozilla::dom::AutoEntryScript> aes; | |||
JSContext* cx; | |||
if (globalObject) { | |||
aes.emplace(globalObject, isMainThread, isMainThread ? nullptr : | |||
GetCurrentThreadJSContext()); | |||
cx = aes->cx(); | |||
} else { | |||
jsapi.Init(); | |||
cx = jsapi.cx(); | |||
} | |||
// If we're not on the worker thread we'll either be in our parent's | |||
// compartment or the null compartment, so we need to enter our own. | |||
Maybe<JSAutoCompartment> ac; | |||
if (!targetIsWorkerThread && mWorkerPrivate->GetWrapper()) { | |||
ac.emplace(cx, mWorkerPrivate->GetWrapper()); | |||
} | |||
bool result = WorkerRun(cx, mWorkerPrivate); | |||
// In the case of CompileScriptRunnnable, WorkerRun above can cause us to | |||
// lazily create a global, so we construct aes here before calling PostRun. | |||
if (targetIsWorkerThread && !aes && mWorkerPrivate->GlobalScope()) { | |||
aes.emplace(mWorkerPrivate->GlobalScope(), false, GetCurrentThreadJSContext()); | |||
cx = aes->cx(); | |||
} | |||
PostRun(cx, mWorkerPrivate, result); | |||
return result ? NS_OK : NS_ERROR_FAILURE; | |||
} | |||
class CompileScriptRunnable MOZ_FINAL : public WorkerRunnable | |||
{ | |||
public: | |||
explicit CompileScriptRunnable(WorkerPrivate* aWorkerPrivate) | |||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) | |||
{ } | |||
private: | |||
virtual bool | |||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE | |||
{ | |||
JS::Rooted<JSObject*> global(aCx, | |||
aWorkerPrivate->CreateGlobalScope(aCx)); | |||
if (!global) { | |||
NS_WARNING("Failed to make global!"); | |||
return false; | |||
} | |||
JSAutoCompartment ac(aCx, global); | |||
bool result = scriptloader::LoadWorkerScript(aCx); | |||
if (result) { | |||
aWorkerPrivate->SetWorkerScriptExecutedSuccessfully(); | |||
} | |||
return result; | |||
} | |||
}; | |||
</source> | </source> | ||
=Shared Worker= | =Shared Worker= | ||