Bug 513065 - Part 3, compute scope in the engine before calling the thisObject hook. r=mrbkap.

This commit is contained in:
Jason Orendorff 2010-05-12 08:15:49 -05:00
Родитель e723a3bdd7
Коммит ab890a859e
8 изменённых файлов: 55 добавлений и 61 удалений

Просмотреть файл

@ -371,11 +371,17 @@ js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp)
/* Some objects (e.g., With) delegate 'this' to another object. */ /* Some objects (e.g., With) delegate 'this' to another object. */
static inline JSObject * static inline JSObject *
CallThisObjectHook(JSContext *cx, JSObject *obj, jsval *argv) CallThisObjectHook(JSContext *cx, JSObject *obj, JSObject *scope, jsval *argv)
{ {
JSObject *thisp = obj->thisObject(cx); JSObject *thisp = obj;
if (!thisp) if (JSThisObjectOp thisObject = obj->map->ops->thisObject) {
return NULL; if (!scope)
scope = JSVAL_TO_OBJECT(argv[-2])->getGlobal();
thisp = thisObject(cx, obj, scope);
if (!thisp)
return NULL;
}
argv[-1] = OBJECT_TO_JSVAL(thisp); argv[-1] = OBJECT_TO_JSVAL(thisp);
return thisp; return thisp;
} }
@ -398,45 +404,29 @@ CallThisObjectHook(JSContext *cx, JSObject *obj, jsval *argv)
JS_STATIC_INTERPRET JSObject * JS_STATIC_INTERPRET JSObject *
js_ComputeGlobalThis(JSContext *cx, jsval *argv) js_ComputeGlobalThis(JSContext *cx, jsval *argv)
{ {
JSObject *thisp; JSObject *thisp = JSVAL_TO_OBJECT(argv[-2])->getGlobal();
return CallThisObjectHook(cx, thisp, thisp, argv);
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 * JSObject *
js_ComputeThis(JSContext *cx, jsval *argv) js_ComputeThis(JSContext *cx, jsval *argv)
{ {
JS_ASSERT(argv[-1] != JSVAL_HOLE); // check for SynthesizeFrame poisoning JS_ASSERT(argv[-1] != JSVAL_HOLE); // check for SynthesizeFrame poisoning
if (JSVAL_IS_NULL(argv[-1])) if (JSVAL_IS_NULL(argv[-1]))
return js_ComputeGlobalThis(cx, argv); return js_ComputeGlobalThis(cx, argv);
return ComputeThis(cx, argv);
if (!JSVAL_IS_OBJECT(argv[-1])) {
if (!js_PrimitiveToObject(cx, &argv[-1]))
return NULL;
return JSVAL_TO_OBJECT(argv[-1]);
}
JSObject *thisp = JSVAL_TO_OBJECT(argv[-1]);
if (thisp->getClass() == &js_CallClass || thisp->getClass() == &js_BlockClass)
return js_ComputeGlobalThis(cx, argv);
return CallThisObjectHook(cx, thisp, NULL, argv);
} }
#if JS_HAS_NO_SUCH_METHOD #if JS_HAS_NO_SUCH_METHOD
@ -1058,7 +1048,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
return false; return false;
frame.scopeChain = chain; frame.scopeChain = chain;
JSObject *thisp = JSVAL_TO_OBJECT(frame.thisv)->thisObject(cx); JSObject *thisp = JSVAL_TO_OBJECT(frame.thisv)->thisObject(cx, chain);
if (!thisp) if (!thisp)
return false; return false;
frame.thisv = OBJECT_TO_JSVAL(thisp); frame.thisv = OBJECT_TO_JSVAL(thisp);

Просмотреть файл

@ -2947,12 +2947,12 @@ with_TypeOf(JSContext *cx, JSObject *obj)
} }
static JSObject * static JSObject *
with_ThisObject(JSContext *cx, JSObject *obj) with_ThisObject(JSContext *cx, JSObject *obj, JSObject *scope)
{ {
JSObject *proto = obj->getProto(); JSObject *proto = obj->getProto();
if (!proto) if (!proto)
return obj; return obj;
return proto->thisObject(cx); return proto->thisObject(cx, scope);
} }
JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = { JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {

Просмотреть файл

@ -161,7 +161,7 @@ struct JSObjectOps {
JSTraceOp trace; JSTraceOp trace;
/* Optionally non-null members start here. */ /* Optionally non-null members start here. */
JSObjectOp thisObject; JSThisObjectOp thisObject;
JSPropertyRefOp dropProperty; JSPropertyRefOp dropProperty;
JSNative call; JSNative call;
JSNative construct; JSNative construct;
@ -634,8 +634,8 @@ struct JSObject {
} }
/* These four are time-optimized to avoid stub calls. */ /* These four are time-optimized to avoid stub calls. */
JSObject *thisObject(JSContext *cx) { JSObject *thisObject(JSContext *cx, JSObject *scope) {
return map->ops->thisObject ? map->ops->thisObject(cx, this) : this; return map->ops->thisObject ? map->ops->thisObject(cx, this, scope) : this;
} }
void dropProperty(JSContext *cx, JSProperty *prop) { void dropProperty(JSContext *cx, JSProperty *prop) {

Просмотреть файл

@ -423,9 +423,19 @@ typedef JSBool
(* JSEqualityOp)(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); (* JSEqualityOp)(JSContext *cx, JSObject *obj, jsval v, JSBool *bp);
/* /*
* A generic type for functions mapping an object to another object, or null * The type of JSObjectOps::thisObject. Return a "stunt this" object for obj,
* if an error or exception was thrown on cx. Used by JSObjectOps.thisObject * having a parent chain that ends in scope; or NULL on error.
* at present. *
* The engine guarantees that obj->map->ops->thisObject == the callback
* and that cx, obj, and scope are non-null.
*/
typedef JSObject *
(* JSThisObjectOp)(JSContext *cx, JSObject *obj, JSObject *scope);
/*
* A generic type for functions mapping an object to another object, or null if
* an error or exception was thrown on cx. Used by JSObjectOps.innerObject and
* outerObject at present.
*/ */
typedef JSObject * typedef JSObject *
(* JSObjectOp)(JSContext *cx, JSObject *obj); (* JSObjectOp)(JSContext *cx, JSObject *obj);

Просмотреть файл

@ -9516,7 +9516,7 @@ TraceRecorder::getThis(LIns*& this_ins)
this_ins = get(&thisv); this_ins = get(&thisv);
JSObject* wrappedGlobal = globalObj->thisObject(cx); JSObject* wrappedGlobal = globalObj->thisObject(cx, globalObj);
if (!wrappedGlobal) if (!wrappedGlobal)
RETURN_ERROR("globalObj->thisObject hook threw in getThis"); RETURN_ERROR("globalObj->thisObject hook threw in getThis");

Просмотреть файл

@ -2763,7 +2763,7 @@ split_outerObject(JSContext *cx, JSObject *obj)
} }
static JSObject * static JSObject *
split_thisObject(JSContext *cx, JSObject *obj) split_thisObject(JSContext *cx, JSObject *obj, JSObject */*scope*/)
{ {
OBJ_TO_OUTER_OBJECT(cx, obj); OBJ_TO_OUTER_OBJECT(cx, obj);
if (!obj) if (!obj)

Просмотреть файл

@ -133,13 +133,16 @@ xpcJSWeakReference::Get()
// nsXPConnect::GetWrapperForObject. But it takes a lot of // nsXPConnect::GetWrapperForObject. But it takes a lot of
// arguments! It turns out that the thisObject hook on XPConnect // arguments! It turns out that the thisObject hook on XPConnect
// objects does the right thing though, so... // objects does the right thing though, so...
if (obj->map->ops->thisObject)
if (obj->map->ops->thisObject &&
!(obj = obj->map->ops->thisObject(cx, obj)))
{ {
return NS_ERROR_FAILURE; JSObject *scope = JS_GetScopeChain(cx);
if (!scope)
return NS_ERROR_FAILURE;
scope = JS_GetGlobalForObject(cx, scope);
obj = obj->map->ops->thisObject(cx, obj, scope);
if (!obj)
return NS_ERROR_FAILURE;
} }
*retval = OBJECT_TO_JSVAL(obj); *retval = OBJECT_TO_JSVAL(obj);
} }
} }

Просмотреть файл

@ -1477,7 +1477,7 @@ private:
} // namespace } // namespace
static JSObject* static JSObject*
XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj, JSObject *scope)
{ {
// None of the wrappers we could potentially hand out are threadsafe so // None of the wrappers we could potentially hand out are threadsafe so
// just hand out the given object. // just hand out the given object.
@ -1488,15 +1488,6 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj)
if(!obj) if(!obj)
return nsnull; return nsnull;
JSObject *scope = JS_GetScopeChain(cx);
if(!scope)
{
XPCThrower::Throw(NS_ERROR_FAILURE, cx);
return nsnull;
}
scope = JS_GetGlobalForObject(cx, scope);
XPCPerThreadData *threadData = XPCPerThreadData::GetData(cx); XPCPerThreadData *threadData = XPCPerThreadData::GetData(cx);
if(!threadData) if(!threadData)
{ {