Bug 476447 - Array.prototype getter/setter does not work as usual (r=jorendorff).

This commit is contained in:
Brendan Eich 2009-03-09 11:25:43 -07:00
Родитель 137804716b
Коммит 3b1b70d1c3
3 изменённых файлов: 31 добавлений и 8 удалений

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

@ -63,6 +63,28 @@ extern JSClass js_ArrayClass, js_SlowArrayClass;
#define OBJ_IS_ARRAY(cx,obj) (OBJ_IS_DENSE_ARRAY(cx, obj) || \ #define OBJ_IS_ARRAY(cx,obj) (OBJ_IS_DENSE_ARRAY(cx, obj) || \
OBJ_GET_CLASS(cx, obj) == &js_SlowArrayClass) OBJ_GET_CLASS(cx, obj) == &js_SlowArrayClass)
/*
* Dense arrays are not native (OBJ_IS_NATIVE(cx, aobj) for a dense array aobj
* results in false, meaning aobj->map does not point to a JSScope).
*
* But Array methods are called via aobj.sort(), e.g., and the interpreter and
* the trace recorder must consult the property cache in order to perform well.
* The cache works only for native objects.
*
* Therefore the interpreter (js_Interpret in JSOP_GETPROP and JSOP_CALLPROP)
* and js_GetPropertyHelper use this inline function to skip up one link in the
* prototype chain when obj is a dense array, in order to find a likely-native
* object (to wit, Array.prototype) in which to probe for cached methods.
*
* Callers of js_GetProtoIfDenseArray must take care to use the original object
* (obj) for the |this| value of a getter, setter, or method call (bug 476447).
*/
static JS_INLINE JSObject *
js_GetProtoIfDenseArray(JSContext *cx, JSObject *obj)
{
return OBJ_IS_DENSE_ARRAY(cx, obj) ? OBJ_GET_PROTO(cx, obj) : obj;
}
extern JSObject * extern JSObject *
js_InitArrayClass(JSContext *cx, JSObject *obj); js_InitArrayClass(JSContext *cx, JSObject *obj);

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

@ -4263,7 +4263,7 @@ js_Interpret(JSContext *cx)
JSObject *aobj; JSObject *aobj;
JSPropCacheEntry *entry; JSPropCacheEntry *entry;
aobj = OBJ_IS_DENSE_ARRAY(cx, obj) ? OBJ_GET_PROTO(cx, obj) : obj; aobj = js_GetProtoIfDenseArray(cx, obj);
if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) { if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) {
PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom); PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom);
if (!atom) { if (!atom) {
@ -4291,7 +4291,7 @@ js_Interpret(JSContext *cx)
} }
id = ATOM_TO_JSID(atom); id = ATOM_TO_JSID(atom);
if (entry if (entry
? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry) ? !js_GetPropertyHelper(cx, obj, id, &rval, &entry)
: !OBJ_GET_PROPERTY(cx, obj, id, &rval)) { : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
goto error; goto error;
} }
@ -4354,7 +4354,7 @@ js_Interpret(JSContext *cx)
goto error; goto error;
} }
aobj = OBJ_IS_DENSE_ARRAY(cx, obj) ? OBJ_GET_PROTO(cx, obj) : obj; aobj = js_GetProtoIfDenseArray(cx, obj);
if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) { if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty)) {
PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom); PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom);
if (!atom) { if (!atom) {
@ -4399,7 +4399,7 @@ js_Interpret(JSContext *cx)
} else } else
#endif #endif
if (entry if (entry
? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry) ? !js_GetPropertyHelper(cx, obj, id, &rval, &entry)
: !OBJ_GET_PROPERTY(cx, obj, id, &rval)) { : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
goto error; goto error;
} }

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

@ -4205,9 +4205,9 @@ JSBool
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
JSPropCacheEntry **entryp) JSPropCacheEntry **entryp)
{ {
JSObject *aobj, *obj2;
uint32 shape; uint32 shape;
int protoIndex; int protoIndex;
JSObject *obj2;
JSProperty *prop; JSProperty *prop;
JSScopeProperty *sprop; JSScopeProperty *sprop;
@ -4215,8 +4215,9 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
/* Convert string indices to integers if appropriate. */ /* Convert string indices to integers if appropriate. */
CHECK_FOR_STRING_INDEX(id); CHECK_FOR_STRING_INDEX(id);
shape = OBJ_SHAPE(obj); aobj = js_GetProtoIfDenseArray(cx, obj);
protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, shape = OBJ_SHAPE(aobj);
protoIndex = js_LookupPropertyWithFlags(cx, aobj, id, cx->resolveFlags,
&obj2, &prop); &obj2, &prop);
if (protoIndex < 0) if (protoIndex < 0)
return JS_FALSE; return JS_FALSE;
@ -4294,7 +4295,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
if (entryp) { if (entryp) {
JS_ASSERT_NOT_ON_TRACE(cx); JS_ASSERT_NOT_ON_TRACE(cx);
js_FillPropertyCache(cx, obj, shape, 0, protoIndex, obj2, sprop, entryp); js_FillPropertyCache(cx, aobj, shape, 0, protoIndex, obj2, sprop, entryp);
} }
JS_UNLOCK_OBJ(cx, obj2); JS_UNLOCK_OBJ(cx, obj2);
return JS_TRUE; return JS_TRUE;