mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 931864 - remove the activeGCInAtomsZone limitation in JS::CanCompileOffThread (r=billm)
--HG-- extra : rebase_source : d0652c47ca940810ad32e4f34aa23a032f585479
This commit is contained in:
parent
1fad0c2df0
commit
ea95f526af
@ -35,6 +35,8 @@ support-files =
|
||||
[browser_styleeditor_new.js]
|
||||
[browser_styleeditor_nostyle.js]
|
||||
[browser_styleeditor_pretty.js]
|
||||
# Disabled because of intermittent failures - See Bug 942473
|
||||
skip-if = true
|
||||
[browser_styleeditor_private_perwindowpb.js]
|
||||
[browser_styleeditor_reload.js]
|
||||
[browser_styleeditor_sv_keynav.js]
|
||||
|
@ -4501,17 +4501,7 @@ JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optio
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options)
|
||||
{
|
||||
if (!cx->runtime()->canUseParallelParsing())
|
||||
return false;
|
||||
|
||||
// Off thread compilation can't occur during incremental collections on the
|
||||
// atoms compartment, to avoid triggering barriers. Outside the atoms
|
||||
// compartment, the compilation will use a new zone which doesn't require
|
||||
// barriers itself.
|
||||
if (cx->runtime()->activeGCInAtomsZone())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return cx->runtime()->canUseParallelParsing();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
|
@ -4946,6 +4946,12 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget,
|
||||
*/
|
||||
repeat = (rt->gcPoke && rt->gcShouldCleanUpEverything) || wasReset;
|
||||
} while (repeat);
|
||||
|
||||
if (rt->gcIncrementalState == NO_INCREMENTAL) {
|
||||
#ifdef JS_WORKER_THREADS
|
||||
EnqueuePendingParseTasksAfterGC(rt);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -5406,6 +5412,23 @@ js::PurgeJITCaches(Zone *zone)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ArenaLists::normalizeBackgroundFinalizeState(AllocKind thingKind)
|
||||
{
|
||||
volatile uintptr_t *bfs = &backgroundFinalizeState[thingKind];
|
||||
switch (*bfs) {
|
||||
case BFS_DONE:
|
||||
break;
|
||||
case BFS_JUST_FINISHED:
|
||||
// No allocations between end of last sweep and now.
|
||||
// Transfering over arenas is a kind of allocation.
|
||||
*bfs = BFS_DONE;
|
||||
break;
|
||||
default:
|
||||
JS_ASSERT(!"Background finalization in progress, but it should not be.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ArenaLists::adoptArenas(JSRuntime *rt, ArenaLists *fromArenaLists)
|
||||
@ -5422,21 +5445,9 @@ ArenaLists::adoptArenas(JSRuntime *rt, ArenaLists *fromArenaLists)
|
||||
// When we enter a parallel section, we join the background
|
||||
// thread, and we do not run GC while in the parallel section,
|
||||
// so no finalizer should be active!
|
||||
volatile uintptr_t *bfs = &backgroundFinalizeState[thingKind];
|
||||
switch (*bfs) {
|
||||
case BFS_DONE:
|
||||
break;
|
||||
case BFS_JUST_FINISHED:
|
||||
// No allocations between end of last sweep and now.
|
||||
// Transfering over arenas is a kind of allocation.
|
||||
*bfs = BFS_DONE;
|
||||
break;
|
||||
default:
|
||||
JS_ASSERT(!"Background finalization in progress, but it should not be.");
|
||||
break;
|
||||
}
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
normalizeBackgroundFinalizeState(AllocKind(thingKind));
|
||||
fromArenaLists->normalizeBackgroundFinalizeState(AllocKind(thingKind));
|
||||
#endif
|
||||
ArenaList *fromList = &fromArenaLists->arenaLists[thingKind];
|
||||
ArenaList *toList = &arenaLists[thingKind];
|
||||
while (fromList->head != nullptr) {
|
||||
|
@ -616,6 +616,8 @@ class ArenaLists
|
||||
void *allocateFromArena(JS::Zone *zone, AllocKind thingKind);
|
||||
inline void *allocateFromArenaInline(JS::Zone *zone, AllocKind thingKind);
|
||||
|
||||
inline void normalizeBackgroundFinalizeState(AllocKind thingKind);
|
||||
|
||||
friend class js::Nursery;
|
||||
};
|
||||
|
||||
|
@ -176,18 +176,20 @@ static const JSClass workerGlobalClass = {
|
||||
JS_ConvertStub, nullptr
|
||||
};
|
||||
|
||||
ParseTask::ParseTask(ExclusiveContext *cx, JSContext *initCx,
|
||||
ParseTask::ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal, JSContext *initCx,
|
||||
const jschar *chars, size_t length, JSObject *scopeChain,
|
||||
JS::OffThreadCompileCallback callback, void *callbackData)
|
||||
: cx(cx), options(initCx), chars(chars), length(length),
|
||||
alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), scopeChain(scopeChain),
|
||||
callback(callback), callbackData(callbackData), script(nullptr),
|
||||
errors(cx), overRecursed(false)
|
||||
exclusiveContextGlobal(exclusiveContextGlobal), callback(callback),
|
||||
callbackData(callbackData), script(nullptr), errors(cx), overRecursed(false)
|
||||
{
|
||||
JSRuntime *rt = scopeChain->runtimeFromMainThread();
|
||||
|
||||
if (!AddObjectRoot(rt, &this->scopeChain, "ParseTask::scopeChain"))
|
||||
MOZ_CRASH();
|
||||
if (!AddObjectRoot(rt, &this->exclusiveContextGlobal, "ParseTask::exclusiveContextGlobal"))
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -196,11 +198,19 @@ ParseTask::init(JSContext *cx, const ReadOnlyCompileOptions &options)
|
||||
return this->options.copy(cx, options);
|
||||
}
|
||||
|
||||
void
|
||||
ParseTask::activate(JSRuntime *rt)
|
||||
{
|
||||
rt->setUsedByExclusiveThread(exclusiveContextGlobal->zone());
|
||||
cx->enterCompartment(exclusiveContextGlobal->compartment());
|
||||
}
|
||||
|
||||
ParseTask::~ParseTask()
|
||||
{
|
||||
JSRuntime *rt = scopeChain->runtimeFromMainThread();
|
||||
|
||||
JS_RemoveObjectRootRT(rt, &scopeChain);
|
||||
JS_RemoveObjectRootRT(rt, &exclusiveContextGlobal);
|
||||
|
||||
// ParseTask takes over ownership of its input exclusive context.
|
||||
js_delete(cx);
|
||||
@ -257,38 +267,75 @@ js::StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &optio
|
||||
}
|
||||
}
|
||||
|
||||
cx->runtime()->setUsedByExclusiveThread(global->zone());
|
||||
|
||||
ScopedJSDeletePtr<ExclusiveContext> workercx(
|
||||
cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData *) nullptr,
|
||||
ThreadSafeContext::Context_Exclusive));
|
||||
if (!workercx)
|
||||
return false;
|
||||
|
||||
workercx->enterCompartment(global->compartment());
|
||||
|
||||
ScopedJSDeletePtr<ParseTask> task(
|
||||
cx->new_<ParseTask>(workercx.get(), cx, chars, length,
|
||||
cx->new_<ParseTask>(workercx.get(), global, cx, chars, length,
|
||||
scopeChain, callback, callbackData));
|
||||
if (!task || !task->init(cx, options))
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
workercx.forget();
|
||||
|
||||
if (!task->init(cx, options))
|
||||
return false;
|
||||
|
||||
WorkerThreadState &state = *cx->runtime()->workerThreadState;
|
||||
JS_ASSERT(state.numThreads);
|
||||
|
||||
AutoLockWorkerThreadState lock(state);
|
||||
// Off thread parsing can't occur during incremental collections on the
|
||||
// atoms compartment, to avoid triggering barriers. (Outside the atoms
|
||||
// compartment, the compilation will use a new zone which doesn't require
|
||||
// barriers itself.) If an atoms-zone GC is in progress, hold off on
|
||||
// executing the parse task until the atoms-zone GC completes (see
|
||||
// EnqueuePendingParseTasksAfterGC).
|
||||
if (cx->runtime()->activeGCInAtomsZone()) {
|
||||
if (!state.parseWaitingOnGC.append(task.get()))
|
||||
return false;
|
||||
} else {
|
||||
task->activate(cx->runtime());
|
||||
|
||||
if (!state.parseWorklist.append(task.get()))
|
||||
return false;
|
||||
AutoLockWorkerThreadState lock(state);
|
||||
|
||||
if (!state.parseWorklist.append(task.get()))
|
||||
return false;
|
||||
|
||||
state.notifyAll(WorkerThreadState::PRODUCER);
|
||||
}
|
||||
|
||||
task.forget();
|
||||
|
||||
state.notifyAll(WorkerThreadState::PRODUCER);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
js::EnqueuePendingParseTasksAfterGC(JSRuntime *rt)
|
||||
{
|
||||
JS_ASSERT(!rt->activeGCInAtomsZone());
|
||||
|
||||
if (!rt->workerThreadState || rt->workerThreadState->parseWaitingOnGC.empty())
|
||||
return;
|
||||
|
||||
// This logic should mirror the contents of the !activeGCInAtomsZone()
|
||||
// branch in StartOffThreadParseScript:
|
||||
|
||||
WorkerThreadState &state = *rt->workerThreadState;
|
||||
|
||||
for (size_t i = 0; i < state.parseWaitingOnGC.length(); i++)
|
||||
state.parseWaitingOnGC[i]->activate(rt);
|
||||
|
||||
AutoLockWorkerThreadState lock(state);
|
||||
|
||||
JS_ASSERT(state.parseWorklist.empty());
|
||||
state.parseWorklist.swap(state.parseWaitingOnGC);
|
||||
|
||||
state.notifyAll(WorkerThreadState::PRODUCER);
|
||||
}
|
||||
|
||||
void
|
||||
js::WaitForOffThreadParsingToFinish(JSRuntime *rt)
|
||||
{
|
||||
|
@ -71,6 +71,9 @@ class WorkerThreadState
|
||||
/* Shared worklist for parsing/emitting scripts on worker threads. */
|
||||
Vector<ParseTask*, 0, SystemAllocPolicy> parseWorklist, parseFinishedList;
|
||||
|
||||
/* Main-thread-only list of parse tasks waiting for an atoms-zone GC to complete. */
|
||||
Vector<ParseTask*, 0, SystemAllocPolicy> parseWaitingOnGC;
|
||||
|
||||
/* Worklist for source compression worker threads. */
|
||||
Vector<SourceCompressionTask *, 0, SystemAllocPolicy> compressionWorklist;
|
||||
|
||||
@ -230,6 +233,13 @@ StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &options,
|
||||
const jschar *chars, size_t length, HandleObject scopeChain,
|
||||
JS::OffThreadCompileCallback callback, void *callbackData);
|
||||
|
||||
/*
|
||||
* Called at the end of GC to enqueue any Parse tasks that were waiting on an
|
||||
* atoms-zone GC to finish.
|
||||
*/
|
||||
void
|
||||
EnqueuePendingParseTasksAfterGC(JSRuntime *rt);
|
||||
|
||||
/* Block until in progress and pending off thread parse jobs have finished. */
|
||||
void
|
||||
WaitForOffThreadParsingToFinish(JSRuntime *rt);
|
||||
@ -329,6 +339,9 @@ struct ParseTask
|
||||
// main thread.
|
||||
JSObject *scopeChain;
|
||||
|
||||
// Rooted pointer to the global object used by 'cx'.
|
||||
JSObject *exclusiveContextGlobal;
|
||||
|
||||
// Callback invoked off the main thread when the parse finishes.
|
||||
JS::OffThreadCompileCallback callback;
|
||||
void *callbackData;
|
||||
@ -343,11 +356,13 @@ struct ParseTask
|
||||
Vector<frontend::CompileError *> errors;
|
||||
bool overRecursed;
|
||||
|
||||
ParseTask(ExclusiveContext *cx, JSContext *initCx,
|
||||
ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal, JSContext *initCx,
|
||||
const jschar *chars, size_t length, JSObject *scopeChain,
|
||||
JS::OffThreadCompileCallback callback, void *callbackData);
|
||||
bool init(JSContext *cx, const ReadOnlyCompileOptions &options);
|
||||
|
||||
void activate(JSRuntime *rt);
|
||||
|
||||
~ParseTask();
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user