Bug 1127908 - Allow overriding the Ion register allocator with an environment variable, clean up Ion default overrides a bit, r=h4writer.
☠☠ backed out by 8b9d38b020e1 ☠ ☠
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 03 Feb 2015 08:11:08 -0700
changeset 254362 8b393c8dae2b60833936bc46cd8257e0ddc0477f
parent 254361 b69f8f44b1bb8df7794bb01a5fa644fbf2f56aa4
child 254363 f65ca700dfff2492fe49902bf2f1e3a150188543
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1127908
milestone38.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 1127908 - Allow overriding the Ion register allocator with an environment variable, clean up Ion default overrides a bit, r=h4writer.
js/src/jit/IonOptimizationLevels.cpp
js/src/jit/IonOptimizationLevels.h
js/src/jit/JitOptions.cpp
js/src/jit/JitOptions.h
js/src/jsapi.cpp
js/src/shell/js.cpp
--- a/js/src/jit/IonOptimizationLevels.cpp
+++ b/js/src/jit/IonOptimizationLevels.cpp
@@ -36,17 +36,17 @@ OptimizationInfo::initNormalOptimization
     sink_ = true;
     registerAllocator_ = RegisterAllocator_LSRA;
 
     inlineMaxTotalBytecodeLength_ = 1000;
     inliningMaxCallerBytecodeLength_ = 10000;
     maxInlineDepth_ = 3;
     scalarReplacement_ = true;
     smallFunctionMaxInlineDepth_ = 10;
-    compilerWarmUpThreshold_ = 1000;
+    compilerWarmUpThreshold_ = CompilerWarmupThreshold;
     inliningWarmUpThresholdFactor_ = 0.125;
     inliningRecompileThresholdFactor_ = 4;
 }
 
 void
 OptimizationInfo::initAsmjsOptimizationInfo()
 {
     // The AsmJS optimization level
@@ -68,18 +68,18 @@ uint32_t
 OptimizationInfo::compilerWarmUpThreshold(JSScript *script, jsbytecode *pc) const
 {
     MOZ_ASSERT(pc == nullptr || pc == script->code() || JSOp(*pc) == JSOP_LOOPENTRY);
 
     if (pc == script->code())
         pc = nullptr;
 
     uint32_t warmUpThreshold = compilerWarmUpThreshold_;
-    if (js_JitOptions.forceDefaultIonWarmUpThreshold)
-        warmUpThreshold = js_JitOptions.forcedDefaultIonWarmUpThreshold;
+    if (js_JitOptions.forcedDefaultIonWarmUpThreshold.isSome())
+        warmUpThreshold = js_JitOptions.forcedDefaultIonWarmUpThreshold.ref();
 
     // If the script is too large to compile on the main thread, we can still
     // compile it off thread. In these cases, increase the warm-up counter
     // threshold to improve the compilation's type information and hopefully
     // avoid later recompilation.
 
     if (script->length() > MAX_MAIN_THREAD_SCRIPT_SIZE)
         warmUpThreshold *= (script->length() / (double) MAX_MAIN_THREAD_SCRIPT_SIZE);
--- a/js/src/jit/IonOptimizationLevels.h
+++ b/js/src/jit/IonOptimizationLevels.h
@@ -102,16 +102,19 @@ class OptimizationInfo
     // The value is currently very low.
     // Actually it is only needed to make sure we don't blow out the stack.
     uint32_t smallFunctionMaxInlineDepth_;
 
     // How many invocations or loop iterations are needed before functions
     // are compiled.
     uint32_t compilerWarmUpThreshold_;
 
+    // Default compiler warmup threshold, unless it is overridden.
+    static const uint32_t CompilerWarmupThreshold = 1000;
+
     // How many invocations or loop iterations are needed before calls
     // are inlined, as a fraction of compilerWarmUpThreshold.
     double inliningWarmUpThresholdFactor_;
 
     // How many invocations or loop iterations are needed before a function
     // is hot enough to recompile the outerScript to inline that function,
     // as a multiplication of inliningWarmUpThreshold.
     uint32_t inliningRecompileThresholdFactor_;
@@ -168,19 +171,19 @@ class OptimizationInfo
         return edgeCaseAnalysis_ && !js_JitOptions.disableEdgeCaseAnalysis;
     }
 
     bool eliminateRedundantChecksEnabled() const {
         return eliminateRedundantChecks_;
     }
 
     IonRegisterAllocator registerAllocator() const {
-        if (!js_JitOptions.forceRegisterAllocator)
-            return registerAllocator_;
-        return js_JitOptions.forcedRegisterAllocator;
+        if (js_JitOptions.forcedRegisterAllocator.isSome())
+            return js_JitOptions.forcedRegisterAllocator.ref();
+        return registerAllocator_;
     }
 
     bool scalarReplacementEnabled() const {
         return scalarReplacement_ && !js_JitOptions.disableScalarReplacement;
     }
 
     uint32_t smallFunctionMaxInlineDepth() const {
         return smallFunctionMaxInlineDepth_;
@@ -197,18 +200,18 @@ class OptimizationInfo
     }
 
     uint32_t inliningMaxCallerBytecodeLength() const {
         return inlineMaxTotalBytecodeLength_;
     }
 
     uint32_t inliningWarmUpThreshold() const {
         uint32_t compilerWarmUpThreshold = compilerWarmUpThreshold_;
-        if (js_JitOptions.forceDefaultIonWarmUpThreshold)
-            compilerWarmUpThreshold = js_JitOptions.forcedDefaultIonWarmUpThreshold;
+        if (js_JitOptions.forcedDefaultIonWarmUpThreshold.isSome())
+            compilerWarmUpThreshold = js_JitOptions.forcedDefaultIonWarmUpThreshold.ref();
         return compilerWarmUpThreshold * inliningWarmUpThresholdFactor_;
     }
 
     uint32_t inliningRecompileThreshold() const {
         return inliningWarmUpThreshold() * inliningRecompileThresholdFactor_;
     }
 };
 
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -7,46 +7,61 @@
 #include "jit/JitOptions.h"
 #include "mozilla/TypeTraits.h"
 
 #include <cstdlib>
 #include "jsfun.h"
 using namespace js;
 using namespace js::jit;
 
