mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Removed callee from FrameInfo, and fixed upvar bugs in stack reconstruction (bug 510300, r=dmandelin,brendan).
This commit is contained in:
parent
cad54739ba
commit
bed67e910c
@ -2358,6 +2358,22 @@ FlushNativeGlobalFrame(JSContext *cx, double *global, unsigned ngslots,
|
|||||||
debug_only_print0(LC_TMTracer, "\n");
|
debug_only_print0(LC_TMTracer, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the number of values on the native stack, excluding the innermost
|
||||||
|
* frame. This walks all FrameInfos on the native frame stack and sums the
|
||||||
|
* slot usage of each frame.
|
||||||
|
*/
|
||||||
|
static int32
|
||||||
|
StackDepthFromCallStack(InterpState* state, uint32 callDepth)
|
||||||
|
{
|
||||||
|
int32 nativeStackFramePos = 0;
|
||||||
|
|
||||||
|
// Duplicate native stack layout computation: see VisitFrameSlots header comment.
|
||||||
|
for (FrameInfo** fip = state->callstackBase; fip < state->rp + callDepth; fip++)
|
||||||
|
nativeStackFramePos += (*fip)->callerHeight;
|
||||||
|
return nativeStackFramePos;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic function to read upvars on trace from slots of active frames.
|
* Generic function to read upvars on trace from slots of active frames.
|
||||||
* T Traits type parameter. Must provide static functions:
|
* T Traits type parameter. Must provide static functions:
|
||||||
@ -2377,27 +2393,34 @@ GetUpvarOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDepth,
|
|||||||
FrameInfo** fip = state->rp + callDepth;
|
FrameInfo** fip = state->rp + callDepth;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First search the FrameInfo call stack for an entry containing
|
* First search the FrameInfo call stack for an entry containing our
|
||||||
* our upvar, namely one with level == upvarLevel.
|
* upvar, namely one with level == upvarLevel. The first FrameInfo is a
|
||||||
|
* transition from the entry frame to some callee. However, it is not
|
||||||
|
* known (from looking at the FrameInfo) whether the entry frame had a
|
||||||
|
* callee. Rather than special-case this or insert more logic into the
|
||||||
|
* loop, instead just stop before that FrameInfo (i.e. |> base| instead of
|
||||||
|
* |>= base|), and let the code after the loop handle it.
|
||||||
*/
|
*/
|
||||||
while (--fip >= state->callstackBase) {
|
int32 stackOffset = StackDepthFromCallStack(state, callDepth);
|
||||||
|
while (--fip > state->callstackBase) {
|
||||||
FrameInfo* fi = *fip;
|
FrameInfo* fi = *fip;
|
||||||
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, fi->callee);
|
|
||||||
|
/*
|
||||||
|
* The loop starts aligned to the top of the stack, so move down to the first meaningful
|
||||||
|
* callee. Then read the callee directly from the frame.
|
||||||
|
*/
|
||||||
|
stackOffset -= fi->callerHeight;
|
||||||
|
JSObject* callee = *(JSObject**)(&state->stackBase[stackOffset]);
|
||||||
|
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, callee);
|
||||||
uintN calleeLevel = fun->u.i.script->staticLevel;
|
uintN calleeLevel = fun->u.i.script->staticLevel;
|
||||||
if (calleeLevel == upvarLevel) {
|
if (calleeLevel == upvarLevel) {
|
||||||
/*
|
/*
|
||||||
* Now find the upvar's value in the native stack.
|
* Now find the upvar's value in the native stack. stackOffset is
|
||||||
* nativeStackFramePos is the offset of the start of the
|
* the offset of the start of the activation record corresponding
|
||||||
* activation record corresponding to *fip in the native
|
* to *fip in the native stack.
|
||||||
* stack.
|
|
||||||
*/
|
*/
|
||||||
int32 nativeStackFramePos = state->callstackBase[0]->spoffset;
|
uint32 native_slot = T::native_slot(fi->callerArgc, slot);
|
||||||
// Duplicate native stack layout computation: see VisitFrameSlots header comment.
|
*result = state->stackBase[stackOffset + native_slot];
|
||||||
for (FrameInfo** fip2 = state->callstackBase; fip2 <= fip; fip2++)
|
|
||||||
nativeStackFramePos += (*fip2)->spdist + 1 /* arguments */;
|
|
||||||
nativeStackFramePos -= (3 /* callee,this,arguments */ + (*fip)->get_argc());
|
|
||||||
uint32 native_slot = T::native_slot((*fip)->get_argc(), slot);
|
|
||||||
*result = state->stackBase[nativeStackFramePos + native_slot];
|
|
||||||
return fi->get_typemap()[native_slot];
|
return fi->get_typemap()[native_slot];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2477,7 +2500,8 @@ struct UpvarStackTraits {
|
|||||||
};
|
};
|
||||||
|
|
||||||
uint32 JS_FASTCALL
|
uint32 JS_FASTCALL
|
||||||
GetUpvarStackOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDepth, double* result)
|
GetUpvarStackOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDepth,
|
||||||
|
double* result)
|
||||||
{
|
{
|
||||||
return GetUpvarOnTrace<UpvarStackTraits>(cx, upvarLevel, slot, callDepth, result);
|
return GetUpvarOnTrace<UpvarStackTraits>(cx, upvarLevel, slot, callDepth, result);
|
||||||
}
|
}
|
||||||
@ -2505,10 +2529,14 @@ GetFromClosure(JSContext* cx, JSObject* callee, uint32 scopeIndex, uint32 slot,
|
|||||||
JS_ASSERT(OBJ_GET_CLASS(cx, call) == &js_CallClass);
|
JS_ASSERT(OBJ_GET_CLASS(cx, call) == &js_CallClass);
|
||||||
|
|
||||||
InterpState* state = cx->interpState;
|
InterpState* state = cx->interpState;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
int32 stackOffset = StackDepthFromCallStack(state, callDepth);
|
||||||
FrameInfo** fip = state->rp + callDepth;
|
FrameInfo** fip = state->rp + callDepth;
|
||||||
while (--fip >= state->callstackBase) {
|
while (--fip > state->callstackBase) {
|
||||||
FrameInfo* fi = *fip;
|
FrameInfo* fi = *fip;
|
||||||
if (fi->callee == call) {
|
JSObject* callee = *(JSObject**)(&state->stackBase[stackOffset]);
|
||||||
|
if (callee == call) {
|
||||||
// This is not reachable as long as JSOP_LAMBDA is not traced:
|
// This is not reachable as long as JSOP_LAMBDA is not traced:
|
||||||
// - The upvar is found at this point only if the upvar was defined on a frame that was
|
// - The upvar is found at this point only if the upvar was defined on a frame that was
|
||||||
// entered on this trace.
|
// entered on this trace.
|
||||||
@ -2518,7 +2546,9 @@ GetFromClosure(JSContext* cx, JSObject* callee, uint32 scopeIndex, uint32 slot,
|
|||||||
// is on the trace.
|
// is on the trace.
|
||||||
JS_NOT_REACHED("JSOP_NAME variable found in outer trace");
|
JS_NOT_REACHED("JSOP_NAME variable found in outer trace");
|
||||||
}
|
}
|
||||||
|
stackOffset -= fi->callerHeight;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we specifically want to check the call object of the trace entry frame.
|
* Here we specifically want to check the call object of the trace entry frame.
|
||||||
@ -4544,13 +4574,11 @@ TrashTree(JSContext* cx, Fragment* f)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
SynthesizeFrame(JSContext* cx, const FrameInfo& fi)
|
SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee)
|
||||||
{
|
{
|
||||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||||
|
|
||||||
JS_ASSERT(HAS_FUNCTION_CLASS(fi.callee));
|
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, callee);
|
||||||
|
|
||||||
JSFunction* fun = GET_FUNCTION_PRIVATE(cx, fi.callee);
|
|
||||||
JS_ASSERT(FUN_INTERPRETED(fun));
|
JS_ASSERT(FUN_INTERPRETED(fun));
|
||||||
|
|
||||||
/* Assert that we have a correct sp distance from cx->fp->slots in fi. */
|
/* Assert that we have a correct sp distance from cx->fp->slots in fi. */
|
||||||
@ -4625,7 +4653,7 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi)
|
|||||||
newifp->frame.argsobj = NULL;
|
newifp->frame.argsobj = NULL;
|
||||||
newifp->frame.varobj = NULL;
|
newifp->frame.varobj = NULL;
|
||||||
newifp->frame.script = script;
|
newifp->frame.script = script;
|
||||||
newifp->frame.callee = fi.callee; // Roll with a potentially stale callee for now.
|
newifp->frame.callee = callee;
|
||||||
newifp->frame.fun = fun;
|
newifp->frame.fun = fun;
|
||||||
|
|
||||||
bool constructing = fi.is_constructing();
|
bool constructing = fi.is_constructing();
|
||||||
@ -5713,12 +5741,16 @@ LeaveTree(InterpState& state, VMSideExit* lr)
|
|||||||
|
|
||||||
JS_ARENA_RELEASE(&cx->stackPool, state.stackMark);
|
JS_ARENA_RELEASE(&cx->stackPool, state.stackMark);
|
||||||
while (callstack < rp) {
|
while (callstack < rp) {
|
||||||
|
FrameInfo* fi = *callstack;
|
||||||
|
/* Peek at the callee native slot in the not-yet-synthesized down frame. */
|
||||||
|
JSObject* callee = *(JSObject**)&stack[fi->callerHeight];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Synthesize a stack frame and write out the values in it using the
|
* Synthesize a stack frame and write out the values in it using the
|
||||||
* type map pointer on the native call stack.
|
* type map pointer on the native call stack.
|
||||||
*/
|
*/
|
||||||
SynthesizeFrame(cx, **callstack);
|
SynthesizeFrame(cx, *fi, callee);
|
||||||
int slots = FlushNativeStackFrame(cx, 1 /* callDepth */, (JSTraceType*)(*callstack + 1),
|
int slots = FlushNativeStackFrame(cx, 1 /* callDepth */, (JSTraceType*)(fi + 1),
|
||||||
stack, cx->fp);
|
stack, cx->fp);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JSStackFrame* fp = cx->fp;
|
JSStackFrame* fp = cx->fp;
|
||||||
@ -5746,8 +5778,14 @@ LeaveTree(InterpState& state, VMSideExit* lr)
|
|||||||
JS_ASSERT(rp == callstack);
|
JS_ASSERT(rp == callstack);
|
||||||
unsigned calldepth = innermost->calldepth;
|
unsigned calldepth = innermost->calldepth;
|
||||||
unsigned calldepth_slots = 0;
|
unsigned calldepth_slots = 0;
|
||||||
|
unsigned calleeOffset = 0;
|
||||||
for (unsigned n = 0; n < calldepth; ++n) {
|
for (unsigned n = 0; n < calldepth; ++n) {
|
||||||
calldepth_slots += SynthesizeFrame(cx, *callstack[n]);
|
/* Peek at the callee native slot in the not-yet-synthesized down frame. */
|
||||||
|
calleeOffset += callstack[n]->callerHeight;
|
||||||
|
JSObject* callee = *(JSObject**)&stack[calleeOffset];
|
||||||
|
|
||||||
|
/* Reconstruct the frame. */
|
||||||
|
calldepth_slots += SynthesizeFrame(cx, *callstack[n], callee);
|
||||||
++*state.inlineCallCountp;
|
++*state.inlineCallCountp;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JSStackFrame* fp = cx->fp;
|
JSStackFrame* fp = cx->fp;
|
||||||
@ -10621,10 +10659,8 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc,
|
|||||||
DetermineTypesVisitor detVisitor(*this, typemap);
|
DetermineTypesVisitor detVisitor(*this, typemap);
|
||||||
VisitStackSlots(detVisitor, cx, 0);
|
VisitStackSlots(detVisitor, cx, 0);
|
||||||
|
|
||||||
if (argc >= 0x8000)
|
JS_ASSERT(argc < FrameInfo::CONSTRUCTING_FLAG);
|
||||||
ABORT_TRACE("too many arguments");
|
|
||||||
|
|
||||||
fi->callee = JSVAL_TO_OBJECT(fval);
|
|
||||||
treeInfo->gcthings.addUnique(fval);
|
treeInfo->gcthings.addUnique(fval);
|
||||||
fi->block = fp->blockChain;
|
fi->block = fp->blockChain;
|
||||||
if (fp->blockChain)
|
if (fp->blockChain)
|
||||||
@ -10633,13 +10669,12 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc,
|
|||||||
fi->imacpc = fp->imacpc;
|
fi->imacpc = fp->imacpc;
|
||||||
fi->spdist = fp->regs->sp - fp->slots;
|
fi->spdist = fp->regs->sp - fp->slots;
|
||||||
fi->set_argc(argc, constructing);
|
fi->set_argc(argc, constructing);
|
||||||
fi->spoffset = 2 /*callee,this*/ + fp->argc;
|
fi->callerHeight = NativeStackSlots(cx, 0) - (2 + argc);
|
||||||
|
fi->callerArgc = fp->argc;
|
||||||
|
|
||||||
unsigned callDepth = getCallDepth();
|
unsigned callDepth = getCallDepth();
|
||||||
if (callDepth >= treeInfo->maxCallDepth)
|
if (callDepth >= treeInfo->maxCallDepth)
|
||||||
treeInfo->maxCallDepth = callDepth + 1;
|
treeInfo->maxCallDepth = callDepth + 1;
|
||||||
if (callDepth == 0)
|
|
||||||
fi->spoffset = -fp->script->nfixed;
|
|
||||||
|
|
||||||
lir->insStorei(INS_CONSTPTR(fi), lirbuf->rp, callDepth * sizeof(FrameInfo*));
|
lir->insStorei(INS_CONSTPTR(fi), lirbuf->rp, callDepth * sizeof(FrameInfo*));
|
||||||
|
|
||||||
|
@ -483,36 +483,37 @@ struct REHashFn {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct FrameInfo {
|
struct FrameInfo {
|
||||||
JSObject* callee; // callee function object
|
|
||||||
JSObject* block; // caller block chain head
|
JSObject* block; // caller block chain head
|
||||||
jsbytecode* pc; // caller fp->regs->pc
|
jsbytecode* pc; // caller fp->regs->pc
|
||||||
jsbytecode* imacpc; // caller fp->imacpc
|
jsbytecode* imacpc; // caller fp->imacpc
|
||||||
uint16 spdist; // distance from fp->slots to fp->regs->sp at JSOP_CALL
|
uint32 spdist; // distance from fp->slots to fp->regs->sp at JSOP_CALL
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bit 15 (0x8000) is a flag that is set if constructing (called through new).
|
* Bit 15 (0x8000) is a flag that is set if constructing (called through new).
|
||||||
* Bits 0-14 are the actual argument count. This may be less than fun->nargs.
|
* Bits 0-14 are the actual argument count. This may be less than fun->nargs.
|
||||||
|
* NB: This is argc for the callee, not the caller.
|
||||||
*/
|
*/
|
||||||
uint16 argc;
|
uint32 argc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stack pointer adjustment needed for navigation of native stack in
|
* Number of stack slots in the caller, not counting slots pushed when
|
||||||
* js_GetUpvarOnTrace. spoffset is the number of slots in the native
|
* invoking the callee. That is, slots after JSOP_CALL completes but
|
||||||
* stack frame for the caller *before* the slots covered by spdist.
|
* without the return value. This is also equal to the number of slots
|
||||||
* This may be negative if the caller is the top level script.
|
* between fp->down->argv[-2] (calleR fp->callee) and fp->argv[-2]
|
||||||
* The key fact is that if we let 'cpos' be the start of the caller's
|
* (calleE fp->callee).
|
||||||
* native stack frame, then (cpos + spoffset) points to the first
|
|
||||||
* non-argument slot in the callee's native stack frame.
|
|
||||||
*/
|
*/
|
||||||
int32 spoffset;
|
uint32 callerHeight;
|
||||||
|
|
||||||
|
/* argc of the caller */
|
||||||
|
uint32 callerArgc;
|
||||||
|
|
||||||
// Safer accessors for argc.
|
// Safer accessors for argc.
|
||||||
enum { CONSTRUCTING_MASK = 0x8000 };
|
enum { CONSTRUCTING_FLAG = 0x10000 };
|
||||||
void set_argc(uint16 argc, bool constructing) {
|
void set_argc(uint16 argc, bool constructing) {
|
||||||
this->argc = argc | (constructing ? CONSTRUCTING_MASK : 0);
|
this->argc = uint32(argc) | (constructing ? CONSTRUCTING_FLAG: 0);
|
||||||
}
|
}
|
||||||
uint16 get_argc() const { return argc & ~CONSTRUCTING_MASK; }
|
uint16 get_argc() const { return argc & ~CONSTRUCTING_FLAG; }
|
||||||
bool is_constructing() const { return (argc & CONSTRUCTING_MASK) != 0; }
|
bool is_constructing() const { return (argc & CONSTRUCTING_FLAG) != 0; }
|
||||||
|
|
||||||
// The typemap just before the callee is called.
|
// The typemap just before the callee is called.
|
||||||
JSTraceType* get_typemap() { return (JSTraceType*) (this+1); }
|
JSTraceType* get_typemap() { return (JSTraceType*) (this+1); }
|
||||||
|
Loading…
Reference in New Issue
Block a user