[INFER] Wait for code to get hot before inlining calls, bug 639099.

This commit is contained in:
Brian Hackett 2011-03-27 07:48:03 -07:00
Родитель 8d02c12c24
Коммит 7daf01913b
11 изменённых файлов: 92 добавлений и 5 удалений

Просмотреть файл

@ -445,6 +445,12 @@ Script::analyze(JSContext *cx, JSScript *script)
usesThis = true;
break;
case JSOP_CALL:
case JSOP_NEW:
/* Only consider potentially inlineable calls here. */
hasCalls = true;
break;
case JSOP_TABLESWITCH:
case JSOP_TABLESWITCHX: {
isInlineable = false;

Просмотреть файл

@ -140,6 +140,7 @@ class Script
bool usesRval;
bool usesScope;
bool usesThis;
bool hasCalls;
bool isInlineable;
@ -165,8 +166,8 @@ class Script
/* Whether there are NAME bytecodes which can access the frame's scope chain. */
bool usesScopeChain() const { return usesScope; }
/* Whether there are THIS bytecodes. */
bool usesThisValue() const { return usesThis; }
bool hasFunctionCalls() const { return hasCalls; }
bool hasAnalyzed() const { return !!codeArray; }
JSScript *getScript() const { return script; }

Просмотреть файл

@ -1333,7 +1333,7 @@ JS_PUBLIC_API(JSStackFrame *)
JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
{
if (*iteratorp == NULL)
*iteratorp = js_GetTopStackFrame(cx, FRAME_EXPAND_ALL);
*iteratorp = js_GetTopStackFrame(cx, FRAME_EXPAND_NONE);
else
*iteratorp = (*iteratorp)->prev();
return *iteratorp;

Просмотреть файл

@ -2886,9 +2886,15 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
JSObject *clone;
if (cx->compartment == fun->compartment()) {
/* Don't clone functions with singleton types. JIT optimizations depend on this. */
/*
* Don't clone functions with singleton types, we need to ensure that
* there is only one object with this type. We may need to reparent the
* function, however.
*/
if (fun->getType()->singleton) {
JS_ASSERT(fun->getType()->singleton == fun);
JS_ASSERT(fun->getProto() == proto);
fun->setParent(parent);
return fun;
}

Просмотреть файл

@ -619,6 +619,7 @@ struct JSScript {
size_t callCount() const { return callCount_; }
size_t incCallCount() { return ++callCount_; }
size_t *addressOfCallCount() { return &callCount_; }
JITScriptStatus getJITStatus(bool constructing) {
void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal;

Просмотреть файл

@ -83,6 +83,12 @@ static const char *OpcodeNames[] = {
};
#endif
/*
* Number of times a script must be called or had a backedge before we try to
* inline its calls.
*/
static const size_t CALLS_BACKEDGES_BEFORE_INLINING = 10000;
mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp,
const Vector<PatchableFrame> *patchFrames, bool recompiling)
: BaseCompiler(cx),
@ -122,12 +128,22 @@ mjit::Compiler::Compiler(JSContext *cx, JSStackFrame *fp,
addTraceHints(false),
#endif
recompiling(recompiling),
inlining(false),
oomInVector(false),
applyTricks(NoApplyTricks)
{
/* :FIXME: bug 637856 disabling traceJit if inference is enabled */
if (cx->typeInferenceEnabled())
addTraceHints = false;
/*
* Note: we use callCount_ to count both calls and backedges in scripts
* after they have been compiled and we are checking to recompile a version
* with inline calls. :FIXME: should remove compartment->incBackEdgeCount
* and do the same when deciding to initially compile.
*/
if (outerScript->callCount() >= CALLS_BACKEDGES_BEFORE_INLINING)
inlining = true;
}
CompileStatus
@ -270,6 +286,11 @@ mjit::Compiler::performCompilation(JITScript **jitp)
JaegerSpew(JSpew_Scripts, "compiling script (file \"%s\") (line \"%d\") (length \"%d\")\n",
outerScript->filename, outerScript->lineno, outerScript->length);
if (inlining) {
JaegerSpew(JSpew_Inlining, "inlining calls in script (file \"%s\") (line \"%d\")\n",
outerScript->filename, outerScript->lineno);
}
#ifdef JS_METHODJIT_SPEW
Profiler prof;
prof.start();
@ -587,6 +608,8 @@ mjit::Compiler::generatePrologue()
}
}
recompileCheckHelper();
return Compile_Okay;
}
@ -1837,7 +1860,7 @@ mjit::Compiler::generateMethod()
else if (status != Compile_InlineAbort)
return status;
}
if (!done) {
if (!done && inlining) {
CompileStatus status = inlineScriptedFunction(GET_ARGC(PC), false);
if (status == Compile_Okay)
done = true;
@ -2471,8 +2494,10 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_TRACE)
BEGIN_CASE(JSOP_NOTRACE)
{
if (a->analysis.jumpTarget(PC))
if (a->analysis.jumpTarget(PC)) {
interruptCheckHelper();
recompileCheckHelper();
}
}
END_CASE(JSOP_TRACE)
@ -2908,6 +2933,30 @@ mjit::Compiler::interruptCheckHelper()
stubcc.rejoin(Changes(0));
}
void
mjit::Compiler::recompileCheckHelper()
{
if (!a->analysis.hasFunctionCalls() || !cx->typeInferenceEnabled())
return;
if (inlining) {
OOL_STUBCALL(stubs::RecompileForInline);
stubcc.rejoin(Changes(0));
return;
}
JS_ASSERT(script->callCount() < CALLS_BACKEDGES_BEFORE_INLINING);
size_t *addr = script->addressOfCallCount();
masm.add32(Imm32(1), AbsoluteAddress(addr));
Jump jump = masm.branch32(Assembler::GreaterThanOrEqual, AbsoluteAddress(addr),
Imm32(CALLS_BACKEDGES_BEFORE_INLINING));
stubcc.linkExit(jump, Uses(0));
OOL_STUBCALL(stubs::RecompileForInline);
stubcc.rejoin(Changes(0));
}
void
mjit::Compiler::addReturnSite(Label joinPoint, bool ool)
{
@ -3433,6 +3482,8 @@ mjit::Compiler::inlineCallHelper(uint32 callImmArgc, bool callingNew)
CompileStatus
mjit::Compiler::inlineScriptedFunction(uint32 argc, bool callingNew)
{
JS_ASSERT(inlining);
if (!cx->typeInferenceEnabled())
return Compile_InlineAbort;
@ -3520,6 +3571,9 @@ mjit::Compiler::inlineScriptedFunction(uint32 argc, bool callingNew)
return Compile_InlineAbort;
}
JaegerSpew(JSpew_Inlining, "inlining call to script (file \"%s\") (line \"%d\")\n",
script->filename, script->lineno);
a->needReturnValue = needReturnValue;
a->syncReturnValue = syncReturnValue;
a->returnValueDouble = returnType == JSVAL_TYPE_DOUBLE;
@ -3566,6 +3620,9 @@ mjit::Compiler::inlineScriptedFunction(uint32 argc, bool callingNew)
frame.addressOf(frame.peek(-1)));
stubcc.rejoin(Changes(1));
JaegerSpew(JSpew_Inlining, "finished inlining call to script (file \"%s\") (line \"%d\")\n",
script->filename, script->lineno);
return Compile_Okay;
}

