bug 488029 - fixing bindname optimization regression from the bug 462734 plus creating js_DeclEnvClass instances together with Call objects. r=brendan

This commit is contained in:
Igor Bukanov
2009-04-14 12:54:37 +02:00
parent a47973ce5f
commit e2fcdbada6
3 changed files with 74 additions and 59 deletions

View File

@@ -4069,7 +4069,25 @@ js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
return js_FindPropertyHelper(cx, id, objp, pobjp, propp, NULL) >= 0;
}
JS_REQUIRES_STACK JSObject *
/*
* We cache property lookup results for JSOP_BIND only for the global object or
* for native non-global objects without resolve hooks, see bug 462734.
*/
static inline bool
IsCacheableNonGlobalScope(JSObject *obj)
{
JS_ASSERT(STOBJ_GET_PARENT(obj));
JSClass *clasp = STOBJ_GET_CLASS(obj);
bool cacheable = (clasp == &js_CallClass ||
clasp == &js_BlockClass ||
clasp == &js_DeclEnvClass);
JS_ASSERT_IF(cacheable, obj->map->ops->lookupProperty == js_LookupProperty);
return cacheable;
}
JSObject *
js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id,
JSPropCacheEntry *entry)
{
@@ -4077,31 +4095,29 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id,
* This function should not be called for a global object or from the
* trace and should have a valid cache entry for native scopeChain.
*/
JSObject *parent = OBJ_GET_PARENT(cx, scopeChain);
JS_ASSERT(parent);
JS_ASSERT(OBJ_GET_PARENT(cx, scopeChain));
JS_ASSERT(!JS_ON_TRACE(cx));
JS_ASSERT_IF(OBJ_IS_NATIVE(scopeChain), entry);
/*
* Optimize and cache only for classes that do not have resolve hooks and
* where the prototype is used only to implement a shared scope, bug 462734
* and bug 487039.
*/
JSObject *obj = scopeChain;
for (int scopeIndex = 0; ; scopeIndex++) {
JSClass *clasp = OBJ_GET_CLASS(cx, obj);
if (clasp != &js_CallClass && clasp != &js_BlockClass)
break;
/*
* Loop over cacheable objects on the scope chain until we find a
* property. We also stop when we reach the global object skipping any
* farther checks or lookups. For details see the JSOP_BINDNAME case of
* js_Interpret.
*/
for (int scopeIndex = 0; IsCacheableNonGlobalScope(obj); scopeIndex++) {
JSObject *pobj;
JSProperty *prop;
int protoIndex = js_LookupPropertyWithFlags(cx, obj, id, 0,
int protoIndex = js_LookupPropertyWithFlags(cx, obj, id,
cx->resolveFlags,
&pobj, &prop);
if (protoIndex < 0)
return NULL;
if (prop) {
JS_ASSERT(OBJ_IS_NATIVE(pobj));
JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == clasp);
JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == OBJ_GET_CLASS(cx, obj));
js_FillPropertyCache(cx, scopeChain, OBJ_SHAPE(scopeChain),
scopeIndex, protoIndex, pobj,
(JSScopeProperty *) prop, &entry);
@@ -4109,17 +4125,13 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id,
return obj;
}
obj = parent;
parent = OBJ_GET_PARENT(cx, parent);
if (!parent) {
/*
* Here obj is the global one and we can skip any checks for it,
* see comments in the JSOP_BINDNAME case of js_Interpret.
*/
/* Call and other cacheable objects always have a parent. */
obj = OBJ_GET_PARENT(cx, obj);
if (!OBJ_GET_PARENT(cx, obj))
return obj;
}
}
/* Loop until we find a property or reach the global object. */
do {
JSObject *pobj;
JSProperty *prop;
@@ -4129,9 +4141,17 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id,
OBJ_DROP_PROPERTY(cx, pobj, prop);
break;
}
/*
* We conservatively assume that a resolve hook could mutate the scope
* chain during OBJ_LOOKUP_PROPERTY. So we must check if parent is not
* null here even if it wasn't before the lookup.
*/
JSObject *parent = OBJ_GET_PARENT(cx, obj);
if (!parent)
break;
obj = parent;
parent = OBJ_GET_PARENT(cx, parent);
} while (parent);
} while (OBJ_GET_PARENT(cx, obj));
return obj;
}