Bug 458838: enable tracing of upvar accesses that go outside the current trace to interpreter state, r=gal

This commit is contained in:
David Mandelin 2009-05-11 18:05:44 -07:00
parent a9c94fc9f3
commit f0a30c0e9c
3 changed files with 101 additions and 5 deletions

View File

@ -211,6 +211,7 @@ struct JSTraceableNative {
#define _JS_CTYPE_INTERPSTATE _JS_CTYPE(InterpState *, _JS_PTR, --, --, INFALLIBLE)
#define _JS_CTYPE_FRAGMENT _JS_CTYPE(nanojit::Fragment *, _JS_PTR, --, --, INFALLIBLE)
#define _JS_CTYPE_CLASS _JS_CTYPE(JSClass *, _JS_PTR, --, --, INFALLIBLE)
#define _JS_CTYPE_DOUBLEPTR _JS_CTYPE(double *, _JS_PTR, --, --, INFALLIBLE)
#define _JS_EXPAND(tokens) tokens

View File

@ -367,7 +367,7 @@ Tracker::set(const void* v, LIns* i)
p->map[(jsuword(v) & PAGEMASK) >> 2] = i;
}
static inline jsint argSlots(JSStackFrame* fp)
static inline jsuint argSlots(JSStackFrame* fp)
{
return JS_MAX(fp->argc, fp->fun->nargs);
}
@ -1238,7 +1238,7 @@ TypeMap::captureTypes(JSContext* cx, SlotList& slots, unsigned callDepth)
if ((type == JSVAL_INT) && oracle.isStackSlotUndemotable(cx, unsigned(m - map)))
type = JSVAL_DOUBLE;
JS_ASSERT(type != JSVAL_BOXED);
debug_only_v(printf("capture stack type %s%d: %d=%c vp=%p v=%x\n", vpname, vpnum, type, typeChar[type], vp, (uint32) *vp);)
debug_only_v(printf("capture stack type %s%d: %d=%c\n", vpname, vpnum, type, typeChar[type], vp, (uint32) *vp);)
JS_ASSERT(uintptr_t(m - map) < length());
*m++ = type;
);
@ -1838,6 +1838,47 @@ FlushNativeGlobalFrame(JSContext* cx, unsigned ngslots, uint16* gslots, uint8* m
return mp - mp_base;
}
/*
* Builtin to get an upvar on trace. See js_GetUpvar for the meaning
* of the first three arguments. The value of the upvar is stored in
* *result as an unboxed native. The return value is the typemap type.
*/
uint32 JS_FASTCALL
js_GetUpvarOnTrace(JSContext *cx, uint32 level, uint32 cookie, double* result)
{
uintN skip = UPVAR_FRAME_SKIP(cookie);
InterpState* state = cx->interpState;
uintN callDepth = state->rp - state->callstackBase;
/*
* If we are skipping past all frames that are part of active traces,
* then we simply get the value from the interpreter state.
*/
if (skip > callDepth) {
jsval v = js_GetUpvar(cx, level, cookie);
uint8 type = getCoercedType(v);
ValueToNative(cx, v, type, result);
return type;
}
/*
* The value we need is logically in a stack frame that is part of
* an active trace. We reconstruct the value we need from the tracer
* stack records.
*/
uintN frameIndex = callDepth - skip; // pos of target frame in rp stack
uintN nativeStackFramePos = 0; // pos of target stack frame in sp stack
for (uintN i = 0; i < frameIndex; ++i)
nativeStackFramePos += state->callstackBase[i]->s.spdist;
FrameInfo* fi = state->callstackBase[frameIndex];
uint8* typemap = (uint8*) (fi+1);
uintN slot = UPVAR_FRAME_SLOT(cookie);
slot = slot == CALLEE_UPVAR_SLOT ? 0 : slot + 2;
*result = state->stackBase[nativeStackFramePos + slot];
return typemap[slot];
}
/**
* Box the given native stack frame into the virtual machine stack. This
* is infallible.
@ -8282,6 +8323,8 @@ TraceRecorder::record_JSOP_CALLNAME()
return JSRS_CONTINUE;
}
JS_DEFINE_CALLINFO_4(extern, UINT32, js_GetUpvarOnTrace, CONTEXT, UINT32, UINT32, DOUBLEPTR, 0, 0)
JS_REQUIRES_STACK JSRecordingStatus
TraceRecorder::record_JSOP_GETUPVAR()
{
@ -8292,9 +8335,61 @@ TraceRecorder::record_JSOP_GETUPVAR()
JS_ASSERT(index < uva->length);
uintN skip = UPVAR_FRAME_SKIP(uva->vector[index]);
if (skip > callDepth)
ABORT_TRACE("upvar out of reach");
if (skip > callDepth) {
/*
* The frame containing the upvar is not part of the trace, so we
* get the upvar value exactly as the interpreter does and unbox.
*/
jsval v = js_GetUpvar(cx, script->staticLevel, uva->vector[index]);
uint8 type = getCoercedType(v);
LIns* outp = lir->insAlloc(sizeof(double));
LIns* args[] = {
outp,
lir->insImm(uva->vector[index]),
lir->insImm(script->staticLevel),
cx_ins
};
const CallInfo* ci = &js_GetUpvarOnTrace_ci;
LIns* call_ins = lir->insCall(ci, args);
guard(true,
addName(lir->ins2(LIR_eq, call_ins, lir->insImm(type)),
"guard(type-stable upvar)"),
BRANCH_EXIT);
LOpcode loadOp;
switch (type) {
case JSVAL_DOUBLE:
loadOp = LIR_ldq;
break;
case JSVAL_OBJECT:
case JSVAL_STRING:
case JSVAL_TFUN:
case JSVAL_TNULL:
loadOp = LIR_ldp;
break;
case JSVAL_INT:
case JSVAL_BOOLEAN:
loadOp = LIR_ld;
break;
case JSVAL_BOXED:
default:
JS_NOT_REACHED("found boxed type in an upvar type map entry");
return JSRS_STOP;
}
LIns* result = lir->insLoad(loadOp, outp, lir->insImm(0));
if (type == JSVAL_INT)
result = lir->ins1(LIR_i2f, result);
stack(0, result);
return JSRS_CONTINUE;
}
/*
* At this point, the frame containing the upvar is part of the trace,
* so the upvar is in the tracker. We only need to update the tracker.
*/
JSStackFrame* fp2 = cx->display[script->staticLevel - skip];
JS_ASSERT(fp2->script);

View File

@ -367,7 +367,7 @@ typedef enum JSBuiltinStatus {
struct InterpState
{
double *sp; // native stack pointer, stack[0] is spbase[0]
void *rp; // call stack pointer
FrameInfo** rp; // call stack pointer
JSContext *cx; // current VM context handle
double *eos; // first unusable word after the native stack
void *eor; // first unusable word after the call stack