Bug 922096 - OdinMonkey: prevent multiple concurrent parallel asm.js compilations (r=sstangl)

This commit is contained in:
Luke Wagner 2013-10-01 17:23:55 -05:00
parent 548b3fc608
commit 5530c7cf8e
3 changed files with 66 additions and 7 deletions

View File

@ -0,0 +1,26 @@
load(libdir + "asm.js");
if (!isAsmJSCompilationAvailable())
quit();
var module = "'use asm';\n";
for (var i = 0; i < 100; i++) {
module += "function f" + i + "(i) {\n";
module += " i=i|0; var j=0; j=(i+1)|0; i=(j-4)|0; i=(i+j)|0; return i|0\n";
module += "}\n";
}
module += "return f0";
var script = "(function() {\n" + module + "})";
for (var i = 0; i < 10; i++) {
try {
offThreadCompileScript(script);
var f = new Function(module);
var g = runOffThreadScript();
assertEq(isAsmJSModule(f), true);
assertEq(isAsmJSModule(g), true);
} catch (e) {
// ignore spurious error when offThreadCompileScript can't run in
// parallel
}
}

View File

@ -5074,6 +5074,29 @@ CheckFunctionsSequential(ModuleCompiler &m)
#ifdef JS_WORKER_THREADS
// Currently, only one asm.js parallel compilation is allowed at a time.
// This RAII class attempts to claim this parallel compilation using atomic ops
// on rt->workerThreadState->asmJSCompilationInProgress.
class ParallelCompilationGuard
{
WorkerThreadState *parallelState_;
public:
ParallelCompilationGuard() : parallelState_(NULL) {}
~ParallelCompilationGuard() {
if (parallelState_) {
JS_ASSERT(parallelState_->asmJSCompilationInProgress == true);
parallelState_->asmJSCompilationInProgress = false;
}
}
bool claim(WorkerThreadState *state) {
JS_ASSERT(!parallelState_);
if (!state->asmJSCompilationInProgress.compareExchange(false, true))
return false;
parallelState_ = state;
return true;
}
};
static bool
ParallelCompilationEnabled(ExclusiveContext *cx)
{
@ -5254,6 +5277,15 @@ static const size_t LIFO_ALLOC_PARALLEL_CHUNK_SIZE = 1 << 12;
static bool
CheckFunctionsParallel(ModuleCompiler &m)
{
// If parallel compilation isn't enabled (not enough cores, disabled by
// pref, etc) or another thread is currently compiling asm.js in parallel,
// fall back to sequential compilation. (We could lift the latter
// constraint by hoisting asmJS* state out of WorkerThreadState so multiple
// concurrent asm.js parallel compilations don't race.)
ParallelCompilationGuard g;
if (!ParallelCompilationEnabled(m.cx()) || !g.claim(m.cx()->workerThreadState()))
return CheckFunctionsSequential(m);
// Saturate all worker threads plus the main thread.
WorkerThreadState &state = *m.cx()->workerThreadState();
size_t numParallelJobs = state.numThreads + 1;
@ -6393,13 +6425,8 @@ CheckModule(ExclusiveContext *cx, AsmJSParser &parser, ParseNode *stmtList,
return false;
#ifdef JS_WORKER_THREADS
if (ParallelCompilationEnabled(cx)) {
if (!CheckFunctionsParallel(m))
return false;
} else {
if (!CheckFunctionsSequential(m))
return false;
}
if (!CheckFunctionsParallel(m))
return false;
#else
if (!CheckFunctionsSequential(m))
return false;

View File

@ -71,6 +71,12 @@ class WorkerThreadState
*/
Vector<AsmJSParallelTask*, 0, SystemAllocPolicy> asmJSFinishedList;
/*
* For now, only allow a single parallel asm.js compilation to happen at a
* time. This avoids race conditions on asmJSWorklist/asmJSFinishedList/etc.
*/
mozilla::Atomic<uint32_t> asmJSCompilationInProgress;
/* Shared worklist for parsing/emitting scripts on worker threads. */
Vector<ParseTask*, 0, SystemAllocPolicy> parseWorklist, parseFinishedList;