Added end-of-trace detection and make sure trace loops back to the loop header.

This commit is contained in:
Andreas Gal 2008-06-22 09:30:04 -07:00
parent 2270a14eb0
commit 6d192a7054
3 changed files with 88 additions and 39 deletions

View File

@ -2782,17 +2782,9 @@ JS_INTERPRET(JSContext *cx, JSInterpreterState *state)
# endif
# define ABORT_TRACE(x) \
REPORT_ABORT(x); \
goto abort_trace;
# define ABORT_TRACE_IF_ERROR \
JS_BEGIN_MACRO \
if (js_GetRecorderError(cx)) { \
REPORT_ABORT("recorder error"); \
goto abort_trace; \
} \
JS_END_MACRO
goto abort_recording;
#else
# define ABORT_TRACE(x) ((void)0)
# define ABORT_TRACE_IF_ERROR ((void)0)
#endif
#if JS_THREADED_INTERP
@ -2811,7 +2803,6 @@ JS_INTERPRET(JSContext *cx, JSInterpreterState *state)
};
# define DO_OP() JS_BEGIN_MACRO \
ABORT_TRACE_IF_ERROR; \
JS_EXTENSION_(goto *jumpTable[op]); \
JS_END_MACRO
# define DO_NEXT_OP(n) JS_BEGIN_MACRO \
@ -2835,7 +2826,6 @@ JS_INTERPRET(JSContext *cx, JSInterpreterState *state)
#else /* !JS_THREADED_INTERP */
# define DO_OP() JS_BEGIN_MACRO \
ABORT_TRACE_IF_ERROR; \
goto do_op; \
JS_END_MACRO
# define DO_NEXT_OP(n) JS_BEGIN_MACRO \
@ -2937,11 +2927,18 @@ JS_INTERPRET(JSContext *cx, JSInterpreterState *state)
if (ENABLE_TRACER && \
(JS_TRACE_MONITOR(cx).freq++ & TRACE_TRIGGER_MASK) == 0) { \
regs.pc += n; \
goto attempt_tracing; \
goto attempt_recording; \
} \
JS_END_MACRO
#else
# define MONITOR_BRANCH(n) ((void)0)
# define MONITOR_BRANCH(n) \
JS_BEGIN_MACRO \
if (ENABLE_TRACER && \
JS_TRACE_MONITOR(cx).status == RECORDING && \
JS_TRACE_MONITOR(cx).entryState.pc == (regs.pc + n)) { \
goto end_recording; \
} \
JS_END_MACRO
#endif
/*
@ -7004,8 +7001,18 @@ JS_INTERPRET(JSContext *cx, JSInterpreterState *state)
SAVE_STATE(state, JS_NEXT_ERROR);
return JS_FALSE;
abort_trace:
js_StopRecorder(cx, regs);
abort_recording:
#ifdef DEBUG
printf("Abort recording.\n");
#endif
JS_TRACE_MONITOR(cx).status = ABORTED;
/* fall through */
end_recording:
#ifdef DEBUG
printf("End recording.\n");
#endif
js_EndRecording(cx, regs);
SAVE_STATE(state, JS_NEXT_CONTINUE);
return ok;
#else
@ -7225,10 +7232,13 @@ JS_INTERPRET(JSContext *cx, JSInterpreterState *state)
}
#ifndef jstracer_cpp___
attempt_tracing:
attempt_recording:
{
js_StartRecorder(cx, regs);
if (js_GetRecorderError(cx)) {
#ifdef DEBUG
printf("Attempt recording.\n");
#endif
js_StartRecording(cx, regs);
if (JS_TRACE_MONITOR(cx).status != RECORDING) {
op = (JSOp) *regs.pc;
DO_OP();
}

View File

@ -144,8 +144,48 @@ static struct CallInfo builtins[] = {
#undef BUILTIN2
#undef BUILTIN3
struct BoxOpTable {
int32_t box;
int32_t unbox;
};
static BoxOpTable boxOpTable[] = {
{F_UNBOX_BOOLEAN, F_BOX_BOOLEAN},
{F_UNBOX_STRING, F_BOX_STRING},
{F_UNBOX_OBJECT, F_BOX_OBJECT},
{F_UNBOX_INT, F_BOX_INT},
{F_UNBOX_DOUBLE, F_BOX_DOUBLE}
};
// This filter eliminates redundant boxing.
class BoxFilter: public LirWriter
{
LInsp check(int32_t fid, LInsp args[], int32_t first, int32_t second) {
if (fid == first) {
LInsp a = args[0];
if (a->isop(LIR_call) && (a->imm8() == second))
return a[-1].oprnd1();
}
return (LInsp)0;
}
public:
BoxFilter(LirWriter* out): LirWriter(out)
{
}
LInsp insCall(int32_t fid, LInsp args[])
{
LInsp p;
for (uint32 n = 0; n < sizeof(boxOpTable)/sizeof(struct BoxOpTable); ++n)
if ((p = check(fid, args, boxOpTable[n].unbox, boxOpTable[n].box)) != 0)
return p;
return out->insCall(fid, args);
}
};
void
js_StartRecorder(JSContext* cx, JSFrameRegs& regs)
js_StartRecording(JSContext* cx, JSFrameRegs& regs)
{
struct JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
@ -156,6 +196,8 @@ js_StartRecorder(JSContext* cx, JSFrameRegs& regs)
tm->fragmento = fragmento;
}
memcpy(&tm->entryState, &regs, sizeof(regs));
InterpState state;
state.ip = NULL;
state.sp = NULL;
@ -167,6 +209,7 @@ js_StartRecorder(JSContext* cx, JSFrameRegs& regs)
lirbuf->names = new (&gc) LirNameMap(&gc, builtins, tm->fragmento->labels);
fragment->lirbuf = lirbuf;
LirWriter* lir = new (&gc) LirBufWriter(lirbuf);
lir = new (&gc) BoxFilter(lir);
lir->ins0(LIR_trace);
fragment->param0 = lir->insImm8(LIR_param, Assembler::argRegs[0], 0);
fragment->param1 = lir->insImm8(LIR_param, Assembler::argRegs[1], 0);
@ -187,24 +230,17 @@ js_StartRecorder(JSContext* cx, JSFrameRegs& regs)
tm->fragment = fragment;
tm->lir = lir;
tm->status = RECORDING;
}
void
js_StopRecorder(JSContext* cx, JSFrameRegs& regs)
js_EndRecording(JSContext* cx, JSFrameRegs& regs)
{
struct JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
SideExit exit;
memset(&exit, 0, sizeof(exit));
exit.from = tm->fragment;
tm->fragment->lastIns = tm->lir->insGuard(LIR_x, NULL, &exit);
compile(tm->fragmento->assm(), tm->fragment);
if (tm->status == RECORDING) {
tm->fragment->lastIns = tm->lir->ins0(LIR_loop);
compile(tm->fragmento->assm(), tm->fragment);
}
tm->status = IDLE;
}
bool
js_GetRecorderError(JSContext* cx)
{
return false;
}

View File

@ -74,6 +74,10 @@ public:
void clear();
};
enum TraceRecorderStatus {
IDLE, RECORDING, ABORTED
};
/*
* Trace monitor. Every runtime is associated with a trace monitor that keeps
* track of loop frequencies for all JavaScript code loaded into that runtime.
@ -86,6 +90,8 @@ public:
*/
struct JSTraceMonitor {
int freq;
TraceRecorderStatus status;
JSFrameRegs entryState;
Tracker tracker;
nanojit::Fragment* fragment;
nanojit::Fragmento* fragmento;
@ -96,12 +102,9 @@ struct JSTraceMonitor {
#define TRACE_TRIGGER_MASK 0x3f
extern void
js_StartRecorder(JSContext* cx, JSFrameRegs& regs);
js_StartRecording(JSContext* cx, JSFrameRegs& regs);
extern void
js_StopRecorder(JSContext* cx, JSFrameRegs& regs);
extern bool
js_GetRecorderError(JSContext* cx);
js_EndRecording(JSContext* cx, JSFrameRegs& regs);
#endif /* jstracer_h___ */