mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge backout.
This commit is contained in:
commit
37d6a810f7
@ -4602,8 +4602,11 @@ JS_PUBLIC_API(JSBool)
|
||||
JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
JSBool ok;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
JSBool ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(FUN_OBJECT(fun)), argc, argv, rval);
|
||||
ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(FUN_OBJECT(fun)), argc, argv,
|
||||
rval);
|
||||
LAST_FRAME_CHECKS(cx, ok);
|
||||
return ok;
|
||||
}
|
||||
@ -4627,8 +4630,10 @@ JS_PUBLIC_API(JSBool)
|
||||
JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
JSBool ok;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
JSBool ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
|
||||
ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
|
||||
LAST_FRAME_CHECKS(cx, ok);
|
||||
return ok;
|
||||
}
|
||||
|
@ -864,7 +864,8 @@ JS_InitCTypesClass(JSContext *cx, JSObject *global);
|
||||
*/
|
||||
#define JS_CALLEE(cx,vp) ((vp)[0])
|
||||
#define JS_ARGV_CALLEE(argv) ((argv)[-2])
|
||||
#define JS_THIS_OBJECT(cx,vp) JSVAL_TO_OBJECT(JS_THIS(cx,vp))
|
||||
#define JS_THIS(cx,vp) JS_ComputeThis(cx, vp)
|
||||
#define JS_THIS_OBJECT(cx,vp) ((JSObject *) JS_THIS(cx,vp))
|
||||
#define JS_ARGV(cx,vp) ((vp) + 2)
|
||||
#define JS_RVAL(cx,vp) (*(vp))
|
||||
#define JS_SET_RVAL(cx,vp,v) (*(vp) = (v))
|
||||
@ -872,12 +873,6 @@ JS_InitCTypesClass(JSContext *cx, JSObject *global);
|
||||
extern JS_PUBLIC_API(jsval)
|
||||
JS_ComputeThis(JSContext *cx, jsval *vp);
|
||||
|
||||
static JS_ALWAYS_INLINE jsval
|
||||
JS_THIS(JSContext *cx, jsval *vp)
|
||||
{
|
||||
return JSVAL_IS_PRIMITIVE(vp[1]) ? JS_ComputeThis(cx, vp) : vp[1];
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(void *)
|
||||
JS_malloc(JSContext *cx, size_t nbytes);
|
||||
|
||||
|
@ -240,6 +240,17 @@ js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Some objects (e.g., With) delegate 'this' to another object. */
|
||||
static inline JSObject *
|
||||
CallThisObjectHook(JSContext *cx, JSObject *obj, jsval *argv)
|
||||
{
|
||||
JSObject *thisp = obj->thisObject(cx);
|
||||
if (!thisp)
|
||||
return NULL;
|
||||
argv[-1] = OBJECT_TO_JSVAL(thisp);
|
||||
return thisp;
|
||||
}
|
||||
|
||||
/*
|
||||
* ECMA requires "the global object", but in embeddings such as the browser,
|
||||
* which have multiple top-level objects (windows, frames, etc. in the DOM),
|
||||
@ -258,10 +269,36 @@ js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp)
|
||||
JS_STATIC_INTERPRET JSObject *
|
||||
js_ComputeGlobalThis(JSContext *cx, jsval *argv)
|
||||
{
|
||||
JSObject *thisp = JSVAL_TO_OBJECT(argv[-2])->getGlobal()->thisObject(cx);
|
||||
if (thisp)
|
||||
argv[-1] = OBJECT_TO_JSVAL(thisp);
|
||||
return thisp;
|
||||
JSObject *thisp;
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(argv[-2]) ||
|
||||
!JSVAL_TO_OBJECT(argv[-2])->getParent()) {
|
||||
thisp = cx->globalObject;
|
||||
} else {
|
||||
thisp = JSVAL_TO_OBJECT(argv[-2])->getGlobal();
|
||||
}
|
||||
|
||||
return CallThisObjectHook(cx, thisp, argv);
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
ComputeThis(JSContext *cx, jsval *argv)
|
||||
{
|
||||
JSObject *thisp;
|
||||
|
||||
JS_ASSERT(!JSVAL_IS_NULL(argv[-1]));
|
||||
if (!JSVAL_IS_OBJECT(argv[-1])) {
|
||||
if (!js_PrimitiveToObject(cx, &argv[-1]))
|
||||
return NULL;
|
||||
thisp = JSVAL_TO_OBJECT(argv[-1]);
|
||||
return thisp;
|
||||
}
|
||||
|
||||
thisp = JSVAL_TO_OBJECT(argv[-1]);
|
||||
if (thisp->getClass() == &js_CallClass || thisp->getClass() == &js_BlockClass)
|
||||
return js_ComputeGlobalThis(cx, argv);
|
||||
|
||||
return CallThisObjectHook(cx, thisp, argv);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
@ -270,28 +307,7 @@ js_ComputeThis(JSContext *cx, jsval *argv)
|
||||
JS_ASSERT(argv[-1] != JSVAL_HOLE); // check for SynthesizeFrame poisoning
|
||||
if (JSVAL_IS_NULL(argv[-1]))
|
||||
return js_ComputeGlobalThis(cx, argv);
|
||||
if (!JSVAL_IS_OBJECT(argv[-1])) {
|
||||
if (!js_PrimitiveToObject(cx, &argv[-1]))
|
||||
return NULL;
|
||||
return JSVAL_TO_OBJECT(argv[-1]);
|
||||
}
|
||||
|
||||
JSObject *obj = JSVAL_TO_OBJECT(argv[-1]);
|
||||
JS_ASSERT(js_IsSaneThisObject(obj));
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
JSStackFrame::computeThisObject(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(JSVAL_IS_PRIMITIVE(thisv));
|
||||
JS_ASSERT(fun);
|
||||
|
||||
JSObject *obj = js_ComputeThis(cx, argv);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
thisv = OBJECT_TO_JSVAL(obj);
|
||||
return obj;
|
||||
return ComputeThis(cx, argv);
|
||||
}
|
||||
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
@ -502,6 +518,26 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & JSINVOKE_CONSTRUCT) {
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
|
||||
} else {
|
||||
/*
|
||||
* We must call js_ComputeThis in case we are not called from the
|
||||
* interpreter, where a prior bytecode has computed an appropriate
|
||||
* |this| already.
|
||||
*
|
||||
* But we need to compute |this| eagerly only for so-called "slow"
|
||||
* (i.e., not fast) native functions. Fast natives must use either
|
||||
* JS_THIS or JS_THIS_OBJECT, and scripted functions will go through
|
||||
* the appropriate this-computing bytecode, e.g., JSOP_THIS.
|
||||
*/
|
||||
if (native && (!fun || !(fun->flags & JSFUN_FAST_NATIVE))) {
|
||||
if (!js_ComputeThis(cx, vp + 2))
|
||||
return false;
|
||||
flags |= JSFRAME_COMPUTED_THIS;
|
||||
}
|
||||
}
|
||||
|
||||
start_call:
|
||||
if (native && fun && fun->isFastNative()) {
|
||||
#ifdef DEBUG_NOT_THROWING
|
||||
@ -531,6 +567,7 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
|
||||
nmissing = (minargs > argc ? minargs - argc : 0) + fun->u.n.extra;
|
||||
nvars = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
nvars = nmissing = 0;
|
||||
}
|
||||
@ -598,27 +635,6 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute |this|. Currently, this must happen after the frame is pushed
|
||||
* and fp->scopeChain is correct because the thisObject hook may call
|
||||
* JS_GetScopeChain.
|
||||
*/
|
||||
JS_ASSERT_IF(flags & JSINVOKE_CONSTRUCT, !JSVAL_IS_PRIMITIVE(vp[1]));
|
||||
if (JSVAL_IS_OBJECT(vp[1]) && !(flags & JSINVOKE_CONSTRUCT)) {
|
||||
/*
|
||||
* We must call the thisObject hook in case we are not called from the
|
||||
* interpreter, where a prior bytecode has computed an appropriate
|
||||
* |this| already.
|
||||
*/
|
||||
JSObject *thisp = JSVAL_TO_OBJECT(vp[1]);
|
||||
thisp = thisp ? thisp : funobj->getGlobal();
|
||||
thisp = thisp->thisObject(cx);
|
||||
if (!thisp)
|
||||
return false;
|
||||
fp->thisv = vp[1] = OBJECT_TO_JSVAL(thisp);
|
||||
}
|
||||
JS_ASSERT_IF(!JSVAL_IS_PRIMITIVE(vp[1]), js_IsSaneThisObject(JSVAL_TO_OBJECT(vp[1])));
|
||||
|
||||
/* Call the hook if present after we fully initialized the frame. */
|
||||
JSInterpreterHook hook = cx->debugHooks->callHook;
|
||||
void *hookData = NULL;
|
||||
@ -772,7 +788,7 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script,
|
||||
fp->argsobj = down->argsobj;
|
||||
fp->fun = (script->staticLevel > 0) ? down->fun : NULL;
|
||||
fp->thisv = down->thisv;
|
||||
fp->flags = flags;
|
||||
fp->flags = flags | (down->flags & JSFRAME_COMPUTED_THIS);
|
||||
fp->argc = down->argc;
|
||||
fp->argv = down->argv;
|
||||
fp->annotation = down->annotation;
|
||||
@ -793,7 +809,7 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script,
|
||||
fp->argsobj = NULL;
|
||||
fp->fun = NULL;
|
||||
/* Ininitialize fp->thisv after pushExecuteFrame. */
|
||||
fp->flags = flags;
|
||||
fp->flags = flags | JSFRAME_COMPUTED_THIS;
|
||||
fp->argc = 0;
|
||||
fp->argv = NULL;
|
||||
fp->annotation = NULL;
|
||||
@ -2176,8 +2192,6 @@ js_Interpret(JSContext *cx)
|
||||
script = fp->script;
|
||||
JS_ASSERT(!script->isEmpty());
|
||||
JS_ASSERT(script->length > 1);
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(fp->thisv));
|
||||
JS_ASSERT_IF(!fp->fun, !JSVAL_IS_NULL(fp->thisv));
|
||||
|
||||
/* Count of JS function calls that nest in this C js_Interpret frame. */
|
||||
inlineCallCount = 0;
|
||||
|
@ -59,7 +59,8 @@ typedef struct JSFrameRegs {
|
||||
/* JS stack frame flags. */
|
||||
enum JSFrameFlags {
|
||||
JSFRAME_CONSTRUCTING = 0x01, /* frame is for a constructor invocation */
|
||||
JSFRAME_OVERRIDE_ARGS = 0x02, /* overridden arguments local variable */
|
||||
JSFRAME_COMPUTED_THIS = 0x02, /* frame.thisv was computed already and
|
||||
JSVAL_IS_OBJECT(thisv) */
|
||||
JSFRAME_ASSIGNING = 0x04, /* a complex (not simplex JOF_ASSIGNING) op
|
||||
is currently assigning to a property */
|
||||
JSFRAME_DEBUGGER = 0x08, /* frame for JS_EvaluateInStackFrame */
|
||||
@ -67,6 +68,7 @@ enum JSFrameFlags {
|
||||
JSFRAME_FLOATING_GENERATOR = 0x20, /* frame copy stored in a generator obj */
|
||||
JSFRAME_YIELDING = 0x40, /* js_Interpret dispatched JSOP_YIELD */
|
||||
JSFRAME_GENERATOR = 0x80, /* frame belongs to generator-iterator */
|
||||
JSFRAME_OVERRIDE_ARGS = 0x100, /* overridden arguments local variable */
|
||||
|
||||
JSFRAME_SPECIAL = JSFRAME_DEBUGGER | JSFRAME_EVAL
|
||||
};
|
||||
@ -87,22 +89,7 @@ struct JSStackFrame
|
||||
JSVAL_OBJECT */
|
||||
JSScript *script; /* script being interpreted */
|
||||
JSFunction *fun; /* function being called or null */
|
||||
|
||||
/*
|
||||
* The value of |this| in this stack frame, or JSVAL_NULL if |this| is to
|
||||
* be computed lazily on demand.
|
||||
*
|
||||
* thisv is eagerly initialized for non-function-call frames and qualified
|
||||
* method calls, but lazily initialized in most unqualified function calls.
|
||||
* See getThisObject().
|
||||
*
|
||||
* Usually if argv != NULL then thisv == argv[-1], but natives may assign
|
||||
* to argv[-1]. Also, obj_eval can trigger a special case where two stack
|
||||
* frames have the same argv. If one of the frames fills in both argv[-1]
|
||||
* and thisv, the other frame's thisv is left null.
|
||||
*/
|
||||
jsval thisv;
|
||||
|
||||
jsval thisv; /* "this" pointer if in method */
|
||||
uintN argc; /* actual argument count */
|
||||
jsval *argv; /* base of argument stack slots */
|
||||
jsval rval; /* function return value */
|
||||
@ -224,9 +211,6 @@ struct JSStackFrame
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
JSObject *computeThisObject(JSContext *cx);
|
||||
};
|
||||
|
||||
namespace js {
|
||||
@ -273,9 +257,10 @@ js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp);
|
||||
|
||||
/*
|
||||
* For a call with arguments argv including argv[-1] (nominal |this|) and
|
||||
* argv[-2] (callee) replace null |this| with callee's parent and replace
|
||||
* primitive values with the equivalent wrapper objects. argv[-1] must not be
|
||||
* JSVAL_VOID or an activation object.
|
||||
* argv[-2] (callee) replace null |this| with callee's parent, replace
|
||||
* primitive values with the equivalent wrapper objects and censor activation
|
||||
* objects as, per ECMA-262, they may not be referred to by |this|. argv[-1]
|
||||
* must not be a JSVAL_VOID.
|
||||
*/
|
||||
extern JSObject *
|
||||
js_ComputeThis(JSContext *cx, jsval *argv);
|
||||
@ -464,7 +449,14 @@ JS_END_EXTERN_C
|
||||
inline JSObject *
|
||||
JSStackFrame::getThisObject(JSContext *cx)
|
||||
{
|
||||
return JSVAL_IS_PRIMITIVE(thisv) ? computeThisObject(cx) : JSVAL_TO_OBJECT(thisv);
|
||||
if (flags & JSFRAME_COMPUTED_THIS)
|
||||
return JSVAL_TO_OBJECT(thisv); /* JSVAL_COMPUTED_THIS invariant */
|
||||
JSObject* obj = js_ComputeThis(cx, argv);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
thisv = OBJECT_TO_JSVAL(obj);
|
||||
flags |= JSFRAME_COMPUTED_THIS;
|
||||
return obj;
|
||||
}
|
||||
|
||||
#endif /* jsinterp_h___ */
|
||||
|
@ -6415,9 +6415,7 @@ js_DumpAtom(JSAtom *atom)
|
||||
void
|
||||
dumpValue(jsval val)
|
||||
{
|
||||
if ((val & 0xfffffff0) == 0xdadadad0) {
|
||||
fprintf(stderr, "**uninitialized** %p", (void *) val);
|
||||
} else if (JSVAL_IS_NULL(val)) {
|
||||
if (JSVAL_IS_NULL(val)) {
|
||||
fprintf(stderr, "null");
|
||||
} else if (JSVAL_IS_VOID(val)) {
|
||||
fprintf(stderr, "undefined");
|
||||
@ -6651,6 +6649,8 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
|
||||
fprintf(stderr, " none");
|
||||
if (fp->flags & JSFRAME_CONSTRUCTING)
|
||||
fprintf(stderr, " constructing");
|
||||
if (fp->flags & JSFRAME_COMPUTED_THIS)
|
||||
fprintf(stderr, " computed_this");
|
||||
if (fp->flags & JSFRAME_ASSIGNING)
|
||||
fprintf(stderr, " assigning");
|
||||
if (fp->flags & JSFRAME_DEBUGGER)
|
||||
|
@ -1096,25 +1096,6 @@ js_IsCacheableNonGlobalScope(JSObject *obj)
|
||||
return cacheable;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* Used in assertions only. False if obj is a special object which must be
|
||||
* censored and thus can't be the value of 'this'.
|
||||
*/
|
||||
inline bool
|
||||
js_IsSaneThisObject(JSObject *obj)
|
||||
{
|
||||
extern JS_FRIEND_DATA(JSClass) js_CallClass;
|
||||
extern JS_FRIEND_DATA(JSClass) js_DeclEnvClass;
|
||||
|
||||
JSClass *clasp = obj->getClass();
|
||||
return clasp != &js_CallClass &&
|
||||
clasp != &js_BlockClass &&
|
||||
clasp != &js_DeclEnvClass &&
|
||||
clasp != &js_WithClass;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success.
|
||||
*/
|
||||
|
@ -216,10 +216,8 @@ BEGIN_CASE(JSOP_STOP)
|
||||
}
|
||||
|
||||
JS_ASSERT(regs.sp == StackBase(fp));
|
||||
if ((fp->flags & JSFRAME_CONSTRUCTING) && JSVAL_IS_PRIMITIVE(fp->rval)) {
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(fp->thisv));
|
||||
if ((fp->flags & JSFRAME_CONSTRUCTING) && JSVAL_IS_PRIMITIVE(fp->rval))
|
||||
fp->rval = fp->thisv;
|
||||
}
|
||||
ok = JS_TRUE;
|
||||
if (inlineCallCount)
|
||||
inline_return:
|
||||
@ -270,10 +268,8 @@ BEGIN_CASE(JSOP_STOP)
|
||||
* passed in via |this|, and instrument this constructor invocation.
|
||||
*/
|
||||
if (fp->flags & JSFRAME_CONSTRUCTING) {
|
||||
if (JSVAL_IS_PRIMITIVE(fp->rval)) {
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(fp->thisv));
|
||||
if (JSVAL_IS_PRIMITIVE(fp->rval))
|
||||
fp->rval = fp->thisv;
|
||||
}
|
||||
JS_RUNTIME_METER(cx->runtime, constructs);
|
||||
}
|
||||
|
||||
@ -2070,8 +2066,6 @@ BEGIN_CASE(JSOP_APPLY)
|
||||
*disp = newfp;
|
||||
}
|
||||
JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags));
|
||||
JS_ASSERT_IF(!JSVAL_IS_PRIMITIVE(vp[1]),
|
||||
js_IsSaneThisObject(JSVAL_TO_OBJECT(vp[1])));
|
||||
newfp->thisv = vp[1];
|
||||
newfp->imacpc = NULL;
|
||||
|
||||
@ -2178,29 +2172,6 @@ BEGIN_CASE(JSOP_SETCALL)
|
||||
goto error;
|
||||
END_CASE(JSOP_SETCALL)
|
||||
|
||||
#define SLOW_PUSH_THISV(cx, obj) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSClass *clasp; \
|
||||
JSObject *thisp = obj; \
|
||||
if (!thisp->getParent() || \
|
||||
(clasp = thisp->getClass()) == &js_CallClass || \
|
||||
clasp == &js_BlockClass || \
|
||||
clasp == &js_DeclEnvClass) { \
|
||||
/* Normal case: thisp is global or an activation record. */ \
|
||||
/* Callee determines 'this'. */ \
|
||||
thisp = NULL; \
|
||||
} else { \
|
||||
/* thisp is a With object or, even stranger, a plain nonglobal */ \
|
||||
/* object on the scope chain. Call the thisObject hook now: */ \
|
||||
/* since we are pushing a non-null thisv, the callee will */ \
|
||||
/* assume 'this' was computed. */ \
|
||||
thisp = thisp->thisObject(cx); \
|
||||
if (!thisp) \
|
||||
goto error; \
|
||||
} \
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(thisp)); \
|
||||
JS_END_MACRO
|
||||
|
||||
BEGIN_CASE(JSOP_NAME)
|
||||
BEGIN_CASE(JSOP_CALLNAME)
|
||||
{
|
||||
@ -2213,31 +2184,19 @@ BEGIN_CASE(JSOP_CALLNAME)
|
||||
ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
|
||||
if (entry->vword.isObject()) {
|
||||
rval = entry->vword.toJsval();
|
||||
} else if (entry->vword.isSlot()) {
|
||||
goto do_push_rval;
|
||||
}
|
||||
|
||||
if (entry->vword.isSlot()) {
|
||||
slot = entry->vword.toSlot();
|
||||
JS_ASSERT(slot < obj2->scope()->freeslot);
|
||||
rval = obj2->lockedGetSlot(slot);
|
||||
} else {
|
||||
JS_ASSERT(entry->vword.isSprop());
|
||||
sprop = entry->vword.toSprop();
|
||||
NATIVE_GET(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, &rval);
|
||||
goto do_push_rval;
|
||||
}
|
||||
|
||||
// Push results, the same as below, but with a property cache hit there
|
||||
// is no need to test for the unusual and uncacheable case where the
|
||||
// caller determines 'this'.
|
||||
#ifdef DEBUG
|
||||
JSClass *clasp;
|
||||
JS_ASSERT(!obj->getParent() ||
|
||||
(clasp = obj->getClass()) == &js_CallClass ||
|
||||
clasp == &js_BlockClass ||
|
||||
clasp == &js_DeclEnvClass);
|
||||
#endif
|
||||
PUSH_OPND(rval);
|
||||
if (op == JSOP_CALLNAME)
|
||||
PUSH_OPND(JSVAL_NULL);
|
||||
len = JSOP_NAME_LENGTH;
|
||||
DO_NEXT_OP(len);
|
||||
JS_ASSERT(entry->vword.isSprop());
|
||||
sprop = entry->vword.toSprop();
|
||||
goto do_native_get;
|
||||
}
|
||||
|
||||
id = ATOM_TO_JSID(atom);
|
||||
@ -2262,13 +2221,15 @@ BEGIN_CASE(JSOP_CALLNAME)
|
||||
goto error;
|
||||
} else {
|
||||
sprop = (JSScopeProperty *)prop;
|
||||
do_native_get:
|
||||
NATIVE_GET(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, &rval);
|
||||
obj2->dropProperty(cx, (JSProperty *) sprop);
|
||||
}
|
||||
|
||||
do_push_rval:
|
||||
PUSH_OPND(rval);
|
||||
if (op == JSOP_CALLNAME)
|
||||
SLOW_PUSH_THISV(cx, obj);
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||
}
|
||||
END_CASE(JSOP_NAME)
|
||||
|
||||
@ -3733,7 +3694,7 @@ BEGIN_CASE(JSOP_XMLNAME)
|
||||
goto error;
|
||||
STORE_OPND(-1, rval);
|
||||
if (op == JSOP_CALLXMLNAME)
|
||||
SLOW_PUSH_THISV(cx, obj);
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||
END_CASE(JSOP_XMLNAME)
|
||||
|
||||
BEGIN_CASE(JSOP_DESCENDANTS)
|
||||
|
@ -1820,7 +1820,7 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
||||
/* Push lambda and its 'this' parameter. */
|
||||
jsval *sp = rdata.args.getvp();
|
||||
*sp++ = OBJECT_TO_JSVAL(lambda);
|
||||
*sp++ = JSVAL_NULL;
|
||||
*sp++ = OBJECT_TO_JSVAL(lambda->getParent());
|
||||
|
||||
/* Push $&, $1, $2, ... */
|
||||
if (!PushRegExpSubstr(cx, cx->regExpStatics.lastMatch, sp))
|
||||
|
@ -3343,6 +3343,8 @@ FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const TraceType* mp, do
|
||||
fp->scopeChain->setPrivate(fp);
|
||||
}
|
||||
fp->thisv = fp->argv[-1];
|
||||
if (fp->flags & JSFRAME_CONSTRUCTING) // constructors always compute 'this'
|
||||
fp->flags |= JSFRAME_COMPUTED_THIS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9461,54 +9463,78 @@ TraceRecorder::unbox_jsval(jsval v, LIns* v_ins, VMSideExit* exit)
|
||||
JS_REQUIRES_STACK RecordingStatus
|
||||
TraceRecorder::getThis(LIns*& this_ins)
|
||||
{
|
||||
JSStackFrame *fp = cx->fp;
|
||||
JS_ASSERT_IF(fp->argv, fp->argv[-1] == fp->thisv);
|
||||
/*
|
||||
* JSStackFrame::getThisObject updates cx->fp->argv[-1], so sample it into 'original' first.
|
||||
*/
|
||||
jsval original = JSVAL_NULL;
|
||||
if (cx->fp->argv) {
|
||||
original = cx->fp->argv[-1];
|
||||
if (!JSVAL_IS_PRIMITIVE(original)) {
|
||||
if (JSVAL_TO_OBJECT(original)->hasClass(&js_WithClass))
|
||||
RETURN_STOP("can't trace getThis on With object");
|
||||
guardNotClass(get(&cx->fp->argv[-1]), &js_WithClass, snapshot(MISMATCH_EXIT),
|
||||
ACC_OTHER);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fp->fun) {
|
||||
// Top-level code. It is an invariant of the interpreter that fp->thisv
|
||||
// is non-null. Furthermore, we would not be recording if globalObj
|
||||
// were not at the end of the scope chain, so `this` can only be one
|
||||
// object, which we can burn into the trace.
|
||||
JSObject* thisObj = cx->fp->getThisObject(cx);
|
||||
if (!thisObj)
|
||||
RETURN_ERROR("fp->getThisObject failed");
|
||||
|
||||
JS_ASSERT(!fp->argv);
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(fp->thisv));
|
||||
/* In global code, bake in the global object as 'this' object. */
|
||||
if (!cx->fp->callee()) {
|
||||
JS_ASSERT(callDepth == 0);
|
||||
this_ins = INS_CONSTOBJ(thisObj);
|
||||
|
||||
#ifdef DEBUG
|
||||
JSObject *obj = globalObj->thisObject(cx);
|
||||
if (!obj)
|
||||
RETURN_ERROR("thisObject hook failed");
|
||||
JS_ASSERT(JSVAL_TO_OBJECT(fp->thisv) == obj);
|
||||
#endif
|
||||
|
||||
this_ins = INS_CONSTOBJ(JSVAL_TO_OBJECT(fp->thisv));
|
||||
/*
|
||||
* We don't have argv[-1] in global code, so we don't update the
|
||||
* tracker here.
|
||||
*/
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
jsval thisv = fp->argv[-1];
|
||||
JS_ASSERT(thisv == fp->thisv || JSVAL_IS_NULL(fp->thisv));
|
||||
jsval& thisv = cx->fp->argv[-1];
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(thisv));
|
||||
JS_ASSERT(fp->callee()->getGlobal() == globalObj);
|
||||
|
||||
if (!JSVAL_IS_NULL(thisv)) {
|
||||
// fp->argv[-1] has already been computed. Since the type-
|
||||
// specialization of traces distinguishes between null and objects, the
|
||||
// same will be true at run time (or we won't get this far).
|
||||
this_ins = get(&fp->argv[-1]);
|
||||
/*
|
||||
* Traces type-specialize between null and objects, so if we currently see
|
||||
* a null value in argv[-1], this trace will only match if we see null at
|
||||
* runtime as well. Bake in the global object as 'this' object, updating
|
||||
* the tracker as well. We can only detect this condition prior to calling
|
||||
* JSStackFrame::getThisObject, since it updates the interpreter's copy of
|
||||
* argv[-1].
|
||||
*/
|
||||
JSClass* clasp = NULL;
|
||||
if (JSVAL_IS_NULL(original) ||
|
||||
(((clasp = JSVAL_TO_OBJECT(original)->getClass()) == &js_CallClass) ||
|
||||
(clasp == &js_BlockClass))) {
|
||||
if (clasp)
|
||||
guardClass(get(&thisv), clasp, snapshot(BRANCH_EXIT), ACC_OTHER);
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(thisv));
|
||||
if (thisObj != globalObj)
|
||||
RETURN_STOP("global object was wrapped while recording");
|
||||
this_ins = INS_CONSTOBJ(thisObj);
|
||||
set(&thisv, this_ins);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
// Compute fp->argv[-1] now. The result is globalObj->thisObject(), which
|
||||
// is trace-constant. getThisObject writes back to fp->argv[-1], so do the
|
||||
// same on trace.
|
||||
JSObject *obj = fp->getThisObject(cx);
|
||||
if (!obj)
|
||||
RETURN_ERROR("getThisObject failed");
|
||||
JS_ASSERT(fp->argv[-1] == OBJECT_TO_JSVAL(obj));
|
||||
this_ins = INS_CONSTOBJ(obj);
|
||||
set(&fp->argv[-1], this_ins);
|
||||
this_ins = get(&thisv);
|
||||
|
||||
JSObject* wrappedGlobal = globalObj->thisObject(cx);
|
||||
if (!wrappedGlobal)
|
||||
RETURN_ERROR("globalObj->thisObject hook threw in getThis");
|
||||
|
||||
/*
|
||||
* The only unwrapped object that needs to be wrapped that we can get here
|
||||
* is the global object obtained throught the scope chain.
|
||||
*/
|
||||
this_ins = lir->insChoose(lir->insEqP_0(stobj_get_parent(this_ins)),
|
||||
INS_CONSTOBJ(wrappedGlobal),
|
||||
this_ins, avmplus::AvmCore::use_cmov());
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
JS_REQUIRES_STACK void
|
||||
TraceRecorder::guardClassHelper(bool cond, LIns* obj_ins, JSClass* clasp, VMSideExit* exit,
|
||||
AccSet accSet)
|
||||
@ -12366,7 +12392,7 @@ TraceRecorder::record_JSOP_CALLNAME()
|
||||
NameResult nr;
|
||||
CHECK_STATUS_A(scopeChainProp(obj, vp, ins, nr));
|
||||
stack(0, ins);
|
||||
stack(1, INS_NULL());
|
||||
stack(1, INS_CONSTOBJ(globalObj));
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
@ -12382,7 +12408,7 @@ TraceRecorder::record_JSOP_CALLNAME()
|
||||
JS_ASSERT(pcval.toObject()->isFunction());
|
||||
|
||||
stack(0, INS_CONSTOBJ(pcval.toObject()));
|
||||
stack(1, INS_NULL());
|
||||
stack(1, obj_ins);
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
@ -15111,8 +15137,9 @@ TraceRecorder::record_JSOP_GETTHISPROP()
|
||||
|
||||
/*
|
||||
* It's safe to just use cx->fp->thisv here because getThis() returns
|
||||
* ARECORD_STOP or ARECORD_ERROR if thisv is not available.
|
||||
* ARECORD_STOP if thisv is not available.
|
||||
*/
|
||||
JS_ASSERT(cx->fp->flags & JSFRAME_COMPUTED_THIS);
|
||||
CHECK_STATUS_A(getProp(JSVAL_TO_OBJECT(cx->fp->thisv), this_ins));
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
var x = this;
|
||||
var y;
|
||||
for (var i = 0; i < 9; i++)
|
||||
y = this;
|
||||
assertEq(x, y);
|
@ -1,4 +0,0 @@
|
||||
var cx = evalcx("");
|
||||
evalcx("function f() {var x; for (var i=0;i<9;i++) x=this; return x;}", cx);
|
||||
var f = cx.f;
|
||||
assertEq(f(), cx);
|
Loading…
Reference in New Issue
Block a user