зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1072144
part 4. Add a WorkerRunnable::PreRun so that we can move worker global creation to it and always have an AutoEntryScript by the time we're evaluating the main worker script. r=khuey
This commit is contained in:
Родитель
dae479317b
Коммит
de208d989a
|
@ -306,6 +306,9 @@ private:
|
||||||
virtual bool
|
virtual bool
|
||||||
IsDebuggerRunnable() const override;
|
IsDebuggerRunnable() const override;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
PreRun(WorkerPrivate* aWorkerPrivate) override;
|
||||||
|
|
||||||
virtual bool
|
virtual bool
|
||||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
|
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override;
|
||||||
|
|
||||||
|
@ -1723,6 +1726,41 @@ ScriptExecutorRunnable::IsDebuggerRunnable() const
|
||||||
return mScriptLoader.mWorkerScriptType == DebuggerScript;
|
return mScriptLoader.mWorkerScriptType == DebuggerScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ScriptExecutorRunnable::PreRun(WorkerPrivate* aWorkerPrivate)
|
||||||
|
{
|
||||||
|
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
|
||||||
|
if (!mIsWorkerScript) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aWorkerPrivate->GetJSContext()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(mFirstIndex == 0);
|
||||||
|
MOZ_ASSERT(!mScriptLoader.mRv.Failed());
|
||||||
|
|
||||||
|
AutoJSAPI jsapi;
|
||||||
|
jsapi.Init();
|
||||||
|
jsapi.TakeOwnershipOfErrorReporting();
|
||||||
|
|
||||||
|
WorkerGlobalScope* globalScope =
|
||||||
|
aWorkerPrivate->GetOrCreateGlobalScope(jsapi.cx());
|
||||||
|
if (NS_WARN_IF(!globalScope)) {
|
||||||
|
NS_WARNING("Failed to make global!");
|
||||||
|
// There's no way to report the exception on jsapi right now, because there
|
||||||
|
// is no way to even enter a compartment on this thread anymore. Just clear
|
||||||
|
// the exception. We'll report some sort of error to our caller thread in
|
||||||
|
// ShutdownScriptLoader.
|
||||||
|
jsapi.ClearException();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||||
{
|
{
|
||||||
|
@ -1745,32 +1783,11 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||||
// If nothing else has failed, our ErrorResult better not be a failure either.
|
// If nothing else has failed, our ErrorResult better not be a failure either.
|
||||||
MOZ_ASSERT(!mScriptLoader.mRv.Failed(), "Who failed it and why?");
|
MOZ_ASSERT(!mScriptLoader.mRv.Failed(), "Who failed it and why?");
|
||||||
|
|
||||||
JS::Rooted<JSObject*> global(aCx);
|
// Slightly icky action at a distance, but there's no better place to stash
|
||||||
|
// this value, really.
|
||||||
if (mIsWorkerScript) {
|
JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx));
|
||||||
WorkerGlobalScope* globalScope =
|
|
||||||
aWorkerPrivate->GetOrCreateGlobalScope(aCx);
|
|
||||||
if (NS_WARN_IF(!globalScope)) {
|
|
||||||
NS_WARNING("Failed to make global!");
|
|
||||||
// There's no way to report the exception on aCx right now, because there
|
|
||||||
// is no way to even enter a compartment on this thread anymore. Just
|
|
||||||
// clear the exception. We'll report some sort of error to our caller
|
|
||||||
// thread in ShutdownScriptLoader.
|
|
||||||
JS_ClearPendingException(aCx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
global.set(globalScope->GetWrapper());
|
|
||||||
} else {
|
|
||||||
// XXXbz Icky action at a distance... Would be better to capture this state
|
|
||||||
// in mScriptLoader!
|
|
||||||
global.set(JS::CurrentGlobalOrNull(aCx));
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(global);
|
MOZ_ASSERT(global);
|
||||||
|
|
||||||
JSAutoCompartment ac(aCx, global);
|
|
||||||
|
|
||||||
for (uint32_t index = mFirstIndex; index <= mLastIndex; index++) {
|
for (uint32_t index = mFirstIndex; index <= mLastIndex; index++) {
|
||||||
ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
|
ScriptLoadInfo& loadInfo = loadInfos.ElementAt(index);
|
||||||
|
|
||||||
|
|
|
@ -498,6 +498,10 @@ public:
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// We can't implement PreRun effectively, because at the point when that would
|
||||||
|
// run we have not yet done our load so don't know things like our final
|
||||||
|
// principal and whatnot.
|
||||||
|
|
||||||
virtual bool
|
virtual bool
|
||||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||||
{
|
{
|
||||||
|
|
|
@ -155,6 +155,12 @@ WorkerRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
WorkerRunnable::PreRun(WorkerPrivate* aWorkerPrivate)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||||
bool aRunResult)
|
bool aRunResult)
|
||||||
|
@ -256,7 +262,20 @@ WorkerRunnable::Run()
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track down the appropriate global to use for the AutoJSAPI/AutoEntryScript.
|
bool result = PreRun(mWorkerPrivate);
|
||||||
|
if (!result) {
|
||||||
|
MOZ_ASSERT(targetIsWorkerThread,
|
||||||
|
"The only PreRun implementation that can fail is "
|
||||||
|
"ScriptExecutorRunnable");
|
||||||
|
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||||
|
MOZ_ASSERT(!JS_IsExceptionPending(mWorkerPrivate->GetJSContext()));
|
||||||
|
// We can't enter a useful compartment on the JSContext here; just pass it
|
||||||
|
// in as-is.
|
||||||
|
PostRun(mWorkerPrivate->GetJSContext(), mWorkerPrivate, false);
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track down the appropriate global, if any, to use for the AutoEntryScript.
|
||||||
nsCOMPtr<nsIGlobalObject> globalObject;
|
nsCOMPtr<nsIGlobalObject> globalObject;
|
||||||
bool isMainThread = !targetIsWorkerThread && !mWorkerPrivate->GetParent();
|
bool isMainThread = !targetIsWorkerThread && !mWorkerPrivate->GetParent();
|
||||||
MOZ_ASSERT(isMainThread == NS_IsMainThread());
|
MOZ_ASSERT(isMainThread == NS_IsMainThread());
|
||||||
|
@ -273,6 +292,12 @@ WorkerRunnable::Run()
|
||||||
} else {
|
} else {
|
||||||
globalObject = DefaultGlobalObject();
|
globalObject = DefaultGlobalObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We may still not have a globalObject here: in the case of
|
||||||
|
// CompileScriptRunnable, we don't actually create the global object until
|
||||||
|
// we have the script data, which happens in a syncloop under
|
||||||
|
// CompileScriptRunnable::WorkerRun, so we can't assert that it got created
|
||||||
|
// in the PreRun call above.
|
||||||
} else {
|
} else {
|
||||||
kungFuDeathGrip = mWorkerPrivate;
|
kungFuDeathGrip = mWorkerPrivate;
|
||||||
if (isMainThread) {
|
if (isMainThread) {
|
||||||
|
@ -290,7 +315,7 @@ WorkerRunnable::Run()
|
||||||
// It's important that aes is declared after jsapi, because if WorkerRun
|
// 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
|
// creates a global then we construct aes before PostRun and we need them to
|
||||||
// be destroyed in the correct order.
|
// be destroyed in the correct order.
|
||||||
mozilla::dom::AutoJSAPI jsapi;
|
Maybe<mozilla::dom::AutoJSAPI> jsapi;
|
||||||
Maybe<mozilla::dom::AutoEntryScript> aes;
|
Maybe<mozilla::dom::AutoEntryScript> aes;
|
||||||
JSContext* cx;
|
JSContext* cx;
|
||||||
if (globalObject) {
|
if (globalObject) {
|
||||||
|
@ -299,8 +324,9 @@ WorkerRunnable::Run()
|
||||||
isMainThread ? nullptr : GetCurrentThreadJSContext());
|
isMainThread ? nullptr : GetCurrentThreadJSContext());
|
||||||
cx = aes->cx();
|
cx = aes->cx();
|
||||||
} else {
|
} else {
|
||||||
jsapi.Init();
|
jsapi.emplace();
|
||||||
cx = jsapi.cx();
|
jsapi->Init();
|
||||||
|
cx = jsapi->cx();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that we can't assert anything about mWorkerPrivate->GetWrapper()
|
// Note that we can't assert anything about mWorkerPrivate->GetWrapper()
|
||||||
|
@ -344,10 +370,13 @@ WorkerRunnable::Run()
|
||||||
ac.emplace(cx, mWorkerPrivate->GetWrapper());
|
ac.emplace(cx, mWorkerPrivate->GetWrapper());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool result = WorkerRun(cx, mWorkerPrivate);
|
result = WorkerRun(cx, mWorkerPrivate);
|
||||||
MOZ_ASSERT_IF(result, !JS_IsExceptionPending(cx));
|
MOZ_ASSERT_IF(result, !JS_IsExceptionPending(cx));
|
||||||
JS_ReportPendingException(cx);
|
JS_ReportPendingException(cx);
|
||||||
|
|
||||||
|
// We can't even assert that this didn't create our global, since in the case
|
||||||
|
// of CompileScriptRunnable it _does_.
|
||||||
|
|
||||||
// In the case of CompileScriptRunnnable, WorkerRun above can cause us to
|
// In the case of CompileScriptRunnnable, WorkerRun above can cause us to
|
||||||
// lazily create a global, so we construct aes here before calling PostRun.
|
// lazily create a global, so we construct aes here before calling PostRun.
|
||||||
if (targetIsWorkerThread && !aes && DefaultGlobalObject()) {
|
if (targetIsWorkerThread && !aes && DefaultGlobalObject()) {
|
||||||
|
|
|
@ -122,6 +122,16 @@ protected:
|
||||||
virtual void
|
virtual void
|
||||||
PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult);
|
PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult);
|
||||||
|
|
||||||
|
// May be implemented by subclasses if desired if they need to do some sort of
|
||||||
|
// setup before we try to set up our JSContext and compartment for real.
|
||||||
|
// Typically the only thing that should go in here is creation of the worker's
|
||||||
|
// global.
|
||||||
|
//
|
||||||
|
// If false is returned, WorkerRun will not be called at all. PostRun will
|
||||||
|
// still be called, with false passed for aRunResult.
|
||||||
|
virtual bool
|
||||||
|
PreRun(WorkerPrivate* aWorkerPrivate);
|
||||||
|
|
||||||
// Must be implemented by subclasses. Called on the target thread. The return
|
// Must be implemented by subclasses. Called on the target thread. The return
|
||||||
// value will be passed to PostRun(). The JSContext passed in here comes from
|
// value will be passed to PostRun(). The JSContext passed in here comes from
|
||||||
// an AutoJSAPI (or AutoEntryScript) that we set up on the stack. If
|
// an AutoJSAPI (or AutoEntryScript) that we set up on the stack. If
|
||||||
|
|
Загрузка…
Ссылка в новой задаче