Bug 939614: IonMonkey: Use logic in UsesBeforeCompile to get actual needed usecount, r=jandem

This commit is contained in:
Hannes Verschore 2013-12-12 15:14:13 +01:00
parent 173672a3af
commit c7b5004870
7 changed files with 73 additions and 73 deletions

View File

@ -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,

View File

@ -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)
{

View File

@ -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);

View File

@ -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 *

View File

@ -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;

View File

@ -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;

View File

@ -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,