From c7b500487087825f217107d43e466e12cd35f795 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Thu, 12 Dec 2013 15:14:13 +0100 Subject: [PATCH] Bug 939614: IonMonkey: Use logic in UsesBeforeCompile to get actual needed usecount, r=jandem --- js/src/jit/BaselineCompiler.cpp | 3 +- js/src/jit/Ion.cpp | 50 ++---------------------- js/src/jit/Ion.h | 1 - js/src/jit/IonBuilder.cpp | 3 +- js/src/jit/IonOptimizationLevels.cpp | 58 +++++++++++++++++++++------- js/src/jit/IonOptimizationLevels.h | 20 +++++----- js/src/jit/JitOptions.h | 11 ++++++ 7 files changed, 73 insertions(+), 73 deletions(-) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 18cb87d1ee5..9ce50f6f90f 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -638,7 +638,8 @@ BaselineCompiler::emitUseCountIncrement() Label skipCall; - uint32_t minUses = UsesBeforeIonCompile(script, pc); + const OptimizationInfo *info = js_IonOptimizations.get(js_IonOptimizations.firstLevel()); + uint32_t minUses = info->usesBeforeCompile(script, pc); masm.branch32(Assembler::LessThan, countReg, Imm32(minUses), &skipCall); masm.branchPtr(Assembler::Equal, diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index de320952920..a7fbb58b8ba 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1808,17 +1808,6 @@ CheckScript(JSContext *cx, JSScript *script, bool osr) return true; } -// Longer scripts can only be compiled off thread, as these compilations -// can be expensive and stall the main thread for too long. -static const uint32_t MAX_OFF_THREAD_SCRIPT_SIZE = 100 * 1000; -static const uint32_t MAX_MAIN_THREAD_SCRIPT_SIZE = 2 * 1000; -static const uint32_t MAX_MAIN_THREAD_LOCALS_AND_ARGS = 256; - -// DOM Worker runtimes don't have off thread compilation, but can also compile -// larger scripts since this doesn't stall the main thread. -static const uint32_t MAX_DOM_WORKER_SCRIPT_SIZE = 16 * 1000; -static const uint32_t MAX_DOM_WORKER_LOCALS_AND_ARGS = 2048; - static MethodStatus CheckScriptSize(JSContext *cx, JSScript* script) { @@ -1882,14 +1871,14 @@ CanIonCompileScript(JSContext *cx, HandleScript script, bool osr) } static OptimizationLevel -GetOptimizationLevel(HandleScript script, ExecutionMode executionMode) +GetOptimizationLevel(HandleScript script, jsbytecode *pc, ExecutionMode executionMode) { if (executionMode == ParallelExecution) return Optimization_Normal; JS_ASSERT(executionMode == SequentialExecution); - return js_IonOptimizations.levelForUseCount(script->getUseCount()); + return js_IonOptimizations.levelForScript(script, pc); } static MethodStatus @@ -1922,7 +1911,7 @@ Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode } bool recompile = false; - OptimizationLevel optimizationLevel = GetOptimizationLevel(script, executionMode); + OptimizationLevel optimizationLevel = GetOptimizationLevel(script, osrPc, executionMode); if (optimizationLevel == Optimization_DontCompile) return Method_Skipped; @@ -2733,39 +2722,6 @@ jit::ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode) MOZ_ASSUME_UNREACHABLE("No such execution mode"); } -uint32_t -jit::UsesBeforeIonCompile(JSScript *script, jsbytecode *pc) -{ - JS_ASSERT(pc == script->code() || JSOp(*pc) == JSOP_LOOPENTRY); - - OptimizationLevel level = js_IonOptimizations.nextLevel(Optimization_DontCompile); - const OptimizationInfo *info = js_IonOptimizations.get(level); - - uint32_t minUses = info->usesBeforeCompile(); - - // If the script is too large to compile on the main thread, we can still - // compile it off thread. In these cases, increase the use count threshold - // to improve the compilation's type information and hopefully avoid later - // recompilation. - - if (script->length() > MAX_MAIN_THREAD_SCRIPT_SIZE) - minUses = minUses * (script->length() / (double) MAX_MAIN_THREAD_SCRIPT_SIZE); - - uint32_t numLocalsAndArgs = analyze::TotalSlots(script); - if (numLocalsAndArgs > MAX_MAIN_THREAD_LOCALS_AND_ARGS) - minUses = minUses * (numLocalsAndArgs / (double) MAX_MAIN_THREAD_LOCALS_AND_ARGS); - - if (JSOp(*pc) != JSOP_LOOPENTRY || js_JitOptions.eagerCompilation) - return minUses; - - // It's more efficient to enter outer loops, rather than inner loops, via OSR. - // To accomplish this, we use a slightly higher threshold for inner loops. - // Note that the loop depth is always > 0 so we will prefer non-OSR over OSR. - uint32_t loopDepth = GET_UINT8(pc); - JS_ASSERT(loopDepth > 0); - return minUses + loopDepth * 100; -} - void AutoFlushCache::updateTop(uintptr_t p, size_t len) { diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index 178e55202bb..8f27ec7be0a 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -180,7 +180,6 @@ TooManyArguments(unsigned nargs) void ForbidCompilation(JSContext *cx, JSScript *script); void ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode); -uint32_t UsesBeforeIonCompile(JSScript *script, jsbytecode *pc); void PurgeCaches(JSScript *script, JS::Zone *zone); size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 7a1b9325b0c..af7035088c4 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -6063,7 +6063,8 @@ IonBuilder::insertRecompileCheck() // of the next optimization level. OptimizationLevel nextLevel = js_IonOptimizations.nextLevel(curLevel); const OptimizationInfo *info = js_IonOptimizations.get(nextLevel); - current->add(MRecompileCheck::New(alloc(), topBuilder->script(), info->usesBeforeCompile())); + uint32_t useCount = info->usesBeforeCompile(topBuilder->script()); + current->add(MRecompileCheck::New(alloc(), topBuilder->script(), useCount)); } JSObject * diff --git a/js/src/jit/IonOptimizationLevels.cpp b/js/src/jit/IonOptimizationLevels.cpp index e6679c8ccbf..cd2009d03ac 100644 --- a/js/src/jit/IonOptimizationLevels.cpp +++ b/js/src/jit/IonOptimizationLevels.cpp @@ -56,23 +56,49 @@ OptimizationInfo::initAsmjsOptimizationInfo() eliminateRedundantChecks_ = false; } +uint32_t +OptimizationInfo::usesBeforeCompile(JSScript *script, jsbytecode *pc) const +{ + JS_ASSERT(pc == nullptr || pc == script->code() || JSOp(*pc) == JSOP_LOOPENTRY); + + if (pc == script->code()) + pc = nullptr; + + uint32_t minUses = usesBeforeCompile_; + if (js_JitOptions.forceDefaultIonUsesBeforeCompile) + minUses = js_JitOptions.forcedDefaultIonUsesBeforeCompile; + + // If the script is too large to compile on the main thread, we can still + // compile it off thread. In these cases, increase the use count threshold + // to improve the compilation's type information and hopefully avoid later + // recompilation. + + if (script->length() > MAX_MAIN_THREAD_SCRIPT_SIZE) + minUses = minUses * (script->length() / (double) MAX_MAIN_THREAD_SCRIPT_SIZE); + + uint32_t numLocalsAndArgs = analyze::TotalSlots(script); + if (numLocalsAndArgs > MAX_MAIN_THREAD_LOCALS_AND_ARGS) + minUses = minUses * (numLocalsAndArgs / (double) MAX_MAIN_THREAD_LOCALS_AND_ARGS); + + if (!pc || js_JitOptions.eagerCompilation) + return minUses; + + // It's more efficient to enter outer loops, rather than inner loops, via OSR. + // To accomplish this, we use a slightly higher threshold for inner loops. + // Note that the loop depth is always > 0 so we will prefer non-OSR over OSR. + uint32_t loopDepth = GET_UINT8(pc); + JS_ASSERT(loopDepth > 0); + return minUses + loopDepth * 100; +} + OptimizationInfos::OptimizationInfos() { infos_[Optimization_Normal - 1].initNormalOptimizationInfo(); infos_[Optimization_AsmJS - 1].initAsmjsOptimizationInfo(); - -#ifdef DEBUG - OptimizationLevel prev = nextLevel(Optimization_DontCompile); - while (!isLastLevel(prev)) { - OptimizationLevel next = nextLevel(prev); - JS_ASSERT(get(prev)->usesBeforeCompile() < get(next)->usesBeforeCompile()); - prev = next; - } -#endif } OptimizationLevel -OptimizationInfos::nextLevel(OptimizationLevel level) +OptimizationInfos::nextLevel(OptimizationLevel level) const { JS_ASSERT(!isLastLevel(level)); switch (level) { @@ -83,21 +109,27 @@ OptimizationInfos::nextLevel(OptimizationLevel level) } } +OptimizationLevel +OptimizationInfos::firstLevel() const +{ + return nextLevel(Optimization_DontCompile); +} + bool -OptimizationInfos::isLastLevel(OptimizationLevel level) +OptimizationInfos::isLastLevel(OptimizationLevel level) const { return level == Optimization_Normal; } OptimizationLevel -OptimizationInfos::levelForUseCount(uint32_t useCount) +OptimizationInfos::levelForScript(JSScript *script, jsbytecode *pc) const { OptimizationLevel prev = Optimization_DontCompile; while (!isLastLevel(prev)) { OptimizationLevel level = nextLevel(prev); const OptimizationInfo *info = get(level); - if (useCount < info->usesBeforeCompile()) + if (script->getUseCount() < info->usesBeforeCompile(script, pc)) return prev; prev = level; diff --git a/js/src/jit/IonOptimizationLevels.h b/js/src/jit/IonOptimizationLevels.h index 748f73794c4..fc37b652d2c 100644 --- a/js/src/jit/IonOptimizationLevels.h +++ b/js/src/jit/IonOptimizationLevels.h @@ -106,11 +106,7 @@ class OptimizationInfo return inlineNative_ && !js_JitOptions.disableInlining; } - uint32_t usesBeforeCompile() const { - if (js_JitOptions.forceDefaultIonUsesBeforeCompile) - return js_JitOptions.forcedDefaultIonUsesBeforeCompile; - return usesBeforeCompile_; - } + uint32_t usesBeforeCompile(JSScript *script, jsbytecode *pc = nullptr) const; bool gvnEnabled() const { return gvn_ && !js_JitOptions.disableGvn; @@ -171,7 +167,10 @@ class OptimizationInfo } uint32_t usesBeforeInlining() const { - return usesBeforeCompile() * usesBeforeInliningFactor_; + uint32_t usesBeforeCompile = usesBeforeCompile_; + if (js_JitOptions.forceDefaultIonUsesBeforeCompile) + usesBeforeCompile = js_JitOptions.forcedDefaultIonUsesBeforeCompile; + return usesBeforeCompile * usesBeforeInliningFactor_; } }; @@ -183,16 +182,17 @@ class OptimizationInfos public: OptimizationInfos(); - const OptimizationInfo *get(OptimizationLevel level) { + const OptimizationInfo *get(OptimizationLevel level) const { JS_ASSERT(level < Optimization_Count); JS_ASSERT(level != Optimization_DontCompile); return &infos_[level - 1]; } - OptimizationLevel nextLevel(OptimizationLevel level); - bool isLastLevel(OptimizationLevel level); - OptimizationLevel levelForUseCount(uint32_t useCount); + OptimizationLevel nextLevel(OptimizationLevel level) const; + OptimizationLevel firstLevel() const; + bool isLastLevel(OptimizationLevel level) const; + OptimizationLevel levelForScript(JSScript *script, jsbytecode *pc = nullptr) const; }; extern OptimizationInfos js_IonOptimizations; diff --git a/js/src/jit/JitOptions.h b/js/src/jit/JitOptions.h index 4703e94f576..a6f3d584306 100644 --- a/js/src/jit/JitOptions.h +++ b/js/src/jit/JitOptions.h @@ -15,6 +15,17 @@ namespace js { namespace jit { +// Longer scripts can only be compiled off thread, as these compilations +// can be expensive and stall the main thread for too long. +static const uint32_t MAX_OFF_THREAD_SCRIPT_SIZE = 100 * 1000; +static const uint32_t MAX_MAIN_THREAD_SCRIPT_SIZE = 2 * 1000; +static const uint32_t MAX_MAIN_THREAD_LOCALS_AND_ARGS = 256; + +// DOM Worker runtimes don't have off thread compilation, but can also compile +// larger scripts since this doesn't stall the main thread. +static const uint32_t MAX_DOM_WORKER_SCRIPT_SIZE = 16 * 1000; +static const uint32_t MAX_DOM_WORKER_LOCALS_AND_ARGS = 2048; + // Possible register allocators which may be used. enum IonRegisterAllocator { RegisterAllocator_LSRA,