Bug 1031529 part 1 - Add a --no-threads shell flag. r=bhackett

This commit is contained in:
Jan de Mooij 2014-07-24 11:56:41 +02:00
parent 70420ca7e7
commit 6e5c3a5c11
16 changed files with 86 additions and 13 deletions

View File

@ -1606,7 +1606,10 @@ HelperThreadCount(JSContext *cx, unsigned argc, jsval *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
#ifdef JS_THREADSAFE
args.rval().setInt32(HelperThreadState().threadCount);
if (CanUseExtraThreads())
args.rval().setInt32(HelperThreadState().threadCount);
else
args.rval().setInt32(0);
#else
args.rval().setInt32(0);
#endif

View File

@ -1,5 +1,8 @@
// Test offThreadCompileScript option handling.
if (helperThreadCount() === 0)
quit(0);
offThreadCompileScript('Error()');
assertEq(!!runOffThreadScript().stack.match(/^@<string>:1:1\n/), true);

View File

@ -1,6 +1,9 @@
// Owning elements and attribute names are attached to scripts compiled
// off-thread.
if (helperThreadCount() === 0)
quit(0);
var g = newGlobal();
var dbg = new Debugger;
var gDO = dbg.addDebuggee(g);

View File

@ -1,5 +1,8 @@
// Check that scripts' introduction types are properly marked.
if (helperThreadCount() === 0)
quit(0);
var g = newGlobal();
var dbg = new Debugger();
var gDO = dbg.addDebuggee(g);

View File

@ -5521,7 +5521,7 @@ ParallelCompilationEnabled(ExclusiveContext *cx)
// parsing task, ensure that there another free thread to avoid deadlock.
// (Note: there is at most one thread used for parsing so we don't have to
// worry about general dining philosophers.)
if (HelperThreadState().threadCount <= 1)
if (HelperThreadState().threadCount <= 1 || !CanUseExtraThreads())
return false;
if (!cx->isJSContext())

View File

@ -1803,7 +1803,8 @@ OffThreadCompilationAvailable(JSContext *cx)
// Require cpuCount > 1 so that Ion compilation jobs and main-thread
// execution are not competing for the same resources.
return cx->runtime()->canUseOffthreadIonCompilation()
&& HelperThreadState().cpuCount > 1;
&& HelperThreadState().cpuCount > 1
&& CanUseExtraThreads();
#else
return false;
#endif

View File

@ -4575,7 +4575,7 @@ JS::CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, si
#endif // JS_THREADSAFE
}
return cx->runtime()->canUseParallelParsing();
return cx->runtime()->canUseParallelParsing() && CanUseExtraThreads();
}
JS_PUBLIC_API(bool)

View File

