[INFER] Reset use count when recompiling, bug 650163.

This commit is contained in:
Brian Hackett 2011-05-09 15:11:32 -07:00
parent 42a0a50b2d
commit 769796394d
10 changed files with 38 additions and 87 deletions

View File

@ -146,9 +146,6 @@ JSCompartment::init(JSContext *cx)
return false;
#endif
if (!backEdgeTable.init())
return false;
#ifdef JS_METHODJIT
if (!(jaegerCompartment = rt->new_<mjit::JaegerCompartment>()))
return false;
@ -652,21 +649,3 @@ JSCompartment::allocMathCache(JSContext *cx)
js_ReportOutOfMemory(cx);
return mathCache;
}
size_t
JSCompartment::backEdgeCount(jsbytecode *pc) const
{
if (BackEdgeMap::Ptr p = backEdgeTable.lookup(pc))
return p->value;
return 0;
}
size_t
JSCompartment::incBackEdgeCount(jsbytecode *pc)
{
if (BackEdgeMap::Ptr p = backEdgeTable.lookupWithDefault(pc, 0))
return ++p->value;
return 1; /* oom not reported by backEdgeTable, so ignore. */
}

View File

@ -509,21 +509,11 @@ struct JS_FRIEND_API(JSCompartment) {
js::MathCache *allocMathCache(JSContext *cx);
typedef js::HashMap<jsbytecode*,
size_t,
js::DefaultHasher<jsbytecode*>,
js::SystemAllocPolicy> BackEdgeMap;
BackEdgeMap backEdgeTable;
JSCompartment *thisForCtor() { return this; }
public:
js::MathCache *getMathCache(JSContext *cx) {
return mathCache ? mathCache : allocMathCache(cx);
}
size_t backEdgeCount(jsbytecode *pc) const;
size_t incBackEdgeCount(jsbytecode *pc);
};
#define JS_SCRIPTS_TO_GC(cx) ((cx)->compartment->scriptsToGC)

View File

@ -1968,34 +1968,6 @@ TypeCompartment::dynamicPush(JSContext *cx, JSScript *script, uint32 offset, jst
*/
if (script->fun && !script->fun->getType()->unknownProperties())
ObjectStateChange(cx, script->fun->getType(), false);
/*
* If we unexpectedly read a hole out of an array, mark all array reads in
* the script as undefined. :FIXME: bug 650163 remove hack.
*/
if (script->hasAnalysis() && script->analysis(cx)->ranInference() &&
JSOp(*pc) == JSOP_GETELEM && type == TYPE_UNDEFINED) {
analyze::ScriptAnalysis *analysis = script->analysis(cx);
unsigned offset = 0;
while (offset < script->length) {
if (JSOp(script->code[offset]) == JSOP_GETELEM && analysis->maybeCode(offset)) {
TypeSet *pushed = analysis->pushedTypes(offset, 0);
if (!pushed->hasType(TYPE_UNDEFINED)) {
pushed->addType(cx, TYPE_UNDEFINED);
TypeResult *result = (TypeResult *) cx->calloc_(sizeof(TypeResult));
if (!result) {
setPendingNukeTypes(cx);
return;
}
result->offset = offset;
result->type = TYPE_UNDEFINED;
result->next = script->typeResults;
script->typeResults = result;
}
}
offset += analyze::GetBytecodeLength(pc);
}
}
}
void

View File