Просмотреть файл

@ -439,6 +439,7 @@ class Compiler : public BaseCompiler
bool debugMode_;
bool addTraceHints;
bool recompiling;
bool inlining;
bool oomInVector; // True if we have OOM'd appending to a vector.
enum { NoApplyTricks, LazyArgsObj } applyTricks;
@ -552,6 +553,7 @@ class Compiler : public BaseCompiler
void emitInlineReturnValue(FrameEntry *fe);
void dispatchCall(VoidPtrStubUInt32 stub, uint32 argc);
void interruptCheckHelper();
void recompileCheckHelper();
void emitUncachedCall(uint32 argc, bool callingNew);
void checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedArgc,
FrameEntry *origCallee, FrameEntry *origThis,

Просмотреть файл

@ -86,6 +86,7 @@ js::JMCheckLogging()
" pics PIC patching activity\n"
" slowcalls Calls to slow path functions\n"
" regalloc Register allocation behavior\n"
" inlin Call inlining behavior\n"
" recompile Dynamic recompilations\n"
" full everything\n"
" notrace disable trace hints\n"
@ -116,6 +117,8 @@ js::JMCheckLogging()
LoggingBits |= (1 << uint32(JSpew_Regalloc));
if (strstr(env, "recompile"))
LoggingBits |= (1 << uint32(JSpew_Recompile));
if (strstr(env, "inlin"))
LoggingBits |= (1 << uint32(JSpew_Inlining));
if (strstr(env, "full"))
LoggingBits |= 0xFFFFFFFF;
}

Просмотреть файл

@ -58,6 +58,7 @@ namespace js {
_(PICs) \
_(SlowCalls) \
_(Regalloc) \
_(Inlining) \
_(Recompile)
enum JaegerSpewChannel {

Просмотреть файл

@ -52,6 +52,7 @@
#include "jstypes.h"
#include "methodjit/Compiler.h"
#include "methodjit/StubCalls.h"
#include "methodjit/Retcon.h"
#include "jsinterpinlines.h"
#include "jspropertycache.h"
@ -1300,6 +1301,14 @@ stubs::Interrupt(VMFrame &f, jsbytecode *pc)
THROW();
}
void JS_FASTCALL
stubs::RecompileForInline(VMFrame &f)
{
Recompiler recompiler(f.cx, f.script());
if (!recompiler.recompile())
THROW();
}
void JS_FASTCALL
stubs::Trap(VMFrame &f, uint32 trapTypes)
{

Просмотреть файл

@ -59,6 +59,7 @@ JSObject * JS_FASTCALL NewInitObject(VMFrame &f, JSObject *base);
void JS_FASTCALL Trap(VMFrame &f, uint32 trapTypes);
void JS_FASTCALL Debugger(VMFrame &f, jsbytecode *pc);
void JS_FASTCALL Interrupt(VMFrame &f, jsbytecode *pc);
void JS_FASTCALL RecompileForInline(VMFrame &f);
void JS_FASTCALL InitElem(VMFrame &f, uint32 last);
void JS_FASTCALL InitProp(VMFrame &f, JSAtom *atom);
void JS_FASTCALL InitMethod(VMFrame &f, JSAtom *atom);