bug 490364 - mutating parent chain shapes only for Call objects and only when adding properties that are not parameter or var names. r=brendan

This commit is contained in:
Igor Bukanov 2009-05-15 11:43:19 +02:00
parent c142716352
commit 0374ee3760
4 changed files with 43 additions and 14 deletions

View File

@ -910,6 +910,8 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
uintN slot, attrs;
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass);
JS_ASSERT(!STOBJ_GET_PROTO(obj));
if (!JSVAL_IS_STRING(idval))
return JS_TRUE;
@ -921,6 +923,17 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
if (!js_ValueToStringId(cx, idval, &id))
return JS_FALSE;
/*
* Check whether the id refers to a formal parameter, local variable or
* the arguments special name.
*
* We define all such names using JSDNP_DONT_PURGE to avoid an expensive
* shape invalidation in js_DefineNativeProperty. If such an id happens to
* shadow a global or upvar of the same name, any inner functions can
* never access the outer binding. Thus it cannot invalidate any property
* cache entries or derived trace guards for the outer binding. See also
* comments in js_PurgeScopeChainHelper from jsobj.cpp.
*/
localKind = js_LookupLocal(cx, fun, JSID_TO_ATOM(id), &slot);
if (localKind != JSLOCAL_NONE && localKind != JSLOCAL_UPVAR) {
JS_ASSERT((uint16) slot == slot);
@ -944,7 +957,7 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
}
if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, getter, setter,
attrs, SPROP_HAS_SHORTID, (int16) slot,
NULL)) {
NULL, JSDNP_DONT_PURGE)) {
return JS_FALSE;
}
*objp = obj;
@ -959,7 +972,7 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID,
GetCallArguments, SetCallArguments,
JSPROP_PERMANENT | JSPROP_SHARED,
0, 0, NULL)) {
0, 0, NULL, JSDNP_DONT_PURGE)) {
return JS_FALSE;
}
*objp = obj;

View File

@ -6430,7 +6430,7 @@ js_Interpret(JSContext *cx)
? js_SetPropertyHelper(cx, obj, id, true, &rval)
: js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
JSPROP_ENUMERATE, 0, 0, NULL,
true)))
JSDNP_CACHE_RESULT)))
goto error;
} while (0);

View File

@ -3534,11 +3534,19 @@ void
js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id)
{
JS_ASSERT(OBJ_IS_DELEGATE(cx, obj));
PurgeProtoChain(cx, OBJ_GET_PROTO(cx, obj), id);
while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL) {
if (PurgeProtoChain(cx, obj, id))
return;
/*
* We must purge the scope chain only for Call objects as they are the only
* kind of cacheable non-global object that can gain properties after outer
* properties with the same names have been cached or traced. Call objects
* may gain such properties via eval introducing new vars; see bug 490364.
*/
if (STOBJ_GET_CLASS(obj) == &js_CallClass) {
while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL) {
if (PurgeProtoChain(cx, obj, id))
break;
}
}
}
@ -3626,13 +3634,14 @@ JSBool
js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
uintN flags, intN shortid, JSProperty **propp,
JSBool cacheResult /* = JS_FALSE */)
uintN defineHow /* = 0 */)
{
JSClass *clasp;
JSScope *scope;
JSScopeProperty *sprop;
bool added;
JS_ASSERT((defineHow & ~(JSDNP_CACHE_RESULT | JSDNP_DONT_PURGE)) == 0);
js_LeaveTraceIfGlobalObject(cx, obj);
/* Convert string indices to integers if appropriate. */
@ -3685,11 +3694,12 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
#endif /* JS_HAS_GETTER_SETTER */
/*
* Purge the property cache of any properties named by id that are about to
* be shadowed in obj's scope chain. We do this before locking obj to avoid
* nesting locks.
* Purge the property cache of any properties named by id that are about
* to be shadowed in obj's scope chain unless it is known a priori that it
* is not possible. We do this before locking obj to avoid nesting locks.
*/
js_PurgeScopeChain(cx, obj, id);
if (!(defineHow & JSDNP_DONT_PURGE))
js_PurgeScopeChain(cx, obj, id);
/*
* Check whether a readonly property or setter is being defined on a known
@ -3736,7 +3746,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
js_RemoveScopeProperty(cx, scope, id);
goto error);
if (cacheResult) {
if (defineHow & JSDNP_CACHE_RESULT) {
JS_ASSERT_NOT_ON_TRACE(cx);
JSPropCacheEntry *entry;
entry = js_FillPropertyCache(cx, obj, 0, 0, obj, sprop, added);

View File

@ -641,11 +641,17 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
#ifdef __cplusplus /* FIXME: bug 442399 removes this LiveConnect requirement. */
/*
* Flags for the defineHow parameter of js_DefineNativeProperty.
*/
const uintN JSDNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */
const uintN JSDNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */
extern JSBool
js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
uintN flags, intN shortid, JSProperty **propp,
JSBool cacheResult = JS_FALSE);
uintN defineHow = 0);
#endif
/*