This commit is contained in:
David Anderson 2008-08-29 15:38:05 -07:00
commit 7515a0583e
2 changed files with 59 additions and 36 deletions

View File

@ -97,7 +97,7 @@ static struct {
recorderStarted, recorderAborted, traceCompleted, sideExitIntoInterpreter,
typeMapMismatchAtEntry, returnToDifferentLoopHeader, traceTriggered,
globalShapeMismatchAtEntry, treesTrashed, slotPromoted,
unstableLoopVariable;
unstableLoopVariable, breakLoopExits;
} stat = { 0LL, };
#define AUDIT(x) (stat.x++)
#else
@ -756,9 +756,9 @@ bool
TraceRecorder::trackLoopEdges()
{
jsbytecode* pc = cx->fp->regs->pc;
if (loopEdgeList.contains(pc))
if (inlinedLoopEdges.contains(pc))
return false;
loopEdgeList.add(pc);
inlinedLoopEdges.add(pc);
return true;
}
@ -1283,16 +1283,6 @@ js_IsLoopExit(JSContext* cx, JSScript* script, jsbytecode* header, jsbytecode* p
return false;
}
/* Determine whether a bytecode location (pc) is a break statement. */
bool
js_isBreak(JSContext* cx, JSScript* script, jsbytecode* pc)
{
jssrcnote* sn;
return (((*pc == JSOP_GOTO) || (*pc == JSOP_GOTOX)) &&
((sn = js_GetSrcNote(cx->fp->script, pc)) != NULL) &&
SN_TYPE(sn) == SRC_BREAK);
}
struct FrameInfo {
JSObject* callee; // callee function object
jsbytecode* callpc; // pc of JSOP_CALL in caller script
@ -1536,6 +1526,7 @@ TraceRecorder::compile(Fragmento* fragmento)
fragmento->labels->add(fragment, sizeof(Fragment), 0, label);
free(label);
#endif
AUDIT(traceCompleted);
}
/* Complete and compile a trace and link it to the existing tree if appropriate. */
@ -1633,6 +1624,35 @@ TraceRecorder::emitTreeCall(Fragment* inner, GuardRecord* lr)
((TreeInfo*)inner->vmprivate)->dependentTrees.addUnique(fragment->root);
}
/* Add a if/if-else control-flow merge point to the list of known merge points. */
void
TraceRecorder::trackCfgMerges(jsbytecode* pc)
{
/* If we hit the beginning of an if/if-else, then keep track of the merge point after it. */
JS_ASSERT((*pc == JSOP_IFEQ) || (*pc == JSOP_IFEQX));
jssrcnote* sn = js_GetSrcNote(cx->fp->script, pc);
if (sn != NULL) {
if (SN_TYPE(sn) == SRC_IF) {
cfgMerges.add((*pc == JSOP_IFEQ)
? pc + GET_JUMP_OFFSET(pc)
: pc + GET_JUMPX_OFFSET(pc));
} else if (SN_TYPE(sn) == SRC_IF_ELSE)
cfgMerges.add(pc + js_GetSrcNoteOffset(sn, 0));
}
}
/* Emit code for a fused IFEQ/IFNE. */
void
TraceRecorder::fuseIf(jsbytecode* pc, bool cond, LIns* x)
{
if (*pc == JSOP_IFEQ) {
guard(cond, x, BRANCH_EXIT);
trackCfgMerges(pc);
} else if (*pc == JSOP_IFNE) {
guard(cond, x, BRANCH_EXIT);
}
}
int
nanojit::StackFilter::getTop(LInsp guard)
{
@ -1957,7 +1977,6 @@ js_RecordLoopEdge(JSContext* cx, TraceRecorder* r, jsbytecode* oldpc, uintN& inl
js_FlushJITCache(cx);
return false; /* done recording */
}
AUDIT(traceCompleted);
r->closeLoop(fragmento);
js_DeleteRecorder(cx);
return false; /* done recording */
@ -2260,15 +2279,19 @@ js_MonitorLoopEdge(JSContext* cx, jsbytecode* oldpc, uintN& inlineCallCount)
}
bool
js_MonitorGoto(JSContext* cx)
js_MonitorRecording(JSContext* cx)
{
jsbytecode* pc = cx->fp->regs->pc;
/* If we hit a break, end the loop and generate an always taken loop exit guard. For other
downward gotos (like if/else) continue recording. */
if (js_isBreak(cx, cx->fp->script, cx->fp->regs->pc)) {
AUDIT(traceCompleted);
JS_TRACE_MONITOR(cx).recorder->endLoop(JS_TRACE_MONITOR(cx).fragmento);
js_DeleteRecorder(cx);
return false; /* done recording */
if ((*pc == JSOP_GOTO) || (*pc == JSOP_GOTOX)) {
jssrcnote* sn = js_GetSrcNote(cx->fp->script, pc);
if ((sn != NULL) && (SN_TYPE(sn) == SRC_BREAK)) {
AUDIT(breakLoopExits);
JS_TRACE_MONITOR(cx).recorder->endLoop(JS_TRACE_MONITOR(cx).fragmento);
js_DeleteRecorder(cx);
return false; /* done recording */
}
}
/* If its not a break, continue recording and follow the trace. */
return true;
@ -2353,11 +2376,11 @@ js_FinishJIT(JSTraceMonitor *tm)
{
#ifdef DEBUG
printf("recorder: started(%llu), aborted(%llu), completed(%llu), different header(%llu), "
"trees trashed(%llu), slot promoted(%llu), "
"unstable loop variable(%llu)\n",
"trees trashed(%llu), slot promoted(%llu), unstable loop variable(%llu), "
"breaks: (%llu)\n",
stat.recorderStarted, stat.recorderAborted,
stat.traceCompleted, stat.returnToDifferentLoopHeader, stat.treesTrashed,
stat.slotPromoted, stat.unstableLoopVariable);
stat.slotPromoted, stat.unstableLoopVariable, stat.breakLoopExits);
printf("monitor: triggered(%llu), exits(%llu), type mismatch(%llu), "
"global mismatch(%llu)\n", stat.traceTriggered, stat.sideExitIntoInterpreter,
stat.typeMapMismatchAtEntry, stat.globalShapeMismatchAtEntry);
@ -2800,10 +2823,8 @@ TraceRecorder::cmp(LOpcode op, int flags)
/* The interpreter fuses comparisons and the following branch,
so we have to do that here as well. */
if (flags & CMP_TRY_BRANCH_AFTER_COND) {
if (cx->fp->regs->pc[1] == JSOP_IFEQ || cx->fp->regs->pc[1] == JSOP_IFNE)
guard(cond, x, BRANCH_EXIT);
}
if (flags & CMP_TRY_BRANCH_AFTER_COND)
fuseIf(cx->fp->regs->pc + 1, cond, x);
/* We update the stack after the guard. This is safe since
the guard bails out at the comparison and the interpreter
@ -3433,6 +3454,7 @@ TraceRecorder::record_JSOP_GOTO()
bool
TraceRecorder::record_JSOP_IFEQ()
{
trackCfgMerges(cx->fp->regs->pc);
return ifop();
}
@ -5128,8 +5150,7 @@ TraceRecorder::record_JSOP_IN()
/* The interpreter fuses comparisons and the following branch,
so we have to do that here as well. */
if (cx->fp->regs->pc[1] == JSOP_IFEQ || cx->fp->regs->pc[1] == JSOP_IFNE)
guard(cond, x, BRANCH_EXIT);
fuseIf(cx->fp->regs->pc + 1, cond, x);
/* We update the stack after the guard. This is safe since
the guard bails out at the comparison and the interpreter
@ -5337,6 +5358,7 @@ TraceRecorder::record_JSOP_GOTOX()
bool
TraceRecorder::record_JSOP_IFEQX()
{
trackCfgMerges(cx->fp->regs->pc);
return record_JSOP_IFEQ();
}

View File

@ -230,7 +230,8 @@ class TraceRecorder {
nanojit::SideExit exit;
bool trashTree;
nanojit::Fragment* whichTreeToTrash;
Queue<jsbytecode*> loopEdgeList;
Queue<jsbytecode*> inlinedLoopEdges;
Queue<jsbytecode*> cfgMerges;
bool isGlobal(jsval* p) const;
ptrdiff_t nativeGlobalOffset(jsval* p) const;
@ -323,6 +324,8 @@ class TraceRecorder {
bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc);
bool forInLoop(jsval* vp);
void trackCfgMerges(jsbytecode* pc);
void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
public:
TraceRecorder(JSContext* cx, nanojit::GuardRecord*, nanojit::Fragment*, TreeInfo*,
unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap,
@ -357,22 +360,20 @@ public:
#define RECORD(x) \
JS_BEGIN_MACRO \
TraceRecorder* r = JS_TRACE_MONITOR(cx).recorder; \
if (!js_MonitorRecording(cx)) { \
ENABLE_TRACER(0); \
} else \
if (!r->record_##x()) { \
js_AbortRecording(cx, NULL, #x); \
ENABLE_TRACER(0); \
} \
jsbytecode* pc = cx->fp->regs->pc; \
if (((*pc == JSOP_GOTO) || (*pc == JSOP_GOTOX)) && \
!js_MonitorGoto(cx)) { \
ENABLE_TRACER(0); \
} \
JS_END_MACRO
extern bool
js_MonitorLoopEdge(JSContext* cx, jsbytecode* oldpc, uintN& inlineCallCount);
extern bool
js_MonitorGoto(JSContext* cx);
js_MonitorRecording(JSContext* cx);
extern void
js_AbortRecording(JSContext* cx, jsbytecode* abortpc, const char* reason);