Bug 907777 - Add preference for off thread parsing, coalesce with preference for off thread Ion compilation, r=billm.
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 22 Aug 2013 07:22:33 -0600
changeset 156803 caecd32b3f33eb3ea544489a1d58172042307113
parent 156802 a155905a9d08c211e53bccd2bc558d61d510fc36
child 156804 89bec7278d270b4784cbca26524e50560e455684
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs907777
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 907777 - Add preference for off thread parsing, coalesce with preference for off thread Ion compilation, r=billm.
dom/base/nsJSEnvironment.cpp
js/src/jit/AsmJS.cpp
js/src/jit/Ion.cpp
js/src/jit/Ion.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonSpewer.cpp
js/src/jit/shared/Assembler-shared.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsworkers.h
js/src/shell/js.cpp
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
modules/libpref/src/init/all.js
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -693,16 +693,17 @@ static const char js_memlog_option_str[]
 static const char js_memnotify_option_str[]   = JS_OPTIONS_DOT_STR "mem.notify";
 static const char js_asmjs_content_str[]      = JS_OPTIONS_DOT_STR "asmjs";
 static const char js_baselinejit_content_str[] = JS_OPTIONS_DOT_STR "baselinejit.content";
 static const char js_baselinejit_chrome_str[]  = JS_OPTIONS_DOT_STR "baselinejit.chrome";
 static const char js_baselinejit_eager_str[]  = JS_OPTIONS_DOT_STR "baselinejit.unsafe_eager_compilation";
 static const char js_ion_content_str[]        = JS_OPTIONS_DOT_STR "ion.content";
 static const char js_ion_chrome_str[]         = JS_OPTIONS_DOT_STR "ion.chrome";
 static const char js_ion_eager_str[]          = JS_OPTIONS_DOT_STR "ion.unsafe_eager_compilation";
