зеркало из https://github.com/mozilla/gecko-dev.git
[INFER] Wait for code to get hot before inlining calls, bug 639099.
This commit is contained in:
Родитель
8d02c12c24
Коммит
7daf01913b
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче