Bug 783008 - Use better heuristics for recompile checks from JM on behalf of Ion. (r=dvander)

This commit is contained in:
Kannan Vijayan 2012-08-20 16:31:53 -04:00
parent f41cc9da17
commit f5fbf900f3
7 changed files with 75 additions and 12 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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