@ -2677,9 +2677,12 @@ GCHelperState::init()
if (!(done = PR_NewCondVar(rt->gc.lock)))
return false;
backgroundAllocation = (GetCPUCount() >= 2);
HelperThreadState().ensureInitialized();
if (CanUseExtraThreads()) {
backgroundAllocation = (GetCPUCount() >= 2);
HelperThreadState().ensureInitialized();
} else {
backgroundAllocation = false;
}
#else
backgroundAllocation = false;
#endif /* JS_THREADSAFE */
@ -2755,6 +2758,8 @@ void
GCHelperState::work()
{
#ifdef JS_THREADSAFE
JS_ASSERT(CanUseExtraThreads());
AutoLockGC lock(rt);
JS_ASSERT(!thread);
@ -2812,6 +2817,8 @@ void
GCHelperState::startBackgroundSweep(bool shouldShrink)
{
#ifdef JS_THREADSAFE
JS_ASSERT(CanUseExtraThreads());
AutoLockHelperThreadState helperLock;
AutoLockGC lock(rt);
JS_ASSERT(state() == IDLE);
@ -2827,6 +2834,7 @@ void
GCHelperState::startBackgroundShrink()
{
#ifdef JS_THREADSAFE
JS_ASSERT(CanUseExtraThreads());
switch (state()) {
case IDLE:
JS_ASSERT(!sweepFlag);
@ -4333,7 +4341,7 @@ GCRuntime::beginSweepPhase(bool lastGC)
gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP);
#ifdef JS_THREADSAFE
sweepOnBackgroundThread = !lastGC && !TraceEnabled();
sweepOnBackgroundThread = !lastGC && !TraceEnabled() && CanUseExtraThreads();
#endif
#ifdef DEBUG

View File

@ -1652,7 +1652,8 @@ ScriptSource::setSourceCopy(ExclusiveContext *cx, SourceBufferHolder &srcBuf,
#if defined(JS_THREADSAFE)
bool canCompressOffThread =
HelperThreadState().cpuCount > 1 &&
HelperThreadState().threadCount >= 2;
HelperThreadState().threadCount >= 2 &&
CanUseExtraThreads();
#else
bool canCompressOffThread = false;
#endif

View File

@ -2862,6 +2862,11 @@ Vector<PRThread *, 0, SystemAllocPolicy> workerThreads;
static bool
EvalInWorker(JSContext *cx, unsigned argc, jsval *vp)
{
if (!CanUseExtraThreads()) {
JS_ReportError(cx, "Can't create worker threads with --no-threads");
return false;
}
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.get(0).isString()) {
JS_ReportError(cx, "Invalid arguments to evalInWorker");
@ -3672,6 +3677,11 @@ OffThreadCompileScriptCallback(void *token, void *callbackData)
static bool
OffThreadCompileScript(JSContext *cx, unsigned argc, jsval *vp)
{
if (!CanUseExtraThreads()) {
JS_ReportError(cx, "Can't use offThreadCompileScript with --no-threads");
return false;
}
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1) {
@ -6305,6 +6315,7 @@ main(int argc, char **argv, char **envp)
|| !op.addBoolOption('\0', "fuzzing-safe", "Don't expose functions that aren't safe for "
"fuzzers to call")
|| !op.addBoolOption('\0', "latin1-strings", "Enable Latin1 strings (default: on)")
|| !op.addBoolOption('\0', "no-threads", "Disable helper threads and PJS threads")
#ifdef DEBUG
|| !op.addBoolOption('\0', "dump-entrained-variables", "Print variables which are "
"unnecessarily entrained by inner functions")
@ -6384,6 +6395,9 @@ main(int argc, char **argv, char **envp)
#endif // DEBUG
if (op.getBoolOption("no-threads"))
js::DisableExtraThreads();
#ifdef JS_THREADSAFE
// The fake thread count must be set before initializing the Runtime,
// which spins up the thread pool.
@ -6463,6 +6477,7 @@ main(int argc, char **argv, char **envp)
gInterruptFunc.destroy();
#ifdef JS_THREADSAFE
MOZ_ASSERT_IF(!CanUseExtraThreads(), workerThreads.empty());
for (size_t i = 0; i < workerThreads.length(); i++)
PR_JoinThread(workerThreads[i]);
#endif

View File

@ -13,7 +13,7 @@ from results import TestOutput
TBPL_FLAGS = [
[], # no flags, normal baseline and ion
['--ion-eager', '--ion-offthread-compile=off'], # implies --baseline-eager
['--ion-eager', '--ion-offthread-compile=off', '--ion-check-range-analysis', '--no-sse3'],
['--ion-eager', '--ion-offthread-compile=off', '--ion-check-range-analysis', '--no-sse3', '--no-threads'],
['--baseline-eager'],
['--baseline-eager', '--no-fpu'],
['--no-baseline', '--no-ion'],

View File

@ -56,9 +56,8 @@ static bool
ExecuteSequentially(JSContext *cx_, HandleValue funVal, uint16_t *sliceStart,
uint16_t sliceEnd);
#if !defined(JS_THREADSAFE) || !defined(JS_ION)
bool
js::ForkJoin(JSContext *cx, CallArgs &args)
static bool
ForkJoinSequentially(JSContext *cx, CallArgs &args)
{
RootedValue argZero(cx, args[0]);
uint16_t sliceStart = uint16_t(args[1].toInt32());
@ -69,6 +68,13 @@ js::ForkJoin(JSContext *cx, CallArgs &args)
return true;
}
#if !defined(JS_THREADSAFE) || !defined(JS_ION)
bool
js::ForkJoin(JSContext *cx, CallArgs &args)
{
return ForkJoinSequentially(cx, args);
}
JSContext *
ForkJoinContext::acquireJSContext()
{
@ -503,6 +509,9 @@ js::ForkJoin(JSContext *cx, CallArgs &args)
JS_ASSERT(args[3].toInt32() < NumForkJoinModes);
JS_ASSERT(args[4].isObjectOrNull());
if (!CanUseExtraThreads())
return ForkJoinSequentially(cx, args);
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
uint16_t sliceStart = (uint16_t)(args[1].toInt32());
uint16_t sliceEnd = (uint16_t)(args[2].toInt32());

View File

@ -417,6 +417,8 @@ static const uint32_t HELPER_STACK_QUOTA = 450 * 1024;
void
GlobalHelperThreadState::ensureInitialized()
{
JS_ASSERT(CanUseExtraThreads());
JS_ASSERT(this == &HelperThreadState());
AutoLockHelperThreadState lock;
@ -459,6 +461,7 @@ void
GlobalHelperThreadState::finish()
{
if (threads) {
MOZ_ASSERT(CanUseExtraThreads());
for (size_t i = 0; i < threadCount; i++)
threads[i].destroy();
js_free(threads);
@ -1190,6 +1193,8 @@ HelperThread::handleGCHelperWorkload()
void
HelperThread::threadLoop()
{
JS_ASSERT(CanUseExtraThreads());
JS::AutoSuppressGCAnalysis nogc;
AutoLockHelperThreadState lock;

View File

@ -64,6 +64,16 @@ using JS::DoubleNaNValue;
/* static */ size_t JSRuntime::liveRuntimesCount;
#endif
namespace js {
bool gCanUseExtraThreads = true;
};
void
js::DisableExtraThreads()
{
gCanUseExtraThreads = false;
}
const JSSecurityCallbacks js::NullSecurityCallbacks = { };
PerThreadData::PerThreadData(JSRuntime *runtime)

View File

@ -483,6 +483,15 @@ void AssertCurrentThreadCanLock(RuntimeLock which);
inline void AssertCurrentThreadCanLock(RuntimeLock which) {}
#endif
inline bool
CanUseExtraThreads()
{
extern bool gCanUseExtraThreads;
return gCanUseExtraThreads;
}
void DisableExtraThreads();
/*
* Encapsulates portions of the runtime/context that are tied to a
* single active thread. Instances of this structure can occur for

View File

@ -141,6 +141,8 @@ ThreadPoolWorker::start()
// Set state to active now, *before* the thread starts:
state_ = ACTIVE;
MOZ_ASSERT(CanUseExtraThreads());
return PR_CreateThread(PR_USER_THREAD,
HelperThreadMain, this,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
@ -179,6 +181,7 @@ void
ThreadPoolWorker::helperLoop()
{
MOZ_ASSERT(!isMainThread());
MOZ_ASSERT(CanUseExtraThreads());
// This is hokey in the extreme. To compute the stack limit,
// subtract the size of the stack from the address of a local