mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 939614: IonMonkey: Use logic in UsesBeforeCompile to get actual needed usecount, r=jandem
This commit is contained in:
parent
173672a3af
commit
c7b5004870
@ -638,7 +638,8 @@ BaselineCompiler::emitUseCountIncrement()
|
|||||||
|
|
||||||
Label skipCall;
|
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.branch32(Assembler::LessThan, countReg, Imm32(minUses), &skipCall);
|
||||||
|
|
||||||
masm.branchPtr(Assembler::Equal,
|
masm.branchPtr(Assembler::Equal,
|
||||||
|
@ -1808,17 +1808,6 @@ CheckScript(JSContext *cx, JSScript *script, bool osr)
|
|||||||
return true;
|
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
|
static MethodStatus
|
||||||
CheckScriptSize(JSContext *cx, JSScript* script)
|
CheckScriptSize(JSContext *cx, JSScript* script)
|
||||||
{
|
{
|
||||||
@ -1882,14 +1871,14 @@ CanIonCompileScript(JSContext *cx, HandleScript script, bool osr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static OptimizationLevel
|
static OptimizationLevel
|
||||||
GetOptimizationLevel(HandleScript script, ExecutionMode executionMode)
|
GetOptimizationLevel(HandleScript script, jsbytecode *pc, ExecutionMode executionMode)
|
||||||
{
|
{
|
||||||
if (executionMode == ParallelExecution)
|
if (executionMode == ParallelExecution)
|
||||||
return Optimization_Normal;
|
return Optimization_Normal;
|
||||||
|
|
||||||
JS_ASSERT(executionMode == SequentialExecution);
|
JS_ASSERT(executionMode == SequentialExecution);
|
||||||
|
|
||||||
return js_IonOptimizations.levelForUseCount(script->getUseCount());
|
return js_IonOptimizations.levelForScript(script, pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MethodStatus
|
static MethodStatus
|
||||||
@ -1922,7 +1911,7 @@ Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool recompile = false;
|
bool recompile = false;
|
||||||
OptimizationLevel optimizationLevel = GetOptimizationLevel(script, executionMode);
|
OptimizationLevel optimizationLevel = GetOptimizationLevel(script, osrPc, executionMode);
|
||||||
if (optimizationLevel == Optimization_DontCompile)
|
if (optimizationLevel == Optimization_DontCompile)
|
||||||
return Method_Skipped;
|
return Method_Skipped;
|
||||||
|
|
||||||
@ -2733,39 +2722,6 @@ jit::ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode)
|
|||||||
MOZ_ASSUME_UNREACHABLE("No such execution 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
|
void
|
||||||
AutoFlushCache::updateTop(uintptr_t p, size_t len)
|
AutoFlushCache::updateTop(uintptr_t p, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -180,7 +180,6 @@ TooManyArguments(unsigned nargs)
|
|||||||
|
|
||||||
void ForbidCompilation(JSContext *cx, JSScript *script);
|
void ForbidCompilation(JSContext *cx, JSScript *script);
|
||||||
void ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode);
|
void ForbidCompilation(JSContext *cx, JSScript *script, ExecutionMode mode);
|
||||||
uint32_t UsesBeforeIonCompile(JSScript *script, jsbytecode *pc);
|
|
||||||
|
|
||||||
void PurgeCaches(JSScript *script, JS::Zone *zone);
|
void PurgeCaches(JSScript *script, JS::Zone *zone);
|
||||||
size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf);
|
size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf);
|
||||||
|
@ -6063,7 +6063,8 @@ IonBuilder::insertRecompileCheck()
|
|||||||
// of the next optimization level.
|
// of the next optimization level.
|
||||||
OptimizationLevel nextLevel = js_IonOptimizations.nextLevel(curLevel);
|
OptimizationLevel nextLevel = js_IonOptimizations.nextLevel(curLevel);
|
||||||
const OptimizationInfo *info = js_IonOptimizations.get(nextLevel);
|
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 *
|
JSObject *
|
||||||
|
@ -56,23 +56,49 @@ OptimizationInfo::initAsmjsOptimizationInfo()
|
|||||||
eliminateRedundantChecks_ = false;
|
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()
|
OptimizationInfos::OptimizationInfos()
|
||||||
{
|
{
|
||||||
infos_[Optimization_Normal - 1].initNormalOptimizationInfo();
|
infos_[Optimization_Normal - 1].initNormalOptimizationInfo();
|
||||||
infos_[Optimization_AsmJS - 1].initAsmjsOptimizationInfo();
|
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
|
OptimizationLevel
|
||||||
OptimizationInfos::nextLevel(OptimizationLevel level)
|
OptimizationInfos::nextLevel(OptimizationLevel level) const
|
||||||
{
|
{
|
||||||
JS_ASSERT(!isLastLevel(level));
|
JS_ASSERT(!isLastLevel(level));
|
||||||
switch (level) {
|
switch (level) {
|
||||||
@ -83,21 +109,27 @@ OptimizationInfos::nextLevel(OptimizationLevel level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OptimizationLevel
|
||||||
|
OptimizationInfos::firstLevel() const
|
||||||
|
{
|
||||||
|
return nextLevel(Optimization_DontCompile);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
OptimizationInfos::isLastLevel(OptimizationLevel level)
|
OptimizationInfos::isLastLevel(OptimizationLevel level) const
|
||||||
{
|
{
|
||||||
return level == Optimization_Normal;
|
return level == Optimization_Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
OptimizationLevel
|
OptimizationLevel
|
||||||
OptimizationInfos::levelForUseCount(uint32_t useCount)
|
OptimizationInfos::levelForScript(JSScript *script, jsbytecode *pc) const
|
||||||
{
|
{
|
||||||
OptimizationLevel prev = Optimization_DontCompile;
|
OptimizationLevel prev = Optimization_DontCompile;
|
||||||
|
|
||||||
while (!isLastLevel(prev)) {
|
while (!isLastLevel(prev)) {
|
||||||
OptimizationLevel level = nextLevel(prev);
|
OptimizationLevel level = nextLevel(prev);
|
||||||
const OptimizationInfo *info = get(level);
|
const OptimizationInfo *info = get(level);
|
||||||
if (useCount < info->usesBeforeCompile())
|
if (script->getUseCount() < info->usesBeforeCompile(script, pc))
|
||||||
return prev;
|
return prev;
|
||||||
|
|
||||||
prev = level;
|
prev = level;
|
||||||
|
@ -106,11 +106,7 @@ class OptimizationInfo
|
|||||||
return inlineNative_ && !js_JitOptions.disableInlining;
|
return inlineNative_ && !js_JitOptions.disableInlining;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t usesBeforeCompile() const {
|
uint32_t usesBeforeCompile(JSScript *script, jsbytecode *pc = nullptr) const;
|
||||||
if (js_JitOptions.forceDefaultIonUsesBeforeCompile)
|
|
||||||
return js_JitOptions.forcedDefaultIonUsesBeforeCompile;
|
|
||||||
return usesBeforeCompile_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool gvnEnabled() const {
|
bool gvnEnabled() const {
|
||||||
return gvn_ && !js_JitOptions.disableGvn;
|
return gvn_ && !js_JitOptions.disableGvn;
|
||||||
@ -171,7 +167,10 @@ class OptimizationInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t usesBeforeInlining() const {
|
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:
|
public:
|
||||||
OptimizationInfos();
|
OptimizationInfos();
|
||||||
|
|
||||||
const OptimizationInfo *get(OptimizationLevel level) {
|
const OptimizationInfo *get(OptimizationLevel level) const {
|
||||||
JS_ASSERT(level < Optimization_Count);
|
JS_ASSERT(level < Optimization_Count);
|
||||||
JS_ASSERT(level != Optimization_DontCompile);
|
JS_ASSERT(level != Optimization_DontCompile);
|
||||||
|
|
||||||
return &infos_[level - 1];
|
return &infos_[level - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
OptimizationLevel nextLevel(OptimizationLevel level);
|
OptimizationLevel nextLevel(OptimizationLevel level) const;
|
||||||
bool isLastLevel(OptimizationLevel level);
|
OptimizationLevel firstLevel() const;
|
||||||
OptimizationLevel levelForUseCount(uint32_t useCount);
|
bool isLastLevel(OptimizationLevel level) const;
|
||||||
|
OptimizationLevel levelForScript(JSScript *script, jsbytecode *pc = nullptr) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern OptimizationInfos js_IonOptimizations;
|
extern OptimizationInfos js_IonOptimizations;
|
||||||
|
@ -15,6 +15,17 @@
|
|||||||
namespace js {
|
namespace js {
|
||||||
namespace jit {
|
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.
|
// Possible register allocators which may be used.
|
||||||
enum IonRegisterAllocator {
|
enum IonRegisterAllocator {
|
||||||
RegisterAllocator_LSRA,
|
RegisterAllocator_LSRA,
|
||||||
|
Loading…
Reference in New Issue
Block a user