@ -421,9 +421,11 @@ struct JSScript {
uint32 length; /* length of code vector */
private:
uint16 version; /* JS version under which script was compiled */
size_t useCount_; /* Number of times the script has been called
* or has had backedges taken. Reset if the
* script's JIT code is forcibly discarded. */
size_t callCount_; /* Number of times the script has been called. */
uint16 version; /* JS version under which script was compiled */
public:
uint16 nfixed; /* number of slots besides stack operands in
@ -633,9 +635,10 @@ struct JSScript {
return constructing ? jitCtor : jitNormal;
}
size_t callCount() const { return callCount_; }
size_t incCallCount() { return ++callCount_; }
size_t *addressOfCallCount() { return &callCount_; }
size_t useCount() const { return useCount_; }
size_t incUseCount() { return ++useCount_; }
size_t *addressOfUseCount() { return &useCount_; }
void resetUseCount() { useCount_ = 0; }
JITScriptStatus getJITStatus(bool constructing) {
void *addr = constructing ? jitArityCheckCtor : jitArityCheckNormal;

View File

@ -88,7 +88,7 @@ static const char *OpcodeNames[] = {
* 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;
static const size_t USES_BEFORE_INLINING = 10000;
mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructing)
: BaseCompiler(cx),
@ -138,14 +138,9 @@ mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructi
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.
*/
/* Once a script starts getting really hot we will inline calls in it. */
if (!debugMode() && cx->typeInferenceEnabled() &&
(outerScript->callCount() >= CALLS_BACKEDGES_BEFORE_INLINING ||
(outerScript->useCount() >= USES_BEFORE_INLINING ||
cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS))) {
inlining_ = true;
}
@ -1121,9 +1116,8 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
jitTraceICs[i].slowTraceHint = stubCode.locationOf(traceICs[i].slowTraceHint.get());
#ifdef JS_TRACER
uint32 hotloop = GetHotloop(cx);
uint32 prevCount = cx->compartment->backEdgeCount(traceICs[i].jumpTarget);
jitTraceICs[i].loopCounterStart = hotloop;
jitTraceICs[i].loopCounter = hotloop < prevCount ? 1 : hotloop - prevCount;
jitTraceICs[i].loopCounter = hotloop;
#endif
stubCode.patch(traceICs[i].addrLabel, &jitTraceICs[i]);
@ -3129,17 +3123,17 @@ mjit::Compiler::recompileCheckHelper()
if (inlining() || debugMode() || !analysis->hasFunctionCalls() || !cx->typeInferenceEnabled())
return;
size_t *addr = script->addressOfCallCount();
size_t *addr = script->addressOfUseCount();
masm.add32(Imm32(1), AbsoluteAddress(addr));
#if defined(JS_CPU_X86) || defined(JS_CPU_ARM)
Jump jump = masm.branch32(Assembler::GreaterThanOrEqual, AbsoluteAddress(addr),
Imm32(CALLS_BACKEDGES_BEFORE_INLINING));
Imm32(USES_BEFORE_INLINING));
#else
/* Handle processors that can't load from absolute addresses. */
RegisterID reg = frame.allocReg();
masm.move(ImmPtr(addr), reg);
Jump jump = masm.branch32(Assembler::GreaterThanOrEqual, Address(reg, 0),
Imm32(CALLS_BACKEDGES_BEFORE_INLINING));
Imm32(USES_BEFORE_INLINING));
frame.freeReg(reg);
#endif
stubcc.linkExit(jump, Uses(0));

View File

@ -50,11 +50,11 @@ enum CompileRequest
CompileRequest_JIT
};
/* Number of times a script must be called before we run it in the methodjit. */
static const size_t CALLS_BEFORE_COMPILE = 16;
/* Number of loop back-edges we execute in the interpreter before methodjitting. */
static const size_t BACKEDGES_BEFORE_COMPILE = 16;
/*
* Number of times a script must be called or have back edges taken before we
* run it in the methodjit.
*/
static const size_t USES_BEFORE_COMPILE = 16;
static inline CompileStatus
CanMethodJIT(JSContext *cx, JSScript *script, StackFrame *fp, CompileRequest request)
@ -67,7 +67,7 @@ CanMethodJIT(JSContext *cx, JSScript *script, StackFrame *fp, CompileRequest req
if (request == CompileRequest_Interpreter &&
status == JITScript_None &&
!cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) &&
script->incCallCount() <= CALLS_BEFORE_COMPILE)
script->incUseCount() <= USES_BEFORE_COMPILE)
{
return Compile_Skipped;
}
@ -90,7 +90,7 @@ CanMethodJITAtBranch(JSContext *cx, JSScript *script, StackFrame *fp, jsbytecode
return Compile_Abort;
if (status == JITScript_None &&
!cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) &&
cx->compartment->incBackEdgeCount(pc) <= BACKEDGES_BEFORE_COMPILE)
script->incUseCount() <= USES_BEFORE_COMPILE)
{
return Compile_Skipped;
}

View File

@ -718,6 +718,9 @@ extern "C" {
}
}
extern "C" void *
js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VMFrame &f);
__declspec(naked) void JaegerInterpoline() {
__asm {
/* Align the stack to 16 bytes. */

View File

@ -52,6 +52,8 @@
#include "jscntxtinlines.h"
#include "jsinterpinlines.h"
#include "MethodJIT-inl.h"
using namespace js;
using namespace js::mjit;
@ -325,7 +327,7 @@ Recompiler::Recompiler(JSContext *cx, JSScript *script)
* redirect that entryncode to the interpoline.
*/
void
Recompiler::recompile()
Recompiler::recompile(bool resetUses)
{
JS_ASSERT(script->hasJITCode());
@ -418,6 +420,14 @@ Recompiler::recompile()
ReleaseScriptCode(cx, script, false);
}
if (resetUses) {
/*
* Wait for the script to get warm again before doing another compile,
* unless we are recompiling *because* the script got hot.
*/
script->resetUseCount();
}
cx->compartment->types.recompilations++;
}

View File

@ -86,7 +86,7 @@ class Recompiler {
public:
Recompiler(JSContext *cx, JSScript *script);
void recompile();
void recompile(bool resetUses = true);
static void
expandInlineFrames(JSContext *cx, StackFrame *fp, mjit::CallSite *inlined,

View File

@ -1302,7 +1302,7 @@ stubs::RecompileForInline(VMFrame &f)
{
ExpandInlineFrames(f.cx, true);
Recompiler recompiler(f.cx, f.script());
recompiler.recompile();
recompiler.recompile(/* resetUses */ false);
}
void JS_FASTCALL