Bug 1286159 - Clean up FinishOffThread* APIs for off-thread parsing. r=jonco

This commit is contained in:
Jan de Mooij 2016-07-19 09:19:54 +02:00
parent d8b9227dbe
commit 0f65c9be84
9 changed files with 90 additions and 61 deletions

View File

@ -195,7 +195,7 @@ nsJSUtils::EvaluateString(JSContext* aCx,
if (ok && aOffThreadToken) {
JS::Rooted<JSScript*>
script(aCx, JS::FinishOffThreadScript(aCx, JS_GetRuntime(aCx), *aOffThreadToken));
script(aCx, JS::FinishOffThreadScript(aCx, *aOffThreadToken));
*aOffThreadToken = nullptr; // Mark the token as having been finished.
if (script) {
ok = JS_ExecuteScript(aCx, scopeChain, script);

View File

@ -708,8 +708,7 @@ nsScriptLoader::CreateModuleScript(nsModuleLoadRequest* aRequest)
JS::Rooted<JSObject*> module(cx);
if (aRequest->mWasCompiledOMT) {
module = JS::FinishOffThreadModule(cx, xpc::GetJSRuntime(),
aRequest->mOffThreadToken);
module = JS::FinishOffThreadModule(cx, aRequest->mOffThreadToken);
aRequest->mOffThreadToken = nullptr;
rv = module ? NS_OK : NS_ERROR_FAILURE;
} else {
@ -1829,7 +1828,8 @@ nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest)
// (disappearing window, some other error, ...). Finish the
// request to avoid leaks in the JS engine.
MOZ_ASSERT(!aRequest->IsModuleRequest());
JS::FinishOffThreadScript(nullptr, xpc::GetJSRuntime(), aRequest->mOffThreadToken);
JSContext* cx = JS_GetContext(xpc::GetJSRuntime());
JS::CancelOffThreadScript(cx, aRequest->mOffThreadToken);
aRequest->mOffThreadToken = nullptr;
}

View File

@ -2768,7 +2768,7 @@ NotifyOffThreadScriptCompletedRunnable::Run()
return NS_ERROR_UNEXPECTED;
}
JSContext* cx = jsapi.cx();
script = JS::FinishOffThreadScript(cx, JS_GetRuntime(cx), mToken);
script = JS::FinishOffThreadScript(cx, mToken);
}
if (!sReceivers) {

View File

@ -4081,10 +4081,19 @@ JS::CompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options,
}
JS_PUBLIC_API(JSScript*)
JS::FinishOffThreadScript(JSContext* maybecx, JSRuntime* rt, void* token)
JS::FinishOffThreadScript(JSContext* cx, void* token)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
return HelperThreadState().finishScriptParseTask(maybecx, rt, token);
MOZ_ASSERT(cx);
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx));
return HelperThreadState().finishScriptParseTask(cx, token);
}
JS_PUBLIC_API(void)
JS::CancelOffThreadScript(JSContext* cx, void* token)
{
MOZ_ASSERT(cx);
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx));
HelperThreadState().cancelParseTask(cx, ParseTaskKind::Script, token);
}
JS_PUBLIC_API(bool)
@ -4097,10 +4106,19 @@ JS::CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options,
}
JS_PUBLIC_API(JSObject*)
JS::FinishOffThreadModule(JSContext* maybecx, JSRuntime* rt, void* token)
JS::FinishOffThreadModule(JSContext* cx, void* token)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
return HelperThreadState().finishModuleParseTask(maybecx, rt, token);
MOZ_ASSERT(cx);
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx));
return HelperThreadState().finishModuleParseTask(cx, token);
}
JS_PUBLIC_API(void)
JS::CancelOffThreadModule(JSContext* cx, void* token)
{
MOZ_ASSERT(cx);
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx));
HelperThreadState().cancelParseTask(cx, ParseTaskKind::Module, token);
}
JS_PUBLIC_API(bool)

View File

