author | Bill McCloskey <wmccloskey@mozilla.com> |
Tue, 26 Oct 2010 12:03:16 -0700 | |
changeset 56603 | 81fa7d0b8f00981f5fa0665d68e40211e67e2ab8 |
parent 56602 | ceec1a6b5566b5cae142c2bf13f7f6f87a58cea6 |
child 56604 | 94080153175cf2c571557195853074aed8f32811 |
push id | 16602 |
push user | rsayre@mozilla.com |
push date | Wed, 27 Oct 2010 01:10:03 +0000 |
treeherder | mozilla-central@7b83033bb6f8 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | dmandelin |
bugs | 606650 |
milestone | 2.0b8pre |
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
|
js/src/jstracer.cpp | file | annotate | diff | comparison | revisions | |
js/src/jstracer.h | file | annotate | diff | comparison | revisions |
--- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -16768,21 +16768,21 @@ LoopProfile::LoopProfile(JSScript *scrip bottom(bottom), hits(0), profiled(false), traceOK(false), numAllOps(0), numSelfOps(0), numSelfOpsMult(0), branchMultiplier(1), - prevOp(JSOP_LIMIT), shortLoop(false), maybeShortLoop(false), numInnerLoops(0), - loopStackDepth(0) + loopStackDepth(0), + sp(0) { memset(allOps, 0, sizeof(allOps)); memset(selfOps, 0, sizeof(selfOps)); } MonitorResult LoopProfile::profileLoopEdge(JSContext* cx, uintN& inlineCallCount) { @@ -16937,17 +16937,16 @@ PCWithinLoop(JSScript *script, jsbytecod { return script != loop.script || (pc >= loop.top && pc <= loop.bottom); } LoopProfile::ProfileAction LoopProfile::profileOperation(JSContext* cx, JSOp op) { TraceMonitor* tm = &JS_TRACE_MONITOR(cx); - JSOp prev = prevOp; if (profiled) { tm->profile = NULL; return ProfComplete; } jsbytecode *pc = cx->regs->pc; JSScript *script = cx->fp()->maybeScript(); @@ -17007,27 +17006,22 @@ LoopProfile::profileOperation(JSContext* } if (op == JSOP_EVAL) increment(OP_EVAL); if (op == JSOP_NEW) increment(OP_NEW); - if (op == JSOP_INT8) - prevConst = GET_INT8(cx->regs->pc); - if (op == JSOP_GETELEM || op == JSOP_SETELEM) { Value& lval = cx->regs->sp[op == JSOP_GETELEM ? -2 : -3]; if (lval.isObject() && js_IsTypedArray(&lval.toObject())) increment(OP_TYPED_ARRAY); } - prevOp = op; - if (op == JSOP_CALL) { increment(OP_CALL); uintN argc = GET_ARGC(cx->regs->pc); Value &v = cx->regs->sp[-((int)argc + 2)]; JSObject *callee; if (IsFunctionObject(v, &callee)) { JSFunction *fun = callee->getFunctionPrivate(); @@ -17058,42 +17052,70 @@ LoopProfile::profileOperation(JSContext* || op == JSOP_LE || op == JSOP_GE || op == JSOP_IN || op == JSOP_MOREITER) { const JSCodeSpec *cs = &js_CodeSpec[op]; ptrdiff_t oplen = cs->length; JSScript *script = cx->fp()->script(); JS_ASSERT(oplen != -1); if (cx->regs->pc - script->code + oplen < ptrdiff_t(script->length)) - testPC = cx->regs->pc + oplen; + if (cx->regs->pc[oplen] == JSOP_IFEQ || cx->regs->pc[oplen] == JSOP_IFNE) + testPC = cx->regs->pc + oplen; } /* Check if we're exiting the loop being profiled. */ JSOp testOp = js_GetOpcode(cx, cx->fp()->script(), testPC); if (testOp == JSOP_IFEQ || testOp == JSOP_IFNE || testOp == JSOP_GOTO || testOp == JSOP_AND || testOp == JSOP_OR) { ptrdiff_t len = GET_JUMP_OFFSET(testPC); - if (testPC + len == top && prev == JSOP_INT8 - && (op == JSOP_LT || op == JSOP_LE) && prevConst < 8) - { - shortLoop = true; - } + if (testPC + len == top && (op == JSOP_LT || op == JSOP_LE)) { + StackValue v = stackAt(-1); + if (v.hasValue && v.value < 8) + shortLoop = true; + } + if (testPC + len == top && (op == JSOP_LT || op == JSOP_LE) && cx->regs->sp[-2].isInt32() && cx->regs->sp[-2].toInt32() < 16) { maybeShortLoop = true; } + if (testOp != JSOP_GOTO && len > 0) { + bool isConst; + if (testOp == JSOP_IFEQ || testOp == JSOP_IFNE) + isConst = stackAt(-1).isConst && stackAt(-2).isConst; + else + isConst = stackAt(-1).isConst; + increment(OP_FWDJUMP); - if (loopStackDepth == 0) + if (loopStackDepth == 0 && !isConst) branchMultiplier *= 2; } } + if (op == JSOP_INT8) { + stackPush(StackValue(true, GET_INT8(cx->regs->pc))); + } else if (op == JSOP_STRING) { + stackPush(StackValue(true)); + } else if (op == JSOP_TYPEOF || op == JSOP_TYPEOFEXPR) { + stackPush(StackValue(true)); + } else if (op == JSOP_EQ || op == JSOP_NE) { + StackValue v1 = stackAt(-1); + StackValue v2 = stackAt(-2); + stackPush(StackValue(v1.isConst && v2.isConst)); + } else if (op == JSOP_AND) { + bool b = !!js_ValueToBoolean(cx->regs->sp[-1]); + StackValue v = stackAt(-1); + if (b) + stackPop(); + } else { + stackClear(); + } + return ProfContinue; } static LoopProfile * LookupLoopProfile(JSContext *cx, jsbytecode *pc) { TraceMonitor* tm = &JS_TRACE_MONITOR(cx); LoopProfileMap &table = *tm->loopProfiles; @@ -17201,17 +17223,17 @@ LoopProfile::decide(JSContext *cx) if (count(OP_RECURSIVE)) { /* don't trace */ } else if (count(OP_EVAL)) { /* don't trace */ } else if (numInnerLoops > 3) { /* don't trace */ } else if (shortLoop) { /* don't trace */ - } else if (maybeShortLoop) { + } else if (maybeShortLoop && numInnerLoops < 2) { /* don't trace */ } else if (isCompilationExpensive(cx, 4)) { /* don't trace */ } else if (isCompilationUnprofitable(cx, 4)) { /* don't trace */ } else { uintN goodOps = 0; @@ -17226,17 +17248,16 @@ LoopProfile::decide(JSContext *cx) debug_only_printf(LC_TMProfiler, "FEATURE goodOps %u\n", goodOps); if (goodOps >= numAllOps) traceOK = true; } debug_only_printf(LC_TMProfiler, "TRACE %s:%d = %d\n", script->filename, line, traceOK); - debug_only_print0(LC_TMProfiler, "\n"); if (traceOK) { /* Unblacklist the inner loops. */ for (uintN i=0; i<numInnerLoops; i++) { InnerLoop &loop = innerLoops[i]; LoopProfile *prof = LookupLoopProfile(cx, loop.top); if (prof) { /* @@ -17254,16 +17275,18 @@ LoopProfile::decide(JSContext *cx) } } if (!traceOK) { debug_only_printf(LC_TMProfiler, "Blacklisting at %d\n", line); Blacklist(top); } + debug_only_print0(LC_TMProfiler, "\n"); + execOK = traceOK; } JS_REQUIRES_STACK MonitorResult MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount) { TraceMonitor *tm = &JS_TRACE_MONITOR(cx); if (tm->profile)
--- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -662,16 +662,17 @@ VMFragment::toTreeFragment() enum MonitorResult { MONITOR_RECORDING, MONITOR_NOT_RECORDING, MONITOR_ERROR }; const uintN PROFILE_MAX_INNER_LOOPS = 8; +const uintN PROFILE_MAX_STACK = 6; /* * A loop profile keeps track of the instruction mix of a hot loop. We use this * information to predict whether tracing would be beneficial for the loop. */ class LoopProfile { public: @@ -732,25 +733,16 @@ public: /* * This keeps track of the number of times that every succeeding instruction * in the trace will have to be compiled. Every time we hit a branch, we * double this number. Polymorphic calls multiply it by n (for n-way * polymorphism). */ double branchMultiplier; - /* - * Tracks the value of the constant in the most recent INT8 instruction. - * This is used to detect for loops with small upper bounds (i.e., short loops). - */ - uintN prevConst; - - /* Tracks the previous opcode. */ - JSOp prevOp; - /* Set to true if the loop is short (i.e., has fewer than 8 iterations). */ bool shortLoop; /* Set to true if the loop may be short (has few iterations at profiling time). */ bool maybeShortLoop; /* * When we hit a nested loop while profiling, we record where it occurs @@ -772,16 +764,52 @@ public: /* * These two variables track the loops that we are currently nested * inside while profiling. Loops get popped off here when they exit. */ InnerLoop loopStack[PROFILE_MAX_INNER_LOOPS]; uintN loopStackDepth; + /* + * These fields keep track of values on the JS stack. If the stack grows larger + * than PROFILE_MAX_STACK, we continue to track sp, but we return conservative results + * for stackTop(). + */ + struct StackValue { + bool isConst; + bool hasValue; + int value; + + StackValue() : isConst(false), hasValue(false) {} + StackValue(bool isConst) : isConst(isConst), hasValue(false) {} + StackValue(bool isConst, int value) : isConst(isConst), hasValue(true), value(value) {} + }; + StackValue stack[PROFILE_MAX_STACK]; + uintN sp; + + inline void stackClear() { sp = 0; } + + inline void stackPush(const StackValue &v) { + if (sp < PROFILE_MAX_STACK) + stack[sp++] = v; + else + stackClear(); + } + + inline void stackPop() { if (sp > 0) sp--; } + + inline StackValue stackAt(int pos) { + pos += sp; + if (pos >= 0 && uintN(pos) < PROFILE_MAX_STACK) + return stack[pos]; + else + return StackValue(false); + } + LoopProfile(JSScript *script, jsbytecode *top, jsbytecode *bottom); enum ProfileAction { ProfContinue, ProfComplete }; /* These two functions track the instruction mix. */