Allocate recorder dynamically to avoid having a vtable in the struct holding the reference. Emit writebacks for every update to the tracker, not just stack writes.

This commit is contained in:
Andreas Gal 2008-06-26 19:37:28 -08:00
parent 407b9cdf75
commit 5b4f0aaeaa
4 changed files with 61 additions and 35 deletions

View File

@ -2934,8 +2934,8 @@ JS_INTERPRET(JSContext *cx, JSInterpreterState *state)
# 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)) { \
JS_TRACE_MONITOR(cx).recorder != NULL && \
JS_TRACE_MONITOR(cx).recorder->entryState.pc == (regs.pc + n)) { \
goto end_recording; \
} \
JS_END_MACRO
@ -7005,7 +7005,8 @@ JS_INTERPRET(JSContext *cx, JSInterpreterState *state)
#ifdef DEBUG
printf("Abort recording.\n");
#endif
JS_TRACE_MONITOR(cx).status = ABORTED;
delete JS_TRACE_MONITOR(cx).recorder;
JS_TRACE_MONITOR(cx).recorder = NULL;
/* fall through */
end_recording:
@ -7237,8 +7238,7 @@ JS_INTERPRET(JSContext *cx, JSInterpreterState *state)
#ifdef DEBUG
printf("Attempt recording.\n");
#endif
js_StartRecording(cx, regs);
if (JS_TRACE_MONITOR(cx).status != RECORDING) {
if (!js_StartRecording(cx, regs)) {
op = (JSOp) *regs.pc;
DO_OP();
}

View File

@ -114,7 +114,7 @@ template <typename T> void
Tracker<T>::set(const void* v, T i)
{
#ifdef DEBUG
//printf("set %p to %s\n", v, nanojit::lirNames[ins->opcode()]);
//printf("set %p to %s\n", v, nanojit::lirNames[i->opcode()]);
#endif
struct Tracker::Page* p = findPage(v);
if (!p)
@ -154,11 +154,11 @@ static struct CallInfo builtins[] = {
#undef BUILTIN2
#undef BUILTIN3
void
bool
js_StartRecording(JSContext* cx, JSFrameRegs& regs)
{
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
if (!tm->fragmento) {
Fragmento* fragmento = new (&gc) Fragmento(core);
#ifdef DEBUG
@ -168,7 +168,8 @@ js_StartRecording(JSContext* cx, JSFrameRegs& regs)
tm->fragmento = fragmento;
}
memcpy(&tm->entryState, &regs, sizeof(regs));
JSTraceRecorder* recorder = new JSTraceRecorder(regs);
tm->recorder = recorder;
InterpState state;
state.ip = NULL;
@ -188,32 +189,37 @@ js_StartRecording(JSContext* cx, JSFrameRegs& regs)
fragment->param1 = lir->insImm8(LIR_param, Assembler::argRegs[1], 0);
JSStackFrame* fp = cx->fp;
tm->tracker.set(cx, fragment->param0);
recorder->tracker.set(cx, lir->insLoadi(fragment->param0, 0));
recorder->tracker.set(&recorder->entryState.sp, lir->insLoadi(fragment->param0, 4));
#define LOAD_CONTEXT(p) \
tm->tracker.set(p, lir->insLoadi(fragment->param1, STACK_OFFSET(p)))
#define LOAD_CONTEXT(p) \
recorder->tracker.set(p, \
lir->insLoadi(recorder->tracker.get(&recorder->entryState.sp), \
STACK_OFFSET(p)))
unsigned n;
for (n = 0; n < fp->argc; ++n)
LOAD_CONTEXT(&fp->argv[n]);
for (n = 0; n < fp->nvars; ++n)
for (n = 0; n < fp->nvars; ++n)
LOAD_CONTEXT(&fp->vars[n]);
for (n = 0; n < (unsigned)(regs.sp - fp->spbase); ++n)
LOAD_CONTEXT(&fp->spbase[n]);
tm->fragment = fragment;
tm->lir = lir;
recorder->fragment = fragment;
recorder->lir = lir;
tm->status = RECORDING;
return true;
}
void
js_EndRecording(JSContext* cx, JSFrameRegs& regs)
{
JSTraceMonitor* tm = &JS_TRACE_MONITOR(cx);
if (tm->status == RECORDING) {
tm->fragment->lastIns = tm->lir->ins0(LIR_loop);
compile(tm->fragmento->assm(), tm->fragment);
if (tm->recorder != NULL) {
JSTraceRecorder* recorder = tm->recorder;
recorder->fragment->lastIns = recorder->lir->ins0(LIR_loop);
compile(tm->fragmento->assm(), recorder->fragment);
delete recorder;
tm->recorder = NULL;
}
tm->status = IDLE;
}

View File

@ -75,8 +75,16 @@ public:
void clear();
};
enum TraceRecorderStatus {
IDLE, RECORDING, ABORTED
class JSTraceRecorder {
public:
struct JSFrameRegs entryState;
Tracker<nanojit::LIns*> tracker;
nanojit::Fragment* fragment;
nanojit::LirWriter* lir;
JSTraceRecorder(JSFrameRegs& _entryState) {
entryState = _entryState;
}
};
/*
@ -91,18 +99,14 @@ enum TraceRecorderStatus {
*/
struct JSTraceMonitor {
int freq;
TraceRecorderStatus status;
JSFrameRegs entryState;
Tracker<nanojit::LIns*> tracker;
nanojit::Fragment* fragment;
nanojit::Fragmento* fragmento;
nanojit::LirWriter* lir;
JSTraceRecorder* recorder;
};
#define ENABLE_TRACER true
#define TRACE_TRIGGER_MASK 0x3f
extern void
extern bool
js_StartRecording(JSContext* cx, JSFrameRegs& regs);
extern void

View File

@ -45,10 +45,12 @@
#undef PRIMITIVE
#define set(v, l) JS_TRACE_MONITOR(cx).tracker.set(v, l)
#define get(v) JS_TRACE_MONITOR(cx).tracker.get(v)
#define RECORDER(cx) JS_TRACE_MONITOR(cx).recorder
#define set(v, l) RECORDER(cx)->tracker.set(v, l); \
writeBack(cx, v, l);
#define get(v) RECORDER(cx)->tracker.get(v)
#define copy(a, v) set(v, get(a))
#define L (*JS_TRACE_MONITOR(cx).lir)
#define L (*(RECORDER(cx)->lir))
#define F(name) F_##name
#define G(ok) (ok ? LIR_xf : LIR_xt)
#define unary(op, a, v) set(v, L.ins1(op, get(a)))
@ -72,13 +74,28 @@
set(v, L.insCall(F(n), args)); \
JS_END_MACRO
#define STACK_OFFSET(p) (((char*)(p)) - ((char*)JS_TRACE_MONITOR(cx).entryState.sp))
#define STACK_OFFSET(p) (((char*)(p)) - ((char*)(RECORDER(cx)->entryState.sp)))
static inline void writeBack(JSContext* cx, void* p, LIns* l)
{
JSStackFrame* fp = cx->fp;
int32_t offset;
if ((p >= &fp->argv[0] && p < &fp->argv[fp->argc])) {
offset = (int32_t)((jsval*)p - fp->argv);
} else if (p >= &fp->vars[0] && p < &fp->vars[fp->nvars]) {
offset = (int32_t)((jsval*)p - fp->vars) + fp->argc;
} else if (p >= &fp->spbase[0] && p < &fp->spbase[fp->script->depth]) {
offset = (int32_t)((jsval*)p - fp->spbase) + fp->argc + fp->nvars;
} else
return;
L.insStorei(l, get(&RECORDER(cx)->entryState.sp), offset);
}
static inline SideExit*
snapshot(JSContext* cx, JSFrameRegs& regs, SideExit& exit)
{
memset(&exit, 0, sizeof(exit));
exit.from = JS_TRACE_MONITOR(cx).fragment;
exit.from = RECORDER(cx)->fragment;
return &exit;
}
@ -93,7 +110,6 @@ static inline void
prim_push_stack(JSContext* cx, JSFrameRegs& regs, jsval& v)
{
set(regs.sp, get(&v));
L.insStorei(get(&v), JS_TRACE_MONITOR(cx).fragment->param1, STACK_OFFSET(regs.sp));
interp_prim_push_stack(cx, regs, v);
}
@ -109,7 +125,6 @@ prim_store_stack(JSContext* cx, JSFrameRegs& regs, int n, jsval& v)
{
interp_prim_store_stack(cx, regs, n, v);
set(&regs.sp[n], get(&v));
L.insStorei(get(&v), JS_TRACE_MONITOR(cx).fragment->param1, STACK_OFFSET(&regs.sp[n]));
}
static inline void
@ -594,6 +609,7 @@ prim_do_fast_inc_dec(JSContext* cx, jsval& a, jsval incr, jsval& r)
set(&r, L.ins2(LIR_add, get(&a), L.insImm(incr/2)));
}
#undef recorder
#undef set
#undef get
#undef copy