@ -4050,10 +4050,11 @@ CanCompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options, size_t
* After successfully triggering an off thread compile of a script, the
* callback will eventually be invoked with the specified data and a token
* for the compilation. The callback will be invoked while off the main thread,
* so must ensure that its operations are thread safe. Afterwards,
* FinishOffThreadScript must be invoked on the main thread to get the result
* script or nullptr. If maybecx is not specified, the resources will be freed,
* but no script will be returned.
* so must ensure that its operations are thread safe. Afterwards, one of the
* following functions must be invoked on the main thread:
*
* - FinishOffThreadScript, to get the result script (or nullptr on failure).
* - CancelOffThreadScript, to free the resources without creating a script.
*
* The characters passed in to CompileOffThread must remain live until the
* callback is invoked, and the resulting script will be rooted until the call
@ -4066,7 +4067,10 @@ CompileOffThread(JSContext* cx, const ReadOnlyCompileOptions& options,
OffThreadCompileCallback callback, void* callbackData);
extern JS_PUBLIC_API(JSScript*)
FinishOffThreadScript(JSContext* maybecx, JSRuntime* rt, void* token);
FinishOffThreadScript(JSContext* cx, void* token);
extern JS_PUBLIC_API(void)
CancelOffThreadScript(JSContext* cx, void* token);
extern JS_PUBLIC_API(bool)
CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options,
@ -4074,7 +4078,10 @@ CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options,
OffThreadCompileCallback callback, void* callbackData);
extern JS_PUBLIC_API(JSObject*)
FinishOffThreadModule(JSContext* maybecx, JSRuntime* rt, void* token);
FinishOffThreadModule(JSContext* cx, void* token);
extern JS_PUBLIC_API(void)
CancelOffThreadModule(JSContext* cx, void* token);
/**
* Compile a function with scopeChain plus the global as its scope chain.

View File

@ -3928,8 +3928,7 @@ runOffThreadScript(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSRuntime* rt = cx->runtime();
if (OffThreadParsingMustWaitForGC(rt))
if (OffThreadParsingMustWaitForGC(cx))
gc::FinishGC(cx);
void* token = offThreadState.waitUntilDone(cx, ScriptKind::Script);
@ -3938,7 +3937,7 @@ runOffThreadScript(JSContext* cx, unsigned argc, Value* vp)
return false;
}
RootedScript script(cx, JS::FinishOffThreadScript(cx, rt, token));
RootedScript script(cx, JS::FinishOffThreadScript(cx, token));
if (!script)
return false;
@ -4014,8 +4013,7 @@ FinishOffThreadModule(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSRuntime* rt = cx->runtime();
if (OffThreadParsingMustWaitForGC(rt))
if (OffThreadParsingMustWaitForGC(cx))
gc::FinishGC(cx);
void* token = offThreadState.waitUntilDone(cx, ScriptKind::Module);
@ -4024,7 +4022,7 @@ FinishOffThreadModule(JSContext* cx, unsigned argc, Value* vp)
return false;
}
RootedObject module(cx, JS::FinishOffThreadModule(cx, rt, token));
RootedObject module(cx, JS::FinishOffThreadModule(cx, token));
if (!module)
return false;

View File

@ -346,8 +346,7 @@ js::CancelOffThreadParses(JSRuntime* rt)
if (task->runtimeMatches(rt)) {
found = true;
AutoUnlockHelperThreadState unlock(lock);
HelperThreadState().finishParseTask(/* maybecx = */ nullptr, rt, task->kind,
task);
HelperThreadState().cancelParseTask(rt->contextFromMainThread(), task->kind, task);
}
}
if (!found)
@ -1119,41 +1118,40 @@ LeaveParseTaskZone(JSRuntime* rt, ParseTask* task)
rt->clearUsedByExclusiveThread(task->cx->zone());
}
JSScript*
GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, ParseTaskKind kind,
void* token)
ParseTask*
GlobalHelperThreadState::removeFinishedParseTask(ParseTaskKind kind, void* token)
{
ScopedJSDeletePtr<ParseTask> parseTask;
// The token is a ParseTask* which should be in the finished list.
// Find and remove its entry.
{
AutoLockHelperThreadState lock;
ParseTaskVector& finished = parseFinishedList();
for (size_t i = 0; i < finished.length(); i++) {
if (finished[i] == token) {
parseTask = finished[i];
remove(finished, &i);
break;
}
AutoLockHelperThreadState lock;
ParseTaskVector& finished = parseFinishedList();
for (size_t i = 0; i < finished.length(); i++) {
if (finished[i] == token) {
ParseTask* parseTask = finished[i];
remove(finished, &i);
MOZ_ASSERT(parseTask);
MOZ_ASSERT(parseTask->kind == kind);
return parseTask;
}
}
MOZ_ASSERT(parseTask);
MOZ_ASSERT(parseTask->kind == kind);
if (!maybecx) {
LeaveParseTaskZone(rt, parseTask);
return nullptr;
}
MOZ_CRASH("Invalid ParseTask token");
}
JSContext* cx = maybecx;
JSScript*
GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind, void* token)
{
MOZ_ASSERT(cx->compartment());
ScopedJSDeletePtr<ParseTask> parseTask(removeFinishedParseTask(kind, token));
// Make sure we have all the constructors we need for the prototype
// remapping below, since we can't GC while that's happening.
Rooted<GlobalObject*> global(cx, &cx->global()->as<GlobalObject>());
if (!EnsureParserCreatedClasses(cx, kind)) {
LeaveParseTaskZone(rt, parseTask);
LeaveParseTaskZone(cx, parseTask);
return nullptr;
}
@ -1162,7 +1160,7 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, Pars
if (!parseTask->finish(cx))
return nullptr;
RootedScript script(rt, parseTask->script);
RootedScript script(cx, parseTask->script);
releaseAssertSameCompartment(cx, script);
// Report out of memory errors eagerly, or errors could be malformed.
@ -1194,25 +1192,22 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, Pars
}
JSScript*
GlobalHelperThreadState::finishScriptParseTask(JSContext* maybecx, JSRuntime* rt, void* token)
GlobalHelperThreadState::finishScriptParseTask(JSContext* cx, void* token)
{
JSScript* script = finishParseTask(maybecx, rt, ParseTaskKind::Script, token);
JSScript* script = finishParseTask(cx, ParseTaskKind::Script, token);
MOZ_ASSERT_IF(script, script->isGlobalCode());
return script;
}
JSObject*
GlobalHelperThreadState::finishModuleParseTask(JSContext* maybecx, JSRuntime* rt, void* token)
GlobalHelperThreadState::finishModuleParseTask(JSContext* cx, void* token)
{
JSScript* script = finishParseTask(maybecx, rt, ParseTaskKind::Module, token);
JSScript* script = finishParseTask(cx, ParseTaskKind::Module, token);
if (!script)
return nullptr;
MOZ_ASSERT(script->module());
if (!maybecx)
return nullptr;
JSContext* cx = maybecx;
RootedModuleObject module(cx, script->module());
module->fixScopesAfterCompartmentMerge(cx);
if (!ModuleObject::Freeze(cx, module))
@ -1221,6 +1216,13 @@ GlobalHelperThreadState::finishModuleParseTask(JSContext* maybecx, JSRuntime* rt
return module;
}
void
GlobalHelperThreadState::cancelParseTask(JSContext* cx, ParseTaskKind kind, void* token)
{
ScopedJSDeletePtr<ParseTask> parseTask(removeFinishedParseTask(kind, token));
LeaveParseTaskZone(cx, parseTask);
}
JSObject*
GlobalObject::getStarGeneratorFunctionPrototype()
{

View File

@ -101,6 +101,8 @@ class GlobalHelperThreadState
// GC tasks needing to be done in parallel.
GCParallelTaskVector gcParallelWorklist_;
ParseTask* removeFinishedParseTask(ParseTaskKind kind, void* token);
public:
size_t maxIonCompilationThreads() const;
size_t maxUnpausedIonCompilationThreads() const;
@ -225,7 +227,9 @@ class GlobalHelperThreadState
return bool(numWasmFailedJobs);
}
JSScript* finishParseTask(JSContext* maybecx, JSRuntime* rt, ParseTaskKind kind, void* token);
JSScript* finishParseTask(JSContext* cx, ParseTaskKind kind, void* token);
void cancelParseTask(JSContext* cx, ParseTaskKind kind, void* token);
void mergeParseTaskCompartment(JSContext* cx, ParseTask* parseTask,
Handle<GlobalObject*> global,
JSCompartment* dest);
@ -238,8 +242,8 @@ class GlobalHelperThreadState
uint32_t numWasmFailedJobs;
public:
JSScript* finishScriptParseTask(JSContext* maybecx, JSRuntime* rt, void* token);
JSObject* finishModuleParseTask(JSContext* maybecx, JSRuntime* rt, void* token);
JSScript* finishScriptParseTask(JSContext* cx, void* token);
JSObject* finishModuleParseTask(JSContext* cx, void* token);
bool compressionInProgress(SourceCompressionTask* task);
SourceCompressionTask* compressionTaskForSource(ScriptSource* ss);

View File

@ -776,9 +776,9 @@ NotifyPrecompilationCompleteRunnable::Run(void)
AutoSendObserverNotification notifier(mPrecompiler);
if (mToken) {
JSRuntime* rt = XPCJSRuntime::Get()->Runtime();
NS_ENSURE_TRUE(rt, NS_ERROR_FAILURE);
JS::FinishOffThreadScript(nullptr, rt, mToken);
JSContext* cx = XPCJSRuntime::Get()->Context();
NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
JS::CancelOffThreadScript(cx, mToken);
}
return NS_OK;