mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-01 05:48:26 +00:00
Properly compute 'this' object on trace and wrap if necessary (488203, r=mrbkap).
This commit is contained in:
parent
087d5e2840
commit
28ae2c328d
@ -4364,15 +4364,8 @@ js_Interpret(JSContext *cx)
|
||||
|
||||
#define COMPUTE_THIS(cx, fp, obj) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (fp->flags & JSFRAME_COMPUTED_THIS) { \
|
||||
obj = fp->thisp; \
|
||||
} else { \
|
||||
obj = js_ComputeThis(cx, JS_TRUE, fp->argv); \
|
||||
if (!obj) \
|
||||
goto error; \
|
||||
fp->thisp = obj; \
|
||||
fp->flags |= JSFRAME_COMPUTED_THIS; \
|
||||
} \
|
||||
if (!(obj = js_ComputeThisForFrame(cx, fp))) \
|
||||
goto error; \
|
||||
JS_END_MACRO
|
||||
|
||||
BEGIN_CASE(JSOP_THIS)
|
||||
|
@ -466,6 +466,19 @@ extern const uint16 js_PrimitiveTestFlags[];
|
||||
JSFUN_THISP_TEST(JSFUN_THISP_FLAGS((fun)->flags), \
|
||||
js_PrimitiveTestFlags[JSVAL_TAG(thisv) - 1]))
|
||||
|
||||
static inline JSObject *
|
||||
js_ComputeThisForFrame(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
if (fp->flags & JSFRAME_COMPUTED_THIS)
|
||||
return fp->thisp;
|
||||
JSObject* obj = js_ComputeThis(cx, JS_TRUE, fp->argv);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
fp->thisp = obj;
|
||||
fp->flags |= JSFRAME_COMPUTED_THIS;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: js_Invoke requires that cx is currently running JS (i.e., that cx->fp
|
||||
* is non-null), and that vp points to the callee, |this| parameter, and
|
||||
|
@ -1743,9 +1743,11 @@ skip:
|
||||
}
|
||||
for (; n != 0; fp = fp->down) {
|
||||
--n;
|
||||
if (fp->callee) { // might not have it if the entry frame is global
|
||||
if (fp->callee) {
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(fp->argv[-1]));
|
||||
fp->thisp = JSVAL_TO_OBJECT(fp->argv[-1]);
|
||||
if (fp->flags & JSFRAME_CONSTRUCTING) // constructors always compute 'this'
|
||||
fp->flags |= JSFRAME_COMPUTED_THIS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3390,7 +3392,7 @@ js_SynthesizeFrame(JSContext* cx, const FrameInfo& fi)
|
||||
newifp->frame.xmlNamespace = NULL;
|
||||
newifp->frame.blockChain = NULL;
|
||||
newifp->mark = newmark;
|
||||
newifp->frame.thisp = NULL; // will be set by js_ExecuteTree -> FlushNativeStackFrame
|
||||
newifp->frame.thisp = NULL; // will be updated in FlushNativeStackFrame
|
||||
|
||||
newifp->frame.regs = fp->regs;
|
||||
newifp->frame.regs->pc = script->code;
|
||||
@ -4348,8 +4350,6 @@ LeaveTree(InterpState& state, VMSideExit* lr)
|
||||
// Verify that our state restoration worked.
|
||||
for (JSStackFrame* fp = cx->fp; fp; fp = fp->down) {
|
||||
JS_ASSERT_IF(fp->callee, JSVAL_IS_OBJECT(fp->argv[-1]));
|
||||
JS_ASSERT_IF(fp->callee && fp->thisp != JSVAL_TO_OBJECT(fp->argv[-1]),
|
||||
!(fp->flags & JSFRAME_COMPUTED_THIS) && !fp->thisp);
|
||||
}
|
||||
#endif
|
||||
#ifdef JS_JIT_SPEW
|
||||
@ -6236,17 +6236,44 @@ TraceRecorder::unbox_jsval(jsval v, LIns*& v_ins, LIns* exit)
|
||||
}
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
ComputeThis_tn(JSContext* cx)
|
||||
{
|
||||
return js_ComputeThisForFrame(cx, cx->fp);
|
||||
}
|
||||
|
||||
JS_DEFINE_CALLINFO_1(static, OBJECT, ComputeThis_tn, CONTEXT, 1, 1) /* safe to CSE */
|
||||
|
||||
JS_REQUIRES_STACK bool
|
||||
TraceRecorder::getThis(LIns*& this_ins)
|
||||
{
|
||||
if (cx->fp->callee) { /* in a function */
|
||||
if (JSVAL_IS_NULL(cx->fp->argv[-1]))
|
||||
return false;
|
||||
this_ins = get(&cx->fp->argv[-1]);
|
||||
guard(false, lir->ins_eq0(this_ins), MISMATCH_EXIT);
|
||||
} else { /* in global code */
|
||||
this_ins = scopeChain();
|
||||
JSObject* thisObj = js_ComputeThisForFrame(cx, cx->fp);
|
||||
if (!thisObj)
|
||||
ABORT_TRACE("js_ComputeThis failed");
|
||||
if (!cx->fp->callee || JSVAL_IS_NULL(cx->fp->argv[-1])) {
|
||||
JS_ASSERT(callDepth == 0);
|
||||
/*
|
||||
* In global code, or if this is NULL, wrap the global object and bake it directly
|
||||
* into the trace.
|
||||
*/
|
||||
this_ins = INS_CONSTPTR(thisObj);
|
||||
set(&cx->fp->argv[-1], this_ins);
|
||||
return true;
|
||||
}
|
||||
if (callDepth == 0) {
|
||||
/*
|
||||
* Check that we computed the 'this' object for the entry frame. We only have to worry
|
||||
* about this for callDepth == 0 since inlined function calls are not subject to
|
||||
* deferred wrapping as we do not trace across global objects. Note that for nested
|
||||
* tree calls the current cx->fp might not be the current entry frame of the called
|
||||
* tree, however, since we don't cross global objects, we can call js_ComputeThis
|
||||
* on that frame to ensure that the global object was wrapped, and that guarantee than
|
||||
* inductively extends to our current 'this' object.
|
||||
*/
|
||||
LIns* args = { cx_ins };
|
||||
guard(false, lir->ins_eq0(lir->insCall(&ComputeThis_tn_ci, &args)), MISMATCH_EXIT);
|
||||
}
|
||||
this_ins = get(&cx->fp->argv[-1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user