mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 783008 - Use better heuristics for recompile checks from JM on behalf of Ion. (r=dvander)
This commit is contained in:
parent
f41cc9da17
commit
f5fbf900f3
@ -262,8 +262,8 @@ IonBuilder::build()
|
||||
if (!current)
|
||||
return false;
|
||||
|
||||
IonSpew(IonSpew_Scripts, "Analyzing script %s:%d (%p)",
|
||||
script->filename, script->lineno, (void *) script);
|
||||
IonSpew(IonSpew_Scripts, "Analyzing script %s:%d (%p) (usecount=%d) (maxloopcount=%d)",
|
||||
script->filename, script->lineno, (void *) script, (int) script->getUseCount(), (int) script->getMaxLoopCount());
|
||||
|
||||
if (!initParameters())
|
||||
return false;
|
||||
|
@ -1232,6 +1232,9 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
Rooted<JSScript*> script(cx);
|
||||
SET_SCRIPT(regs.fp()->script());
|
||||
|
||||
/* Reset the loop count on the script we're entering. */
|
||||
script->resetLoopCount();
|
||||
|
||||
#if JS_TRACE_LOGGING
|
||||
AutoTraceLog logger(TraceLogging::defaultLogger(),
|
||||
TraceLogging::INTERPRETER_START,
|
||||
@ -1458,9 +1461,14 @@ ADD_EMPTY_CASE(JSOP_TRY)
|
||||
ADD_EMPTY_CASE(JSOP_STARTXML)
|
||||
ADD_EMPTY_CASE(JSOP_STARTXMLEXPR)
|
||||
#endif
|
||||
ADD_EMPTY_CASE(JSOP_LOOPHEAD)
|
||||
END_EMPTY_CASES
|
||||
|
||||
BEGIN_CASE(JSOP_LOOPHEAD)
|
||||
|
||||
script->incrLoopCount();
|
||||
|
||||
END_CASE(JSOP_LOOPHEAD)
|
||||
|
||||
BEGIN_CASE(JSOP_LABEL)
|
||||
END_CASE(JSOP_LABEL)
|
||||
|
||||
@ -2486,6 +2494,7 @@ BEGIN_CASE(JSOP_FUNCALL)
|
||||
goto error;
|
||||
|
||||
SET_SCRIPT(regs.fp()->script());
|
||||
script->resetLoopCount();
|
||||
|
||||
#ifdef JS_ION
|
||||
if (!newType && ion::IsEnabled(cx)) {
|
||||
|
@ -1716,6 +1716,15 @@ JSScript::numNotes()
|
||||
return sn - notes_ + 1; /* +1 for the terminator */
|
||||
}
|
||||
|
||||
bool
|
||||
JSScript::isShortRunning()
|
||||
{
|
||||
return length < 100 &&
|
||||
hasAnalysis() &&
|
||||
!analysis()->hasFunctionCalls() &&
|
||||
getMaxLoopCount() < 40;
|
||||
}
|
||||
|
||||
bool
|
||||
JSScript::enclosingScriptsCompiledSuccessfully() const
|
||||
{
|
||||
|
@ -387,6 +387,10 @@ struct JSScript : public js::gc::Cell
|
||||
* or has had backedges taken. Reset if the
|
||||
* script's JIT code is forcibly discarded. */
|
||||
|
||||
uint32_t maxLoopCount; /* Maximum loop count that has been encountered. */
|
||||
uint32_t loopCount; /* Number of times a LOOPHEAD has been encountered.
|
||||
after a LOOPENTRY. Modified only by interpreter. */
|
||||
|
||||
#ifdef DEBUG
|
||||
// Unique identifier within the compartment for this script, used for
|
||||
// printing analysis information.
|
||||
@ -588,6 +592,9 @@ struct JSScript : public js::gc::Cell
|
||||
inline void clearAnalysis();
|
||||
inline js::analyze::ScriptAnalysis *analysis();
|
||||
|
||||
/* Heuristic to check if the function is expected to be "short running". */
|
||||
bool isShortRunning();
|
||||
|
||||
inline bool hasGlobal() const;
|
||||
inline bool hasClearedGlobal() const;
|
||||
|
||||
@ -656,6 +663,22 @@ struct JSScript : public js::gc::Cell
|
||||
uint32_t *addressOfUseCount() { return &useCount; }
|
||||
void resetUseCount() { useCount = 0; }
|
||||
|
||||
void resetLoopCount() {
|
||||
if (loopCount > maxLoopCount)
|
||||
maxLoopCount = loopCount;
|
||||
loopCount = 0;
|
||||
}
|
||||
|
||||
void incrLoopCount() {
|
||||
++loopCount;
|
||||
}
|
||||
|
||||
uint32_t getMaxLoopCount() {
|
||||
if (loopCount > maxLoopCount)
|
||||
maxLoopCount = loopCount;
|
||||
return maxLoopCount;
|
||||
}
|
||||
|
||||
/*
|
||||
* Size of the JITScript and all sections. If |mallocSizeOf| is NULL, the
|
||||
* size is computed analytically. (This method is implemented in
|
||||
|
@ -502,8 +502,8 @@ CompileStatus
|
||||
mjit::Compiler::performCompilation()
|
||||
{
|
||||
JaegerSpew(JSpew_Scripts,
|
||||
"compiling script (file \"%s\") (line \"%d\") (length \"%d\") (chunk \"%d\")\n",
|
||||
outerScript->filename, outerScript->lineno, outerScript->length, chunkIndex);
|
||||
"compiling script (file \"%s\") (line \"%d\") (length \"%d\") (chunk \"%d\") (usecount \"%d\")\n",
|
||||
outerScript->filename, outerScript->lineno, outerScript->length, chunkIndex, (int) outerScript->getUseCount());
|
||||
|
||||
if (inlining()) {
|
||||
JaegerSpew(JSpew_Inlining,
|
||||
@ -3950,13 +3950,22 @@ mjit::Compiler::interruptCheckHelper()
|
||||
}
|
||||
|
||||
static bool
|
||||
MaybeIonCompileable(JSContext *cx, JSScript *script)
|
||||
MaybeIonCompileable(JSContext *cx, JSScript *script, bool *recompileCheckForIon)
|
||||
{
|
||||
#ifdef JS_ION
|
||||
*recompileCheckForIon = true;
|
||||
|
||||
if (!ion::IsEnabled(cx))
|
||||
return false;
|
||||
if (!script->canIonCompile())
|
||||
return false;
|
||||
|
||||
// If this script is small, doesn't have any function calls, and doesn't have
|
||||
// any big loops, then throwing in a recompile check and causing an invalidation
|
||||
// when we otherwise wouldn't have would be wasteful.
|
||||
if (script->isShortRunning())
|
||||
*recompileCheckForIon = false;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
@ -3968,23 +3977,33 @@ mjit::Compiler::recompileCheckHelper()
|
||||
if (inlining() || debugMode() || !globalObj || !cx->typeInferenceEnabled())
|
||||
return;
|
||||
|
||||
bool maybeIonCompileable = MaybeIonCompileable(cx, outerScript);
|
||||
bool recompileCheckForIon = true;
|
||||
bool maybeIonCompileable = MaybeIonCompileable(cx, outerScript, &recompileCheckForIon);
|
||||
bool hasFunctionCalls = analysis->hasFunctionCalls();
|
||||
|
||||
// Insert a recompile check if either:
|
||||
// 1) IonMonkey is enabled, to optimize the function when it becomes hot.
|
||||
// 2) The script contains function calls JM can inline.
|
||||
if (!maybeIonCompileable && !analysis->hasFunctionCalls())
|
||||
if (!maybeIonCompileable && !hasFunctionCalls)
|
||||
return;
|
||||
|
||||
uint32_t minUses = USES_BEFORE_INLINING;
|
||||
|
||||
#ifdef JS_ION
|
||||
if (maybeIonCompileable)
|
||||
if (recompileCheckForIon)
|
||||
minUses = ion::UsesBeforeIonRecompile(outerScript, PC);
|
||||
#endif
|
||||
|
||||
uint32_t *addr = script->addressOfUseCount();
|
||||
masm.add32(Imm32(1), AbsoluteAddress(addr));
|
||||
|
||||
// If there are no function calls, and we don't want to do a recompileCheck for
|
||||
// Ion, then this just needs to increment the useCount so that we know when to
|
||||
// recompile this function from an Ion call. No need to call out to recompiler
|
||||
// stub.
|
||||
if (!hasFunctionCalls && !recompileCheckForIon)
|
||||
return;
|
||||
|
||||
#if defined(JS_CPU_X86) || defined(JS_CPU_ARM)
|
||||
Jump jump = masm.branch32(Assembler::GreaterThanOrEqual, AbsoluteAddress(addr),
|
||||
Imm32(minUses));
|
||||
|
@ -259,7 +259,10 @@ ShouldJaegerCompileCallee(JSContext *cx, JSScript *caller, JSScript *callee, JIT
|
||||
|
||||
// Use JM if the callee has no loops. In this case calling into Ion
|
||||
// is likely not worth the overhead.
|
||||
if (!callee->hasAnalysis() || !callee->analysis()->hasLoops())
|
||||
if (!callee->hasAnalysis())
|
||||
return true;
|
||||
|
||||
if (callee->isShortRunning())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -396,8 +396,8 @@ Recompiler::clearStackReferences(FreeOp *fop, JSScript *script)
|
||||
{
|
||||
JS_ASSERT(script->hasMJITInfo());
|
||||
|
||||
JaegerSpew(JSpew_Recompile, "recompiling script (file \"%s\") (line \"%d\") (length \"%d\")\n",
|
||||
script->filename, script->lineno, script->length);
|
||||
JaegerSpew(JSpew_Recompile, "recompiling script (file \"%s\") (line \"%d\") (length \"%d\") (usecount=\"%d\")\n",
|
||||
script->filename, script->lineno, script->length, (int) script->getUseCount());
|
||||
|
||||
JSCompartment *comp = script->compartment();
|
||||
types::AutoEnterTypeInference enter(fop, comp);
|
||||
|
Loading…
Reference in New Issue
Block a user