+using mozilla::Maybe;
+
 namespace js {
 namespace jit {
 
 JitOptions js_JitOptions;
 
+static void Warn(const char *env, const char *value)
+{
+    fprintf(stderr, "Warning: I didn't understand %s=\"%s\"\n", env, value);
+}
+
 template<typename T> struct IsBool : mozilla::FalseType {};
 template<> struct IsBool<bool> : mozilla::TrueType {};
 
+static Maybe<int>
+ParseInt(const char *str)
+{
+    char *endp;
+    int retval = strtol(str, &endp, 0);
+    if (*endp == '\0')
+        return mozilla::Some(retval);
+    return mozilla::Nothing();
+}
+
 template<typename T>
 T overrideDefault(const char *param, T dflt) {
     char *str = getenv(param);
     if (!str)
         return dflt;
     if (IsBool<T>::value) {
         if (strcmp(str, "true") == 0 ||
             strcmp(str, "yes")) {
             return true;
         }
         if (strcmp(str, "false") == 0 ||
             strcmp(str, "no")) {
             return false;
         }
-        fprintf(stderr, "Warning: I didn't understand %s=\"%s\"", param, str);
+        Warn(param, str);
     } else {
-        char *endp;
-        int retval = strtol(str, &endp, 0);
-        if (*endp == '\0')
-            return retval;
-
-        fprintf(stderr, "Warning: I didn't understand %s=\"%s\"", param, str);
+        Maybe<int> value = ParseInt(str);
+        if (value.isSome())
+            return value.ref();
+        Warn(param, str);
     }
     return dflt;
 }
 #define SET_DEFAULT(var, dflt) var = overrideDefault("JIT_OPTION_" #var, dflt)
 JitOptions::JitOptions()
 {
     // Whether to perform expensive graph-consistency DEBUG-only assertions.
     // It can be useful to disable this to reduce DEBUG-compile time of large
@@ -91,23 +106,33 @@ JitOptions::JitOptions()
     SET_DEFAULT(disableEaa, false);
 
     // Whether functions are compiled immediately.
     SET_DEFAULT(eagerCompilation, false);
 
     // Force how many invocation or loop iterations are needed before compiling
     // a function with the highest ionmonkey optimization level.
     // (i.e. OptimizationLevel_Normal)
-    SET_DEFAULT(forceDefaultIonWarmUpThreshold, false);
-    SET_DEFAULT(forcedDefaultIonWarmUpThreshold, 1000);
+    const char *forcedDefaultIonWarmUpThresholdEnv = "JIT_OPTION_forcedDefaultIonWarmUpThreshold";
+    if (const char *env = getenv(forcedDefaultIonWarmUpThresholdEnv)) {
+        Maybe<int> value = ParseInt(env);
+        if (value.isSome())
+            forcedDefaultIonWarmUpThreshold.emplace(value.ref());
+        else
+            Warn(forcedDefaultIonWarmUpThresholdEnv, env);
+    }
 
-    // Force the used register allocator instead of letting the
-    // optimization pass decide.
-    forceRegisterAllocator = false;
-    forcedRegisterAllocator = RegisterAllocator_LSRA;
+    // Force the used register allocator instead of letting the optimization
+    // pass decide.
+    const char *forcedRegisterAllocatorEnv = "JIT_OPTION_forcedRegisterAllocator";
+    if (const char *env = getenv(forcedRegisterAllocatorEnv)) {
+        forcedRegisterAllocator = LookupRegisterAllocator(env);
+        if (!forcedRegisterAllocator.isSome())
+            Warn(forcedRegisterAllocatorEnv, env);
+    }
 
     // Toggles whether large scripts are rejected.
     SET_DEFAULT(limitScriptSize, true);
 
     // Toggles whether functions may be entered at loop headers.
     SET_DEFAULT(osr, true);
 
     // How many invocations or loop iterations are needed before functions
@@ -143,38 +168,36 @@ JitOptions::isSmallFunction(JSScript *sc
     return script->length() <= smallFunctionMaxBytecodeLength_;
 }
 
 void
 JitOptions::setEagerCompilation()
 {
     eagerCompilation = true;
     baselineWarmUpThreshold = 0;
-    forceDefaultIonWarmUpThreshold = true;
-    forcedDefaultIonWarmUpThreshold = 0;
+    forcedDefaultIonWarmUpThreshold.emplace(0);
 }
 
 void
 JitOptions::setCompilerWarmUpThreshold(uint32_t warmUpThreshold)
 {
-    forceDefaultIonWarmUpThreshold = true;
-    forcedDefaultIonWarmUpThreshold = warmUpThreshold;
+    forcedDefaultIonWarmUpThreshold.emplace(warmUpThreshold);
 
     // Undo eager compilation
     if (eagerCompilation && warmUpThreshold != 0) {
         jit::JitOptions defaultValues;
         eagerCompilation = false;
         baselineWarmUpThreshold = defaultValues.baselineWarmUpThreshold;
     }
 }
 
 void
 JitOptions::resetCompilerWarmUpThreshold()
 {
-    forceDefaultIonWarmUpThreshold = false;
+    forcedDefaultIonWarmUpThreshold.reset();
 
     // Undo eager compilation
     if (eagerCompilation) {
         jit::JitOptions defaultValues;
         eagerCompilation = false;
         baselineWarmUpThreshold = defaultValues.baselineWarmUpThreshold;
     }
 }
--- a/js/src/jit/JitOptions.h
+++ b/js/src/jit/JitOptions.h
@@ -20,16 +20,28 @@ static const uint32_t MAX_MAIN_THREAD_LO
 
 // Possible register allocators which may be used.
 enum IonRegisterAllocator {
     RegisterAllocator_LSRA,
     RegisterAllocator_Backtracking,
     RegisterAllocator_Stupid
 };
 
+static inline mozilla::Maybe<IonRegisterAllocator>
+LookupRegisterAllocator(const char *name)
+{
+    if (!strcmp(name, "lsra"))
+        return mozilla::Some(RegisterAllocator_LSRA);
+    if (!strcmp(name, "backtracking"))
+        return mozilla::Some(RegisterAllocator_Backtracking);
+    if (!strcmp(name, "stupid"))
+        return mozilla::Some(RegisterAllocator_Stupid);
+    return mozilla::Nothing();
+}
+
 struct JitOptions
 {
     bool checkGraphConsistency;
 #ifdef CHECK_OSIPOINT_REGISTERS
     bool checkOsiPointRegisters;
 #endif
     bool checkRangeAnalysis;
     bool disableScalarReplacement;
@@ -37,20 +49,18 @@ struct JitOptions
     bool disableLicm;
     bool disableInlining;
     bool disableEdgeCaseAnalysis;
     bool disableRangeAnalysis;
     bool disableSink;
     bool disableLoopUnrolling;
     bool disableEaa;
     bool eagerCompilation;
-    bool forceDefaultIonWarmUpThreshold;
-    uint32_t forcedDefaultIonWarmUpThreshold;
-    bool forceRegisterAllocator;
-    IonRegisterAllocator forcedRegisterAllocator;
+    mozilla::Maybe<uint32_t> forcedDefaultIonWarmUpThreshold;
+    mozilla::Maybe<IonRegisterAllocator> forcedRegisterAllocator;
     bool limitScriptSize;
     bool osr;
     uint32_t baselineWarmUpThreshold;
     uint32_t exceptionBailoutThreshold;
     uint32_t frequentBailoutThreshold;
     uint32_t maxStackArgs;
     uint32_t osrPcMismatchesBeforeRecompile;
     uint32_t smallFunctionMaxBytecodeLength_;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5733,17 +5733,19 @@ JS_SetGlobalJitCompilerOption(JSRuntime 
 JS_PUBLIC_API(int)
 JS_GetGlobalJitCompilerOption(JSRuntime *rt, JSJitCompilerOption opt)
 {
 #ifndef JS_CODEGEN_NONE
     switch (opt) {
       case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER:
         return jit::js_JitOptions.baselineWarmUpThreshold;
       case JSJITCOMPILER_ION_WARMUP_TRIGGER:
-        return jit::js_JitOptions.forcedDefaultIonWarmUpThreshold;
+        return jit::js_JitOptions.forcedDefaultIonWarmUpThreshold.isSome()
+             ? jit::js_JitOptions.forcedDefaultIonWarmUpThreshold.ref()
+             : jit::OptimizationInfo::CompilerWarmupThreshold;
       case JSJITCOMPILER_ION_ENABLE:
         return JS::RuntimeOptionsRef(rt).ion();
       case JSJITCOMPILER_BASELINE_ENABLE:
         return JS::RuntimeOptionsRef(rt).baseline();
       case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE:
         return rt->canUseOffthreadIonCompilation();
       case JSJITCOMPILER_SIGNALS_ENABLE:
         return rt->canUseSignalHandlers();
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5645,28 +5645,19 @@ SetRuntimeOptions(JSRuntime *rt, const O
     warmUpThreshold = op.getIntOption("baseline-warmup-threshold");
     if (warmUpThreshold >= 0)
         jit::js_JitOptions.baselineWarmUpThreshold = warmUpThreshold;
 
     if (op.getBoolOption("baseline-eager"))
         jit::js_JitOptions.baselineWarmUpThreshold = 0;
 
     if (const char *str = op.getStringOption("ion-regalloc")) {
-        if (strcmp(str, "lsra") == 0) {
-            jit::js_JitOptions.forceRegisterAllocator = true;
-            jit::js_JitOptions.forcedRegisterAllocator = jit::RegisterAllocator_LSRA;
-        } else if (strcmp(str, "backtracking") == 0) {
-            jit::js_JitOptions.forceRegisterAllocator = true;
-            jit::js_JitOptions.forcedRegisterAllocator = jit::RegisterAllocator_Backtracking;
-        } else if (strcmp(str, "stupid") == 0) {
-            jit::js_JitOptions.forceRegisterAllocator = true;
-            jit::js_JitOptions.forcedRegisterAllocator = jit::RegisterAllocator_Stupid;
-        } else {
+        jit::js_JitOptions.forcedRegisterAllocator = jit::LookupRegisterAllocator(str);
+        if (!jit::js_JitOptions.forcedRegisterAllocator.isSome())
             return OptionFailure("ion-regalloc", str);
-        }
     }
 
     if (op.getBoolOption("ion-eager"))
         jit::js_JitOptions.setEagerCompilation();
 
     bool offthreadCompilation = true;
     if (const char *str = op.getStringOption("ion-offthread-compile")) {
         if (strcmp(str, "off") == 0)