author | Brian Hackett <bhackett1024@gmail.com> |
Mon, 09 May 2011 15:11:32 -0700 | |
changeset 75008 | 32e8c937a40944a7c2666dd07839e304d9075eb2 |
parent 75007 | cb9c34a8b2b47b0c66f7431844eecc26aaf6d1cf |
child 75009 | 49c7baf9872c7ef3d25859f7aaa964f1930e63a3 |
child 75012 | d1724a9944bd0454772837e72ed938fab739195e |
push id | 1199 |
push user | jorendorff@mozilla.com |
push date | Sat, 13 Aug 2011 18:32:33 +0000 |
treeherder | mozilla-inbound@080fece621e4 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 650163 |
milestone | 6.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -141,19 +141,16 @@ JSCompartment::init(JSContext *cx) #endif #if ENABLE_YARR_JIT regExpAllocator = rt->new_<JSC::ExecutableAllocator>(); if (!regExpAllocator) return false; #endif - if (!backEdgeTable.init()) - return false; - #ifdef JS_METHODJIT if (!(jaegerCompartment = rt->new_<mjit::JaegerCompartment>())) return false; return jaegerCompartment->Initialize(); #else return true; #endif } @@ -647,26 +644,8 @@ MathCache * JSCompartment::allocMathCache(JSContext *cx) { JS_ASSERT(!mathCache); mathCache = cx->new_<MathCache>(); if (!mathCache) 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. */ -} -
--- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -504,31 +504,21 @@ struct JS_FRIEND_API(JSCompartment) { js::DtoaCache dtoaCache; private: js::MathCache *mathCache; 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) #define JS_PROPERTY_TREE(cx) ((cx)->compartment->propertyTree) #ifdef DEBUG #define JS_COMPARTMENT_METER(x) x #else
--- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -1963,44 +1963,16 @@ TypeCompartment::dynamicPush(JSContext * * parent has constraints listening to type changes in this one (it won't * necessarily, if we have condensed the constraints but not reanalyzed the * parent). The parent is listening for isUninlineable changes on the * function, so we can treat this as a state change on the function to * trigger any necessary reanalysis. */ 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 TypeCompartment::processPendingRecompiles(JSContext *cx) { /* Steal the list of scripts to recompile, else we will try to recursively recompile them. */ Vector<JSScript*> *pending = pendingRecompiles; pendingRecompiles = NULL;
--- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -416,19 +416,21 @@ struct JSScript { static JSScript *NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg); /* FIXME: bug 586181 */ JSCList links; /* Links for compartment script list */ jsbytecode *code; /* bytecodes and their immediate operands */ 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 slot array */ /* * Offsets to various array structures from the end of this script, or * JSScript::INVALID_OFFSET if the array has length 0. @@ -628,19 +630,20 @@ struct JSScript { inline void **nativeMap(bool constructing); inline void *maybeNativeCodeForPC(bool constructing, jsbytecode *pc); inline void *nativeCodeForPC(bool constructing, jsbytecode *pc); js::mjit::JITScript *getJIT(bool constructing) { 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; if (addr == NULL) return JITScript_None; if (addr == JS_UNJITTABLE_SCRIPT) return JITScript_Invalid; return JITScript_Valid;
--- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -83,17 +83,17 @@ static const char *OpcodeNames[] = { # undef OPDEF }; #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; +static const size_t USES_BEFORE_INLINING = 10000; mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructing) : BaseCompiler(cx), outerScript(outerScript), isConstructing(isConstructing), ssa(cx, outerScript), globalObj(outerScript->global), globalSlots((globalObj && globalObj->isGlobal()) ? globalObj->getRawSlots() : NULL), @@ -133,24 +133,19 @@ mjit::Compiler::Compiler(JSContext *cx, applyTricks(NoApplyTricks) { JS_ASSERT(!outerScript->isUncachedEval); /* :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. - */ + /* 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; } } CompileStatus mjit::Compiler::compile() { @@ -1116,19 +1111,18 @@ mjit::Compiler::finishThisUp(JITScript * jitTraceICs[i].jumpTargetPC = traceICs[i].jumpTarget; #endif jitTraceICs[i].hasSlowTraceHint = traceICs[i].slowTraceHint.isSet(); if (traceICs[i].slowTraceHint.isSet()) 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]); } #endif /* JS_MONOIC */ for (size_t i = 0; i < callPatches.length(); i++) { CallPatchInfo &patch = callPatches[i]; @@ -3124,27 +3118,27 @@ mjit::Compiler::interruptCheckHelper() } void 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)); stubcc.leave(); OOL_STUBCALL(stubs::RecompileForInline, REJOIN_RESUME); stubcc.rejoin(Changes(0)); }
--- a/js/src/methodjit/MethodJIT-inl.h +++ b/js/src/methodjit/MethodJIT-inl.h @@ -45,34 +45,34 @@ namespace js { namespace mjit { enum CompileRequest { CompileRequest_Interpreter, 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) { if (!cx->methodJitEnabled) return Compile_Abort; JITScriptStatus status = script->getJITStatus(fp->isConstructing()); if (status == JITScript_Invalid) return Compile_Abort; 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; } if (status == JITScript_None) return TryCompile(cx, fp); return Compile_Okay; } @@ -85,17 +85,17 @@ CanMethodJITAtBranch(JSContext *cx, JSSc { if (!cx->methodJitEnabled) return Compile_Abort; JITScriptStatus status = script->getJITStatus(fp->isConstructing()); if (status == JITScript_Invalid) 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; } if (status == JITScript_None) return TryCompile(cx, fp); return Compile_Okay; }
--- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -713,16 +713,19 @@ extern "C" { pop edi; pop esi; pop ebp; xor eax, eax ret; } } + 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. */ push esp; push eax; push edi; push esi; call js_InternalInterpret;
--- a/js/src/methodjit/Retcon.cpp +++ b/js/src/methodjit/Retcon.cpp @@ -47,16 +47,18 @@ #include "jsdbgapi.h" #include "jsnum.h" #include "assembler/assembler/LinkBuffer.h" #include "assembler/assembler/RepatchBuffer.h" #include "jscntxtinlines.h" #include "jsinterpinlines.h" +#include "MethodJIT-inl.h" + using namespace js; using namespace js::mjit; namespace js { namespace mjit { AutoScriptRetrapper::~AutoScriptRetrapper() { @@ -320,17 +322,17 @@ Recompiler::Recompiler(JSContext *cx, JS * - For VMFrames with a stub call return address in the original script, * redirect to the interpoline. * * - For VMFrames whose entryncode address (the value of entryfp->ncode before * being clobbered with JaegerTrampolineReturn) is in the original script, * redirect that entryncode to the interpoline. */ void -Recompiler::recompile() +Recompiler::recompile(bool resetUses) { JS_ASSERT(script->hasJITCode()); JaegerSpew(JSpew_Recompile, "recompiling script (file \"%s\") (line \"%d\") (length \"%d\")\n", script->filename, script->lineno, script->length); types::AutoEnterTypeInference enter(cx, true); @@ -413,16 +415,24 @@ Recompiler::recompile() cleanup(script->jitNormal); ReleaseScriptCode(cx, script, true); } if (script->jitCtor) { cleanup(script->jitCtor); 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++; } void Recompiler::cleanup(JITScript *jit) { while (!JS_CLIST_IS_EMPTY(&jit->callers)) { JaegerSpew(JSpew_Recompile, "Purging IC caller\n");
--- a/js/src/methodjit/Retcon.h +++ b/js/src/methodjit/Retcon.h @@ -81,17 +81,17 @@ class AutoScriptRetrapper * ever change the code associated with a JSScript, or otherwise would cause * existing JITed code to be incorrect, you /must/ use this to invalidate the * JITed code, fixing up the stack in the process. */ 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, StackFrame *next, VMFrame *f); private: JSContext *cx; JSScript *script;
--- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -1297,17 +1297,17 @@ stubs::Interrupt(VMFrame &f, jsbytecode THROW(); } void JS_FASTCALL stubs::RecompileForInline(VMFrame &f) { ExpandInlineFrames(f.cx, true); Recompiler recompiler(f.cx, f.script()); - recompiler.recompile(); + recompiler.recompile(/* resetUses */ false); } void JS_FASTCALL stubs::Trap(VMFrame &f, uint32 trapTypes) { Value rval; /*