This commit is contained in:
Bill McCloskey 2010-11-18 16:24:37 -08:00
Родитель 8066a8ac63 eafb6dcfaf
Коммит 6b611606ab
4 изменённых файлов: 62 добавлений и 164 удалений

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

@ -2284,7 +2284,7 @@ JSContext::updateJITEnabled()
# endif
;
#ifdef JS_TRACER
profilingEnabled = (options & JSOPTION_PROFILING) && traceJitEnabled;
profilingEnabled = (options & JSOPTION_PROFILING) && traceJitEnabled && methodJitEnabled;
#endif
#endif
}

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

@ -749,10 +749,6 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this
#ifdef JS_TRACER
if (TRACE_RECORDER(cx))
AbortRecording(cx, "attempt to reenter VM while recording");
#ifdef JS_METHODJIT
if (TRACE_PROFILER(cx))
AbortProfiling(cx);
#endif
LeaveTrace(cx);
#endif
@ -2341,21 +2337,11 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
/* Check for too deep of a native thread stack. */
#ifdef JS_TRACER
#ifdef JS_METHODJIT
JS_CHECK_RECURSION(cx, do {
if (TRACE_RECORDER(cx))
AbortRecording(cx, "too much recursion");
if (TRACE_PROFILER(cx))
AbortProfiling(cx);
return JS_FALSE;
} while (0););
#else
JS_CHECK_RECURSION(cx, do {
if (TRACE_RECORDER(cx))
AbortRecording(cx, "too much recursion");
return JS_FALSE;
} while (0););
#endif
#else
JS_CHECK_RECURSION(cx, return JS_FALSE);
#endif
@ -2418,15 +2404,9 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
MonitorResult r = MonitorLoopEdge(cx, inlineCallCount); \
if (r == MONITOR_RECORDING) { \
JS_ASSERT(TRACE_RECORDER(cx)); \
JS_ASSERT(!TRACE_PROFILER(cx)); \
MONITOR_BRANCH_TRACEVIS; \
ENABLE_INTERRUPTS(); \
CLEAR_LEAVE_ON_TRACE_POINT(); \
} else if (r == MONITOR_PROFILING) { \
JS_ASSERT(TRACE_PROFILER(cx)); \
JS_ASSERT(!TRACE_RECORDER(cx)); \
ENABLE_INTERRUPTS(); \
CLEAR_LEAVE_ON_TRACE_POINT(); \
} \
RESTORE_INTERP_VARS(); \
JS_ASSERT_IF(cx->throwing, r == MONITOR_ERROR); \
@ -2460,7 +2440,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
# define LEAVE_ON_SAFE_POINT() \
do { \
JS_ASSERT_IF(leaveOnSafePoint, !TRACE_RECORDER(cx)); \
JS_ASSERT_IF(leaveOnSafePoint, !TRACE_PROFILER(cx)); \
if (leaveOnSafePoint && !regs.fp->hasImacropc() && \
script->maybeNativeCodeForPC(regs.fp->isConstructing(), regs.pc)) { \
JS_ASSERT(!TRACE_RECORDER(cx)); \
@ -2572,20 +2551,11 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
*/
if (interpMode == JSINTERP_RECORD) {
JS_ASSERT(TRACE_RECORDER(cx));
JS_ASSERT(!TRACE_PROFILER(cx));
ENABLE_INTERRUPTS();
#ifdef JS_METHODJIT
} else if (interpMode == JSINTERP_PROFILE) {
JS_ASSERT(TRACE_PROFILER(cx));
JS_ASSERT(!TRACE_RECORDER(cx));
ENABLE_INTERRUPTS();
#endif
} else if (TRACE_RECORDER(cx)) {
AbortRecording(cx, "attempt to reenter interpreter while recording");
#ifdef JS_METHODJIT
} else if (TRACE_PROFILER(cx)) {
AbortProfiling(cx);
#endif
}
if (regs.fp->hasImacropc())
@ -2660,10 +2630,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
#ifdef JS_TRACER
if (TRACE_RECORDER(cx))
AbortRecording(cx, "interrupt hook");
#ifdef JS_METHODJIT
if (TRACE_PROFILER(cx))
AbortProfiling(cx);
#endif
#endif
Value rval;
switch (hook(cx, script, regs.pc, Jsvalify(&rval),
@ -2688,7 +2654,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
#ifdef JS_TRACER
#ifdef JS_METHODJIT
if (LoopProfile *prof = TRACE_PROFILER(cx)) {
JS_ASSERT(!TRACE_RECORDER(cx));
LoopProfile::ProfileAction act = prof->profileOperation(cx, op);
switch (act) {
case LoopProfile::ProfComplete:
@ -2702,7 +2667,6 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
}
#endif
if (TraceRecorder* tr = TRACE_RECORDER(cx)) {
JS_ASSERT(!TRACE_PROFILER(cx));
AbortableRecordingStatus status = tr->monitorRecording(op);
JS_ASSERT_IF(cx->throwing, status == ARECORD_ERROR);

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

@ -2412,7 +2412,6 @@ TraceMonitor::outOfMemory() const
AbortableRecordingStatus
TraceRecorder::finishSuccessfully()
{
JS_ASSERT(!traceMonitor->profile);
JS_ASSERT(traceMonitor->recorder == this);
JS_ASSERT(fragment->lastIns && fragment->code());
@ -2438,7 +2437,6 @@ TraceRecorder::finishSuccessfully()
JS_REQUIRES_STACK TraceRecorder::AbortResult
TraceRecorder::finishAbort(const char* reason)
{
JS_ASSERT(!traceMonitor->profile);
JS_ASSERT(traceMonitor->recorder == this);
JS_ASSERT(!fragment->code());
@ -2709,7 +2707,6 @@ TraceMonitor::flush()
{
/* flush should only be called after all recorders have been aborted. */
JS_ASSERT(!recorder);
JS_ASSERT(!profile);
AUDIT(cacheFlushed);
// recover profiling data from expiring Fragments
@ -4403,10 +4400,6 @@ ResetJITImpl(JSContext* cx)
JS_ASSERT_NOT_ON_TRACE(cx);
AbortRecording(cx, "flush cache");
}
#if JS_METHODJIT
if (tm->profile)
AbortProfiling(cx);
#endif
if (ProhibitFlush(cx)) {
debug_only_print0(LC_TMTracer, "Deferring JIT flush due to deep bail.\n");
tm->needFlush = JS_TRUE;
@ -5505,7 +5498,6 @@ TraceRecorder::startRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* f,
bool speculate)
{
TraceMonitor *tm = &JS_TRACE_MONITOR(cx);
JS_ASSERT(!tm->profile);
JS_ASSERT(!tm->needFlush);
JS_ASSERT_IF(cx->fp()->hasImacropc(), f->root != f);
@ -6400,9 +6392,6 @@ static JS_ALWAYS_INLINE VMSideExit*
ExecuteTrace(JSContext* cx, Fragment* f, TracerState& state)
{
JS_ASSERT(!cx->bailExit);
#ifdef JS_METHODJIT
JS_ASSERT(!TRACE_PROFILER(cx));
#endif
union { NIns *code; GuardRecord* (FASTCALL *func)(TracerState*); } u;
u.code = f->code();
GuardRecord* rec;
@ -6470,8 +6459,7 @@ ExecuteTree(JSContext* cx, TreeFragment* f, uintN& inlineCallCount,
#endif
JS_ASSERT(f->root == f && f->code());
TraceMonitor* tm = &JS_TRACE_MONITOR(cx);
JS_ASSERT(!tm->profile);
if (!ScopeChainCheck(cx, f) || !cx->stack().ensureEnoughSpaceToEnterTrace() ||
inlineCallCount + f->maxCallDepth > JS_MAX_INLINE_CALL_COUNT) {
*lrp = NULL;
@ -6935,7 +6923,7 @@ TraceRecorder::assertInsideLoop()
}
JS_REQUIRES_STACK MonitorResult
RecordLoopEdge(JSContext* cx, uintN& inlineCallCount, bool execOK)
RecordLoopEdge(JSContext* cx, uintN& inlineCallCount)
{
#ifdef MOZ_TRACEVIS
TraceVisStateObj tvso(cx, S_MONITOR);
@ -6943,8 +6931,6 @@ RecordLoopEdge(JSContext* cx, uintN& inlineCallCount, bool execOK)
TraceMonitor* tm = &JS_TRACE_MONITOR(cx);
JS_ASSERT(!tm->profile);
/* Is the recorder currently active? */
if (tm->recorder) {
tm->recorder->assertInsideLoop();
@ -7060,9 +7046,6 @@ RecordLoopEdge(JSContext* cx, uintN& inlineCallCount, bool execOK)
return MONITOR_NOT_RECORDING;
}
if (!execOK)
return MONITOR_NOT_RECORDING;
VMSideExit* lr = NULL;
VMSideExit* innermostNestedGuard = NULL;
@ -7157,7 +7140,6 @@ TraceRecorder::monitorRecording(JSOp op)
TraceMonitor &localtm = JS_TRACE_MONITOR(cx);
debug_only_stmt( JSContext *localcx = cx; )
assertInsideLoop();
JS_ASSERT(!localtm.profile);
/* Process needFlush requests now. */
if (localtm.needFlush) {
@ -7643,7 +7625,6 @@ void
FinishJIT(TraceMonitor *tm)
{
JS_ASSERT(!tm->recorder);
JS_ASSERT(!tm->profile);
#ifdef JS_JIT_SPEW
if (jitstats.recorderStarted) {
@ -16226,7 +16207,6 @@ RecordTracePoint(JSContext* cx, uintN& inlineCallCount, bool* blacklist, bool ex
jsbytecode* pc = cx->regs->pc;
JS_ASSERT(!TRACE_RECORDER(cx));
JS_ASSERT(!tm->profile);
JSObject* globalObj = cx->fp()->scopeChain().getGlobal();
uint32 globalShape = -1;
@ -16328,15 +16308,13 @@ RecordTracePoint(JSContext* cx, uintN& inlineCallCount, bool* blacklist, bool ex
return TPA_RanStuff;
}
LoopProfile::LoopProfile(JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom)
: script(entryfp->script()),
entryfp(entryfp),
LoopProfile::LoopProfile(JSScript *script, jsbytecode *top, jsbytecode *bottom)
: script(script),
top(top),
bottom(bottom),
hits(0),
profiled(false),
traceOK(false),
execOK(false),
numAllOps(0),
numSelfOps(0),
numSelfOpsMult(0),
@ -16359,21 +16337,20 @@ LoopProfile::profileLoopEdge(JSContext* cx, uintN& inlineCallCount)
decide(cx);
} else {
/* Record an inner loop invocation. */
JSStackFrame *fp = cx->fp();
JSScript *script = cx->fp()->script();
jsbytecode *pc = cx->regs->pc;
bool found = false;
/* We started with the most deeply nested one first, since it gets hit most often.*/
for (int i = int(numInnerLoops)-1; i >= 0; i--) {
if (innerLoops[i].entryfp == fp && innerLoops[i].top == pc) {
if (innerLoops[i].script == script && innerLoops[i].top == pc) {
innerLoops[i].iters++;
found = true;
break;
}
}
if (!found && numInnerLoops < PROFILE_MAX_INNER_LOOPS)
innerLoops[numInnerLoops++] = InnerLoop(fp, pc, NULL);
innerLoops[numInnerLoops++] = InnerLoop(script, pc, NULL);
}
return MONITOR_NOT_RECORDING;
@ -16410,32 +16387,32 @@ LookupOrAddProfile(JSContext *cx, TraceMonitor *tm, void** traceData, uintN *tra
* This ensures that no flush has happened in between.
*/
if (traceData) {
if (*traceData && *traceEpoch == tm->flushEpoch) {
prof = (LoopProfile *)*traceData;
} else {
jsbytecode* pc = cx->regs->pc;
jsbytecode* bottom = GetLoopBottom(cx);
if (!bottom)
return NULL;
prof = new (*tm->dataAlloc) LoopProfile(cx->fp(), pc, bottom);
*traceData = prof;
*traceEpoch = tm->flushEpoch;
tm->loopProfiles->put(pc, prof);
}
#if JS_MONOIC
if (*traceData && *traceEpoch == tm->flushEpoch) {
prof = (LoopProfile *)*traceData;
} else {
LoopProfileMap &table = *tm->loopProfiles;
jsbytecode* pc = cx->regs->pc;
if (LoopProfileMap::AddPtr p = table.lookupForAdd(pc)) {
prof = p->value;
} else {
jsbytecode* bottom = GetLoopBottom(cx);
if (!bottom)
return NULL;
prof = new (*tm->dataAlloc) LoopProfile(cx->fp(), pc, bottom);
table.add(p, pc, prof);
}
jsbytecode* bottom = GetLoopBottom(cx);
if (!bottom)
return NULL;
prof = new (*tm->dataAlloc) LoopProfile(cx->fp()->script(), pc, bottom);
*traceData = prof;
*traceEpoch = tm->flushEpoch;
tm->loopProfiles->put(pc, prof);
}
#else
LoopProfileMap &table = *tm->loopProfiles;
jsbytecode* pc = cx->regs->pc;
if (LoopProfileMap::AddPtr p = table.lookupForAdd(pc)) {
prof = p->value;
} else {
jsbytecode* bottom = GetLoopBottom(cx);
if (!bottom)
return NULL;
prof = new (*tm->dataAlloc) LoopProfile(cx->fp()->script(), pc, bottom);
table.add(p, pc, prof);
}
#endif
return prof;
}
@ -16476,10 +16453,9 @@ MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist,
}
}
debug_only_printf(LC_TMProfiler, "Profiling at line %d from methodjit\n",
debug_only_printf(LC_TMProfiler, "Profiling at line %d\n",
js_FramePCToLineNumber(cx, cx->fp()));
prof->entryfp = cx->fp();
tm->profile = prof;
if (!Interpret(cx, cx->fp(), inlineCallCount, JSINTERP_PROFILE))
@ -16491,14 +16467,16 @@ MonitorTracePoint(JSContext *cx, uintN& inlineCallCount, bool* blacklist,
}
/*
* Returns true if pc is within the given loop. Also returns true if
* we are in some function called by the loop.
* Returns true if pc is within the given loop.
* If we're in a different script, then we must have come from
* a call instruction within the loop (since we check if we're within
* the loop before each instruction) so we're still in the loop.
*/
template<class T>
static inline bool
PCWithinLoop(JSStackFrame *fp, jsbytecode *pc, T& loop)
PCWithinLoop(JSScript *script, jsbytecode *pc, T& loop)
{
return fp > loop.entryfp || (fp == loop.entryfp && pc >= loop.top && pc <= loop.bottom);
return script != loop.script || (pc >= loop.top && pc <= loop.bottom);
}
LoopProfile::ProfileAction
@ -16512,19 +16490,18 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op)
}
jsbytecode *pc = cx->regs->pc;
JSStackFrame *fp = cx->fp();
JSScript *script = fp->script();
JSScript *script = cx->fp()->maybeScript();
if (!PCWithinLoop(fp, pc, *this)) {
if (!PCWithinLoop(script, pc, *this)) {
debug_only_printf(LC_TMProfiler, "Profiling complete (loop exit) at %d (line %u)\n",
(int)(cx->regs->pc - script->code),
(int)(cx->regs->pc - cx->fp()->script()->code),
js_FramePCToLineNumber(cx, cx->fp()));
tm->profile->decide(cx);
tm->profile = NULL;
return ProfComplete;
}
while (loopStackDepth > 0 && !PCWithinLoop(fp, pc, loopStack[loopStackDepth-1])) {
while (loopStackDepth > 0 && !PCWithinLoop(script, pc, loopStack[loopStackDepth-1])) {
debug_only_print0(LC_TMProfiler, "Profiler: Exiting inner loop\n");
loopStackDepth--;
}
@ -16539,7 +16516,7 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op)
}
debug_only_print0(LC_TMProfiler, "Profiler: Entering inner loop\n");
loopStack[loopStackDepth++] = InnerLoop(fp, pc, GetLoopBottom(cx));
loopStack[loopStackDepth++] = InnerLoop(script, pc, GetLoopBottom(cx));
}
}
@ -16601,7 +16578,7 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op)
}
if (op == JSOP_CALLPROP && loopStackDepth == 0)
branchMultiplier *= mjit::GetCallTargetCount(script, cx->regs->pc);
branchMultiplier *= mjit::GetCallTargetCount(cx->fp()->script(), cx->regs->pc);
if (op == JSOP_TABLESWITCH) {
jsint low = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN);
@ -16635,7 +16612,7 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op)
}
/* Check if we're exiting the loop being profiled. */
JSOp testOp = js_GetOpcode(cx, script, testPC);
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)
{
@ -16683,15 +16660,6 @@ LoopProfile::profileOperation(JSContext* cx, JSOp op)
} else {
stackClear();
}
if (count(OP_RECURSIVE) || count(OP_EVAL)) {
debug_only_printf(LC_TMProfiler, "Profiling complete (early exit) at %d (line %u)\n",
(int)(cx->regs->pc - script->code),
js_FramePCToLineNumber(cx, cx->fp()));
tm->profile->decide(cx);
tm->profile = NULL;
return ProfComplete;
}
return ProfContinue;
}
@ -16727,7 +16695,7 @@ LoopProfile::isCompilationExpensive(JSContext *cx, uintN depth)
return true;
/* Is the code too branchy? */
if (numSelfOpsMult > numSelfOps*100000)
if (numSelfOpsMult >= numSelfOps*100000)
return true;
/* Ensure that inner loops aren't too expensive. */
@ -16802,24 +16770,20 @@ LoopProfile::decide(JSContext *cx)
#endif
traceOK = false;
/*
* The first two cases are "early exits"; if these change, need
* to change profileOperation too.
*/
if (count(OP_RECURSIVE)) {
debug_only_print0(LC_TMProfiler, "NOTRACE: recursive\n");
/* don't trace */
} else if (count(OP_EVAL)) {
debug_only_print0(LC_TMProfiler, "NOTRACE: eval\n");
/* don't trace */
} else if (numInnerLoops > 3) {
debug_only_print0(LC_TMProfiler, "NOTRACE: >3 inner loops\n");
/* don't trace */
} else if (shortLoop) {
debug_only_print0(LC_TMProfiler, "NOTRACE: short\n");
/* don't trace */
} else if (maybeShortLoop && numInnerLoops < 2) {
debug_only_print0(LC_TMProfiler, "NOTRACE: maybe short\n");
/* don't trace */
} else if (isCompilationExpensive(cx, 4)) {
debug_only_print0(LC_TMProfiler, "NOTRACE: expensive\n");
/* don't trace */
} else if (isCompilationUnprofitable(cx, 4)) {
debug_only_print0(LC_TMProfiler, "NOTRACE: unprofitable\n");
/* don't trace */
} else {
uintN goodOps = 0;
@ -16874,34 +16838,11 @@ LoopProfile::decide(JSContext *cx)
JS_REQUIRES_STACK MonitorResult
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
{
if (!cx->profilingEnabled || TRACE_RECORDER(cx))
return RecordLoopEdge(cx, inlineCallCount, true);
TraceMonitor *tm = &JS_TRACE_MONITOR(cx);
if (tm->profile)
return tm->profile->profileLoopEdge(cx, inlineCallCount);
LoopProfile *prof = LookupOrAddProfile(cx, tm, NULL, NULL);
if (!prof)
return MONITOR_NOT_RECORDING;
if (prof->hits++ < PROFILE_HOTLOOP)
return MONITOR_NOT_RECORDING;
if (prof->profiled) {
if (prof->traceOK)
return RecordLoopEdge(cx, inlineCallCount, prof->execOK);
return MONITOR_NOT_RECORDING;
}
debug_only_printf(LC_TMProfiler, "Profiling at line %d from interpreter\n",
js_FramePCToLineNumber(cx, cx->fp()));
prof->entryfp = cx->fp();
tm->profile = prof;
return MONITOR_PROFILING;
else
return RecordLoopEdge(cx, inlineCallCount);
}
void
@ -16909,10 +16850,8 @@ AbortProfiling(JSContext *cx)
{
debug_only_print0(LC_TMProfiler, "Profiling complete (aborted)\n");
TraceMonitor *tm = &JS_TRACE_MONITOR(cx);
tm->profile->profiled = true;
tm->profile->traceOK = false;
tm->profile->execOK = false;
Blacklist(tm->profile->top);
tm->profile->numSelfOps = MAX_PROFILE_OPS;
tm->profile->decide(cx);
tm->profile = NULL;
}
@ -16921,7 +16860,7 @@ AbortProfiling(JSContext *cx)
JS_REQUIRES_STACK MonitorResult
MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount)
{
return RecordLoopEdge(cx, inlineCallCount, true);
return RecordLoopEdge(cx, inlineCallCount);
}
#endif /* JS_METHODJIT */

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

@ -640,7 +640,6 @@ VMFragment::toTreeFragment()
enum MonitorResult {
MONITOR_RECORDING,
MONITOR_PROFILING,
MONITOR_NOT_RECORDING,
MONITOR_ERROR
};
@ -673,9 +672,6 @@ public:
/* The script in which the loop header lives. */
JSScript *script;
/* The stack frame where we started profiling. Only valid while profiling! */
JSStackFrame *entryfp;
/* The bytecode locations of the loop header and the back edge. */
jsbytecode *top, *bottom;
@ -731,14 +727,13 @@ public:
* and how many iterations we execute it.
*/
struct InnerLoop {
JSStackFrame *entryfp;
JSScript *script;
jsbytecode *top, *bottom;
uintN iters;
InnerLoop() {}
InnerLoop(JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom)
: entryfp(entryfp), script(entryfp->script()), top(top), bottom(bottom), iters(0) {}
InnerLoop(JSScript *script, jsbytecode *top, jsbytecode *bottom)
: script(script), top(top), bottom(bottom), iters(0) {}
};
/* These two variables track all the inner loops seen while profiling (up to a limit). */
@ -788,7 +783,7 @@ public:
return StackValue(false);
}
LoopProfile(JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom);
LoopProfile(JSScript *script, jsbytecode *top, jsbytecode *bottom);
enum ProfileAction {
ProfContinue,
@ -1565,7 +1560,7 @@ class TraceRecorder
friend class DetermineTypesVisitor;
friend class RecursiveSlotMap;
friend class UpRecursiveSlotMap;
friend MonitorResult RecordLoopEdge(JSContext*, uintN&, bool);
friend MonitorResult RecordLoopEdge(JSContext*, uintN&);
friend TracePointAction RecordTracePoint(JSContext*, uintN &inlineCallCount,
bool *blacklist);
friend AbortResult AbortRecording(JSContext*, const char*);