+static const char js_parallel_parsing_str[]   = JS_OPTIONS_DOT_STR "parallel_parsing";
 static const char js_ion_parallel_compilation_str[] = JS_OPTIONS_DOT_STR "ion.parallel_compilation";
 
 int
 nsJSContext::JSOptionChangedCallback(const char *pref, void *data)
 {
   nsJSContext *context = reinterpret_cast<nsJSContext *>(data);
   uint32_t oldDefaultJSOptions = context->mDefaultJSOptions;
   uint32_t newDefaultJSOptions = oldDefaultJSOptions;
@@ -734,16 +735,17 @@ nsJSContext::JSOptionChangedCallback(con
                                                js_baselinejit_chrome_str :
                                                js_baselinejit_content_str);
   bool useBaselineJITEager = Preferences::GetBool(js_baselinejit_eager_str);
   bool useIon = Preferences::GetBool((chromeWindow || !contentWindow) ?
                                                js_ion_chrome_str :
                                                js_ion_content_str);
   bool useIonEager = Preferences::GetBool(js_ion_eager_str);
   bool useAsmJS = Preferences::GetBool(js_asmjs_content_str);
+  bool parallelParsing = Preferences::GetBool(js_parallel_parsing_str);
   bool parallelIonCompilation = Preferences::GetBool(js_ion_parallel_compilation_str);
   nsCOMPtr<nsIXULRuntime> xr = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
   if (xr) {
     bool safeMode = false;
     xr->GetInSafeMode(&safeMode);
     if (safeMode) {
       useTypeInference = false;
       useHardening = false;
@@ -788,17 +790,18 @@ nsJSContext::JSOptionChangedCallback(con
   bool werror = Preferences::GetBool(js_werror_option_str);
   if (werror)
     newDefaultJSOptions |= JSOPTION_WERROR;
   else
     newDefaultJSOptions &= ~JSOPTION_WERROR;
 
   ::JS_SetOptions(context->mContext, newDefaultJSOptions & JSOPTION_MASK);
 
-  ::JS_SetParallelCompilationEnabled(context->mContext, parallelIonCompilation);
+  ::JS_SetParallelParsingEnabled(context->mContext, parallelParsing);
+  ::JS_SetParallelIonCompilationEnabled(context->mContext, parallelIonCompilation);
 
   ::JS_SetGlobalCompilerOption(context->mContext, JSCOMPILER_BASELINE_USECOUNT_TRIGGER,
                                (useBaselineJITEager ? 0 : -1));
 
   ::JS_SetGlobalCompilerOption(context->mContext, JSCOMPILER_ION_USECOUNT_TRIGGER,
                                (useIonEager ? 0 : -1));
 
   // Save the new defaults for the next page load (InitContext).
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -4814,17 +4814,17 @@ ParallelCompilationEnabled(ExclusiveCont
     // off-thread compilation must be enabled. However, since there are a fixed
     // number of worker threads and one is already being consumed by this
     // 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 (!cx->isJSContext())
         return cx->workerThreadState()->numThreads > 1;
 
-    return OffThreadCompilationEnabled(cx->asJSContext());
+    return OffThreadIonCompilationEnabled(cx->asJSContext()->runtime());
 }
 
 // State of compilation as tracked and updated by the main thread.
 struct ParallelGroupState
 {
     WorkerThreadState &state;
     Vector<AsmJSParallelTask> &tasks;
     int32_t outstandingJobs; // Good work, jobs!
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1587,17 +1587,17 @@ OffThreadCompilationAvailable(JSContext 
     //
     // Skip off thread compilation if PC count profiling is enabled, as
     // CodeGenerator::maybeCreateScriptCounts will not attach script profiles
     // when running off thread.
     //
     // Also skip off thread compilation if the SPS profiler is enabled, as it
     // stores strings in the spsProfiler data structure, which is not protected
     // by a lock.
-    return OffThreadCompilationEnabled(cx)
+    return OffThreadIonCompilationEnabled(cx->runtime())
         && cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL
         && !cx->runtime()->profilingScripts
         && !cx->runtime()->spsProfiler.enabled();
 }
 
 static AbortReason
 IonCompile(JSContext *cx, JSScript *script,
            BaselineFrame *baselineFrame, jsbytecode *osrPc, bool constructing,
@@ -1768,17 +1768,17 @@ CheckScriptSize(JSContext *cx, JSScript*
         IonSpew(IonSpew_Abort, "Script too large (%u bytes)", script->length);
         return Method_CantCompile;
     }
 
     uint32_t numLocalsAndArgs = analyze::TotalSlots(script);
     if (script->length > MAX_MAIN_THREAD_SCRIPT_SIZE ||
         numLocalsAndArgs > MAX_MAIN_THREAD_LOCALS_AND_ARGS)
     {
-        if (OffThreadCompilationEnabled(cx)) {
+        if (OffThreadIonCompilationEnabled(cx->runtime())) {
             // Even if off thread compilation is enabled, there are cases where
             // compilation must still occur on the main thread. Don't compile
             // in these cases (except when profiling scripts, as compilations
             // occurring with profiling should reflect those without), but do
             // not forbid compilation so that the script may be compiled later.
             if (!OffThreadCompilationAvailable(cx) && !cx->runtime()->profilingScripts) {
                 IonSpew(IonSpew_Abort,
                         "Script too large for main thread, skipping (%u bytes) (%u locals/args)",
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -88,21 +88,16 @@ struct IonOptions
     // Default: true
     bool uce;
 
     // Toggles whether Effective Address Analysis is performed.
     //
     // Default: true
     bool eaa;
 
-    // Toggles whether compilation occurs off the main thread.
-    //
-    // Default: true iff there are at least two CPUs available
-    bool parallelCompilation;
-
 #ifdef CHECK_OSIPOINT_REGISTERS
     // Emit extra code to verify live regs at the start of a VM call
     // are not modified before its OsiPoint.
     //
     // Default: false
     bool checkOsiPointRegisters;
 #endif
 
@@ -199,34 +194,31 @@ struct IonOptions
     //
     // Default: 1
     uint32_t usesBeforeCompilePar;
 
     void setEagerCompilation() {
         eagerCompilation = true;
         usesBeforeCompile = 0;
         baselineUsesBeforeCompile = 0;
-
-        parallelCompilation = false;
     }
 
     IonOptions()
       : gvn(true),
         gvnIsOptimistic(true),
         licm(true),
         osr(true),
         limitScriptSize(true),
         registerAllocator(RegisterAllocator_LSRA),
         inlining(true),
         edgeCaseAnalysis(true),
         rangeAnalysis(true),
         checkRangeAnalysis(false),
         uce(true),
         eaa(true),
-        parallelCompilation(false),
 #ifdef CHECK_OSIPOINT_REGISTERS
         checkOsiPointRegisters(false),
 #endif
         baselineUsesBeforeCompile(10),
         usesBeforeCompile(1000),
         usesBeforeInliningFactor(.125),
         osrPcMismatchesBeforeRecompile(6000),
         frequentBailoutThreshold(10),
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -9033,17 +9033,14 @@ IonBuilder::addShapeGuard(MDefinition *o
         guard->setNotMovable();
 
     return guard;
 }
 
 types::StackTypeSet *
 IonBuilder::cloneTypeSet(types::StackTypeSet *types)
 {
-    if (!js_IonOptions.parallelCompilation)
-        return types;
-
     // Clone a type set so that it can be stored into the MIR and accessed
     // during off thread compilation. This is necessary because main thread
     // updates to type sets can race with reads in the compiler backend, and
     // after bug 804676 this code can be removed.
     return types->clone(GetIonContext()->temp->lifoAlloc());
 }
--- a/js/src/jit/IonSpewer.cpp
+++ b/js/src/jit/IonSpewer.cpp
@@ -3,16 +3,18 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef DEBUG
 
 #include "jit/IonSpewer.h"
 
+#include "jsworkers.h"
+
 #include "jit/Ion.h"
 
 #ifndef ION_SPEW_DIR
 # if defined(_WIN32)
 #  define ION_SPEW_DIR ""
 # elif defined(__ANDROID__)
 #  define ION_SPEW_DIR "/data/local/tmp/"
 # else
@@ -74,48 +76,48 @@ ion::EnableIonDebugLogging()
 {
     EnableChannel(IonSpew_Logs);
     ionspewer.init();
 }
 
 void
 ion::IonSpewNewFunction(MIRGraph *graph, HandleScript func)
 {
-    if (!js_IonOptions.parallelCompilation) {
+    if (!OffThreadIonCompilationEnabled(GetIonContext()->runtime)) {
         ionspewer.beginFunction(graph, func);
     } else {
         if (func) {
             IonSpew(IonSpew_Logs,
                     "Can't log script %s:%d. (Compiled on background thread.)",
                     func->filename(), func->lineno);
         } else {
             IonSpew(IonSpew_Logs,
                     "Can't log asm.js compilation. (Compiled on background thread.)");
         }
     }
 }
 
 void
 ion::IonSpewPass(const char *pass)
 {
-    if (!js_IonOptions.parallelCompilation)
+    if (!OffThreadIonCompilationEnabled(GetIonContext()->runtime))
         ionspewer.spewPass(pass);
 }
 
 void
 ion::IonSpewPass(const char *pass, LinearScanAllocator *ra)
 {
-    if (!js_IonOptions.parallelCompilation)
+    if (!OffThreadIonCompilationEnabled(GetIonContext()->runtime))
         ionspewer.spewPass(pass, ra);
 }
 
 void
 ion::IonSpewEndFunction()
 {
-    if (!js_IonOptions.parallelCompilation)
+    if (!OffThreadIonCompilationEnabled(GetIonContext()->runtime))
         ionspewer.endFunction();
 }
 
 
 IonSpewer::~IonSpewer()
 {
     if (!inited_)
         return;
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -6,16 +6,18 @@
 
 #ifndef jit_shared_Assembler_shared_h
 #define jit_shared_Assembler_shared_h
 
 #include "mozilla/PodOperations.h"
 
 #include <limits.h>
 
+#include "jsworkers.h"
+
 #include "jit/IonAllocPolicy.h"
 #include "jit/Registers.h"
 #include "jit/RegisterSets.h"
 
 #if defined(JS_CPU_X64) || defined(JS_CPU_ARM)
 // JS_SMALL_BRANCH means the range on a branch instruction
 // is smaller than the whole address space
 #    define JS_SMALL_BRANCH
@@ -264,18 +266,18 @@ class Label : public LabelBase
     { }
     Label(const Label &label) : LabelBase(label)
     { }
     ~Label()
     {
 #ifdef DEBUG
         // Note: the condition is a hack to silence this assert when OOM testing,
         // see bug 756614.
-        if (!js_IonOptions.parallelCompilation)
-            JS_ASSERT_IF(MaybeGetIonContext() && !GetIonContext()->runtime->hadOutOfMemory, !used());
+        if (MaybeGetIonContext() && !OffThreadIonCompilationEnabled(GetIonContext()->runtime))
+            JS_ASSERT_IF(!GetIonContext()->runtime->hadOutOfMemory, !used());
 #endif
     }
 };
 
 // Label's destructor asserts that if it has been used it has also been bound.
 // In the case long-lived labels, however, failed compilation (e.g. OOM) will
 // trigger this failure innocuously. This Label silences the assertion.
 class NonAssertingLabel : public Label
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4834,20 +4834,23 @@ JS::Compile(JSContext *cx, HandleObject 
     options = options.setFileAndLine(filename, 1);
     JSScript *script = Compile(cx, obj, options, file.fp());
     return script;
 }
 
 JS_PUBLIC_API(bool)
 JS::CanCompileOffThread(JSContext *cx, const CompileOptions &options)
 {
-#if defined(JS_THREADSAFE) && defined(JS_ION)
+#ifdef JS_WORKER_THREADS
     if (!cx->runtime()->useHelperThreads() || !cx->runtime()->helperThreadCount())
         return false;
 
+    if (!cx->runtime()->useHelperThreadsForParsing())
+        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;
 
     // Blacklist filenames which cause mysterious assertion failures in
@@ -4875,28 +4878,28 @@ JS::CanCompileOffThread(JSContext *cx, c
 #endif
 }
 
 JS_PUBLIC_API(bool)
 JS::CompileOffThread(JSContext *cx, Handle<JSObject*> obj, CompileOptions options,
                      const jschar *chars, size_t length,
                      OffThreadCompileCallback callback, void *callbackData)
 {
-#if defined(JS_THREADSAFE) && defined(JS_ION)
+#ifdef JS_WORKER_THREADS
     JS_ASSERT(CanCompileOffThread(cx, options));
     return StartOffThreadParseScript(cx, options, chars, length, obj, callback, callbackData);
 #else
     MOZ_ASSUME_UNREACHABLE("Off thread compilation is only available with JS_ION");
 #endif
 }
 
 JS_PUBLIC_API(void)
 JS::FinishOffThreadScript(JSRuntime *rt, JSScript *script)
 {
-#if defined(JS_THREADSAFE) && defined(JS_ION)
+#ifdef JS_WORKER_THREADS
     JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
     rt->workerThreadState->finishParseTaskForScript(rt, script);
 #else
     MOZ_ASSUME_UNREACHABLE("Off thread compilation is only available with JS_ION");
 #endif
 }
 
 JS_PUBLIC_API(JSScript *)
@@ -6631,20 +6634,28 @@ JS_SetGCZeal(JSContext *cx, uint8_t zeal
 JS_PUBLIC_API(void)
 JS_ScheduleGC(JSContext *cx, uint32_t count)
 {
     cx->runtime()->gcNextScheduled = count;
 }
 #endif
 
 JS_PUBLIC_API(void)
-JS_SetParallelCompilationEnabled(JSContext *cx, bool enabled)
+JS_SetParallelParsingEnabled(JSContext *cx, bool enabled)
 {
 #ifdef JS_ION
-    ion::js_IonOptions.parallelCompilation = enabled;
+    cx->runtime()->setCanUseHelperThreadsForParsing(enabled);
+#endif
+}
+
+JS_PUBLIC_API(void)
+JS_SetParallelIonCompilationEnabled(JSContext *cx, bool enabled)
+{
+#ifdef JS_ION
+    cx->runtime()->setCanUseHelperThreadsForIonCompilation(enabled);
 #endif
 }
 
 JS_PUBLIC_API(void)
 JS_SetGlobalCompilerOption(JSContext *cx, JSCompilerOption opt, uint32_t value)
 {
 #ifdef JS_ION
     ion::IonOptions defaultValues;
@@ -6656,21 +6667,16 @@ JS_SetGlobalCompilerOption(JSContext *cx
         ion::js_IonOptions.baselineUsesBeforeCompile = value;
         break;
       case JSCOMPILER_ION_USECOUNT_TRIGGER:
         if (value == uint32_t(-1))
             value = defaultValues.usesBeforeCompile;
         ion::js_IonOptions.usesBeforeCompile = value;
         ion::js_IonOptions.eagerCompilation = (value == 0);
         break;
-      case JSCOMPILER_PJS_ENABLE:
-        if (value == uint32_t(-1))
-            value = uint32_t(defaultValues.parallelCompilation);
-        ion::js_IonOptions.parallelCompilation = bool(value);
-        break;
     }
 #endif
 }
 
 /************************************************************************/
 
 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && defined(XP_WIN)
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5191,22 +5191,24 @@ JS_NewObjectForConstructor(JSContext *cx
 extern JS_PUBLIC_API(void)
 JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency);
 
 extern JS_PUBLIC_API(void)
 JS_ScheduleGC(JSContext *cx, uint32_t count);
 #endif
 
 extern JS_PUBLIC_API(void)
-JS_SetParallelCompilationEnabled(JSContext *cx, bool enabled);
+JS_SetParallelParsingEnabled(JSContext *cx, bool enabled);
+
+extern JS_PUBLIC_API(void)
+JS_SetParallelIonCompilationEnabled(JSContext *cx, bool enabled);
 
 typedef enum JSCompilerOption {
     JSCOMPILER_BASELINE_USECOUNT_TRIGGER,
-    JSCOMPILER_ION_USECOUNT_TRIGGER,
-    JSCOMPILER_PJS_ENABLE
+    JSCOMPILER_ION_USECOUNT_TRIGGER
 } JSCompilerOption;
 
 extern JS_PUBLIC_API(void)
 JS_SetGlobalCompilerOption(JSContext *cx, JSCompilerOption opt, uint32_t value);
 
 /*
  * Convert a uint32_t index into a jsid.
  */
--- a/js/src/jsworkers.h
+++ b/js/src/jsworkers.h
@@ -181,22 +181,22 @@ struct WorkerThread
 
     static void ThreadMain(void *arg);
     void threadLoop();
 };
 
 #endif /* JS_THREADSAFE && JS_ION */
 
 inline bool
-OffThreadCompilationEnabled(JSContext *cx)
+OffThreadIonCompilationEnabled(JSRuntime *rt)
 {
 #ifdef JS_WORKER_THREADS
-    return ion::js_IonOptions.parallelCompilation
-        && cx->runtime()->useHelperThreads()
-        && cx->runtime()->helperThreadCount() != 0;
+    return rt->useHelperThreads()
+        && rt->helperThreadCount() != 0
+        && rt->useHelperThreadsForIonCompilation();
 #else
     return false;
 #endif
 }
 
 /* Methods for interacting with worker threads. */
 
 /* Initialize worker threads unless already initialized. */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5146,29 +5146,33 @@ ProcessArgs(JSContext *cx, JSObject *obj
 
     if (op->getBoolOption("ion-eager"))
         ion::js_IonOptions.setEagerCompilation();
 
     if (op->getBoolOption("ion-compile-try-catch"))
         ion::js_IonOptions.compileTryCatch = true;
 
 #ifdef JS_THREADSAFE
+    bool parallelCompilation = false;
     if (const char *str = op->getStringOption("ion-parallel-compile")) {
         if (strcmp(str, "on") == 0) {
             if (cx->runtime()->helperThreadCount() == 0) {
                 fprintf(stderr, "Parallel compilation not available without helper threads");
                 return EXIT_FAILURE;
             }
-            ion::js_IonOptions.parallelCompilation = true;
-        } else if (strcmp(str, "off") == 0) {
-            ion::js_IonOptions.parallelCompilation = false;
-        } else {
+            parallelCompilation = true;
+        } else if (strcmp(str, "off") != 0) {
             return OptionFailure("ion-parallel-compile", str);
         }
     }
+    /*
+     * Note: In shell builds, parallel compilation is only enabled with an
+     * explicit option.
+     */
+    cx->runtime()->setCanUseHelperThreadsForIonCompilation(parallelCompilation);
 #endif /* JS_THREADSAFE */
 
 #endif /* JS_ION */
 
 #ifdef DEBUG
     if (op->getBoolOption("dump-entrained-variables"))
         dumpEntrainedVariables = true;
 #endif
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -264,17 +264,19 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     jitHardening(false),
     jitSupportsFloatingPoint(false),
     ionPcScriptCache(NULL),
     threadPool(this),
     ctypesActivityCallback(NULL),
     parallelWarmup(0),
     ionReturnOverride_(MagicValue(JS_ARG_POISON)),
     useHelperThreads_(useHelperThreads),
-    requestedHelperThreadCount(-1)
+    requestedHelperThreadCount(-1),
+    useHelperThreadsForIonCompilation_(true),
+    useHelperThreadsForParsing_(true)
 #ifdef DEBUG
     , enteredPolicy(NULL)
 #endif
 {
     liveRuntimesCount++;
 
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
     JS_INIT_CLIST(&onNewGlobalObjectWatchers);
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -1571,16 +1571,20 @@ struct JSRuntime : public JS::shadow::Ru
 
     void sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *runtime);
 
   private:
 
     JSUseHelperThreads useHelperThreads_;
     int32_t requestedHelperThreadCount;
 
+    // Settings for how helper threads can be used.
+    bool useHelperThreadsForIonCompilation_;
+    bool useHelperThreadsForParsing_;
+
   public:
 
     bool useHelperThreads() const {
 #ifdef JS_THREADSAFE
         return useHelperThreads_ == JS_USE_HELPER_THREADS;
 #else
         return false;
 #endif
@@ -1596,16 +1600,30 @@ struct JSRuntime : public JS::shadow::Ru
         if (requestedHelperThreadCount < 0)
             return js::GetCPUCount() - 1;
         return requestedHelperThreadCount;
 #else
         return 0;
 #endif
     }
 
+    void setCanUseHelperThreadsForIonCompilation(bool value) {
+        useHelperThreadsForIonCompilation_ = value;
+    }
+    bool useHelperThreadsForIonCompilation() const {
+        return useHelperThreadsForIonCompilation_;
+    }
+
+    void setCanUseHelperThreadsForParsing(bool value) {
+        useHelperThreadsForParsing_ = value;
+    }
+    bool useHelperThreadsForParsing() const {
+        return useHelperThreadsForParsing_;
+    }
+
 #ifdef DEBUG
   public:
     js::AutoEnterPolicy *enteredPolicy;
 #endif
 };
 
 namespace js {
 
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -816,16 +816,17 @@ pref("javascript.options.strict",       
 #ifdef DEBUG
 pref("javascript.options.strict.debug",     true);
 #endif
 pref("javascript.options.baselinejit.content", true);
 pref("javascript.options.baselinejit.chrome",  true);
 pref("javascript.options.ion.content",      true);
 pref("javascript.options.ion.chrome",       false);
 pref("javascript.options.asmjs",            true);
+pref("javascript.options.parallel_parsing", true);
 pref("javascript.options.ion.parallel_compilation", true);
 pref("javascript.options.jit_hardening", true);
 pref("javascript.options.typeinference.content", true);
 pref("javascript.options.typeinference.chrome", false);
 // This preference limits the memory usage of javascript.
 // If you want to change these values for your device,
 // please find Bug 417052 comment 17 and Bug 456721
 // Comment 32 and Bug 613551.