mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 13:55:43 +00:00
Bug 458838: enable tracing of upvar accesses that go outside the current trace to interpreter state, r=gal
This commit is contained in:
parent
a9c94fc9f3
commit
f0a30c0e9c
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user