diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 9b18f5e5ca2..0b0e61d4f89 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -63,6 +63,28 @@ extern JSClass js_ArrayClass, js_SlowArrayClass; #define OBJ_IS_ARRAY(cx,obj) (OBJ_IS_DENSE_ARRAY(cx, obj) || \ 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 * js_InitArrayClass(JSContext *cx, JSObject *obj); diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index bb61d2836cf..197d9ce2e43 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -4263,7 +4263,7 @@ js_Interpret(JSContext *cx) JSObject *aobj; 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)) { PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom); if (!atom) { @@ -4291,7 +4291,7 @@ js_Interpret(JSContext *cx) } id = ATOM_TO_JSID(atom); if (entry - ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry) + ? !js_GetPropertyHelper(cx, obj, id, &rval, &entry) : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) { goto error; } @@ -4354,7 +4354,7 @@ js_Interpret(JSContext *cx) 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)) { PROPERTY_CACHE_TEST(cx, regs.pc, aobj, obj2, entry, atom); if (!atom) { @@ -4399,7 +4399,7 @@ js_Interpret(JSContext *cx) } else #endif if (entry - ? !js_GetPropertyHelper(cx, aobj, id, &rval, &entry) + ? !js_GetPropertyHelper(cx, obj, id, &rval, &entry) : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) { goto error; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 82ec59413ac..a6fd7c4cb2d 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -4205,9 +4205,9 @@ JSBool js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, JSPropCacheEntry **entryp) { + JSObject *aobj, *obj2; uint32 shape; int protoIndex; - JSObject *obj2; JSProperty *prop; JSScopeProperty *sprop; @@ -4215,8 +4215,9 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, /* Convert string indices to integers if appropriate. */ CHECK_FOR_STRING_INDEX(id); - shape = OBJ_SHAPE(obj); - protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, + aobj = js_GetProtoIfDenseArray(cx, obj); + shape = OBJ_SHAPE(aobj); + protoIndex = js_LookupPropertyWithFlags(cx, aobj, id, cx->resolveFlags, &obj2, &prop); if (protoIndex < 0) return JS_FALSE; @@ -4294,7 +4295,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, if (entryp) { 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); return JS_TRUE; diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 35245beaa03..65c7f81052c 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -2149,7 +2149,7 @@ class RegExpNativeCompiler { } } - LIns* to_fail = lir->insBranch(LIR_jf, lir->ins2(LIR_lt, pos, cpend), 0); + LIns* to_fail = lir->insBranch(LIR_jf, lir->ins2(LIR_lt, pos, lir->ins2(LIR_sub, cpend, lir->insImm(2))), 0); fails.add(to_fail); LIns* text_word = lir->insLoad(LIR_ld, pos, lir->insImm(0)); LIns* comp_word = useFastCI ?