From 48c3925a9ad8510cd4459e497ac250db2e400811 Mon Sep 17 00:00:00 2001 From: igor Date: Mon, 20 Apr 2009 17:00:59 -0700 Subject: [PATCH] js_SetPropertyHelper does not null *entryp for read-only properties (489171, r=gal,brendan). --- js/src/jsapi.cpp | 12 ++-- js/src/jsinterp.cpp | 70 +++++++++-------------- js/src/jsinterp.h | 14 ++++- js/src/jsiter.cpp | 2 +- js/src/jsobj.cpp | 135 ++++++++++++++++++++++---------------------- js/src/jsobj.h | 38 ++++++++----- js/src/jsparse.cpp | 16 +++--- js/src/jstracer.cpp | 18 ++++-- 8 files changed, 158 insertions(+), 147 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 531c7ff8f9f..c045a3e488f 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2985,8 +2985,8 @@ DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, { if (flags != 0 && OBJ_IS_NATIVE(obj)) { JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); - return js_DefineNativeProperty(cx, obj, id, value, getter, setter, - attrs, flags, tinyid, NULL); + return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter, + attrs, flags, tinyid, NULL); } return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs, NULL); @@ -3029,9 +3029,9 @@ DefineUCProperty(JSContext *cx, JSObject *obj, return JS_FALSE; if (flags != 0 && OBJ_IS_NATIVE(obj)) { JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); - return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value, - getter, setter, attrs, flags, tinyid, - NULL); + return !!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value, + getter, setter, attrs, flags, tinyid, + NULL); } return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs, NULL); @@ -3548,7 +3548,7 @@ JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); CHECK_REQUEST(cx); - if (!js_GetMethod(cx, obj, id, vp, NULL)) + if (!js_GetMethod(cx, obj, id, false, vp)) return JS_FALSE; if (objp) *objp = obj; diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index b59325925b0..9263b4f975f 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -107,11 +107,10 @@ js_GenerateShape(JSContext *cx, JSBool gcLocked) return shape; } -JS_REQUIRES_STACK void +JS_REQUIRES_STACK JSPropCacheEntry * js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, uintN scopeIndex, uintN protoIndex, - JSObject *pobj, JSScopeProperty *sprop, - JSPropCacheEntry **entryp) + JSObject *pobj, JSScopeProperty *sprop) { JSPropertyCache *cache; jsbytecode *pc; @@ -130,8 +129,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, /* FIXME bug 489098: consider enabling the property cache for eval. */ if (js_IsPropertyCacheDisabled(cx) || (cx->fp->flags & JSFRAME_EVAL)) { PCMETER(cache->disfills++); - *entryp = NULL; - return; + return JS_NO_PROP_CACHE_FILL; } /* @@ -142,8 +140,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, JS_ASSERT(scope->object == pobj); if (!SCOPE_HAS_PROPERTY(scope, sprop)) { PCMETER(cache->oddfills++); - *entryp = NULL; - return; + return JS_NO_PROP_CACHE_FILL; } /* @@ -176,8 +173,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, */ if (!tmp || !OBJ_IS_NATIVE(tmp)) { PCMETER(cache->noprotos++); - *entryp = NULL; - return; + return JS_NO_PROP_CACHE_FILL; } if (tmp == pobj) break; @@ -186,8 +182,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, } if (scopeIndex > PCVCAP_SCOPEMASK || protoIndex > PCVCAP_PROTOMASK) { PCMETER(cache->longchains++); - *entryp = NULL; - return; + return JS_NO_PROP_CACHE_FILL; } /* @@ -241,8 +236,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, * js_GenerateShape could not recover from * rt->shapeGen's overflow. */ - *entryp = NULL; - return; + return JS_NO_PROP_CACHE_FILL; } SCOPE_SET_BRANDED(scope); if (OBJ_SCOPE(obj) == scope) @@ -322,10 +316,10 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, entry->kshape = kshape; entry->vcap = PCVCAP_MAKE(scope->shape, scopeIndex, protoIndex); entry->vword = vword; - *entryp = entry; cache->empty = JS_FALSE; PCMETER(cache->fills++); + return entry; } JS_REQUIRES_STACK JSAtom * @@ -991,7 +985,7 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp) MUST_FLOW_THROUGH("out"); id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); - ok = js_GetMethod(cx, obj, id, &tvr.u.value, NULL); + ok = js_GetMethod(cx, obj, id, false, &tvr.u.value); if (!ok) goto out; if (JSVAL_IS_PRIMITIVE(tvr.u.value)) { @@ -3648,7 +3642,7 @@ js_Interpret(JSContext *cx) LOAD_ATOM(0); } id = ATOM_TO_JSID(atom); - obj = js_FindIdentifierBase(cx, fp->scopeChain, id, entry); + obj = js_FindIdentifierBase(cx, fp->scopeChain, id); if (!obj) goto error; } while (0); @@ -4158,11 +4152,10 @@ js_Interpret(JSContext *cx) LOAD_ATOM(0); } } else { - entry = NULL; LOAD_ATOM(0); } id = ATOM_TO_JSID(atom); - if (!js_FindPropertyHelper(cx, id, &obj, &obj2, &prop, &entry)) + if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) goto error; if (!prop) goto atom_not_defined; @@ -4416,7 +4409,7 @@ js_Interpret(JSContext *cx) } id = ATOM_TO_JSID(atom); if (entry - ? !js_GetPropertyHelper(cx, obj, id, &rval, &entry) + ? !js_GetPropertyHelper(cx, obj, id, true, &rval) : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) { goto error; } @@ -4512,13 +4505,13 @@ js_Interpret(JSContext *cx) id = ATOM_TO_JSID(atom); PUSH(JSVAL_NULL); if (!JSVAL_IS_PRIMITIVE(lval)) { - if (!js_GetMethod(cx, obj, id, &rval, entry ? &entry : NULL)) + if (!js_GetMethod(cx, obj, id, !!entry, &rval)) goto error; STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); STORE_OPND(-2, rval); } else { JS_ASSERT(obj->map->ops->getProperty == js_GetProperty); - if (!js_GetPropertyHelper(cx, obj, id, &rval, &entry)) + if (!js_GetPropertyHelper(cx, obj, id, true, &rval)) goto error; STORE_OPND(-1, lval); STORE_OPND(-2, rval); @@ -4747,18 +4740,15 @@ js_Interpret(JSContext *cx) LOAD_ATOM(0); id = ATOM_TO_JSID(atom); if (entry) { - if (!js_SetPropertyHelper(cx, obj, id, &rval, &entry)) + entry = js_SetPropertyHelper(cx, obj, id, true, &rval); + if (!entry) goto error; -#ifdef JS_TRACER - if (entry) - TRACE_1(SetPropMiss, entry); -#endif + TRACE_1(SetPropMiss, entry); } else { if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) goto error; + ABORT_RECORDING(cx, "Non-native set"); } - if (!entry) - ABORT_RECORDING(cx, "SetPropUncached"); } while (0); END_SET_CASE_STORE_RVAL(JSOP_SETPROP, 2); @@ -4809,7 +4799,7 @@ js_Interpret(JSContext *cx) END_CASE(JSOP_GETELEM) BEGIN_CASE(JSOP_CALLELEM) - ELEMENT_OP(-1, js_GetMethod(cx, obj, id, &rval, NULL)); + ELEMENT_OP(-1, js_GetMethod(cx, obj, id, false, &rval)); #if JS_HAS_NO_SUCH_METHOD if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) { regs.sp[-2] = regs.sp[-1]; @@ -5245,12 +5235,11 @@ js_Interpret(JSContext *cx) goto do_native_get; } } else { - entry = NULL; LOAD_ATOM(0); } id = ATOM_TO_JSID(atom); - if (!js_FindPropertyHelper(cx, id, &obj, &obj2, &prop, &entry)) + if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) goto error; if (!prop) { /* Kludge to allow (typeof foo == "undefined") tests. */ @@ -5269,7 +5258,6 @@ js_Interpret(JSContext *cx) OBJ_DROP_PROPERTY(cx, obj2, prop); if (!OBJ_GET_PROPERTY(cx, obj, id, &rval)) goto error; - entry = NULL; } else { sprop = (JSScopeProperty *)prop; do_native_get: @@ -6395,17 +6383,15 @@ js_Interpret(JSContext *cx) NULL, NULL)) { goto error; } - if (JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom) - ? !js_SetPropertyHelper(cx, obj, id, &rval, &entry) - : !js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL, - JSPROP_ENUMERATE, 0, 0, NULL, - &entry)) { + + entry = JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom) + ? js_SetPropertyHelper(cx, obj, id, true, &rval) + : js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL, + JSPROP_ENUMERATE, 0, 0, NULL, + true); + if (!entry) goto error; - } -#ifdef JS_TRACER - if (entry) - TRACE_1(SetPropMiss, entry); -#endif + TRACE_1(SetPropMiss, entry); } while (0); /* Common tail for property cache hit and miss cases. */ diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index 8586d46fe6a..c986082d70b 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -257,6 +257,12 @@ struct JSPropCacheEntry { jsuword vword; /* value word, see PCVAL_* below */ }; +/* + * Special value for functions returning JSPropCacheEntry * to distinguish + * between failure and no no-cache-fill cases. + */ +#define JS_NO_PROP_CACHE_FILL ((JSPropCacheEntry *) NULL + 1) + #if defined DEBUG_brendan || defined DEBUG_brendaneich #define JS_PROPERTY_CACHE_METERING 1 #endif @@ -338,12 +344,14 @@ typedef struct JSPropertyCache { * Fill property cache entry for key cx->fp->pc, optimized value word computed * from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj), * 4-bit scopeIndex, and 4-bit protoIndex. + * + * Return the filled cache entry or JS_NO_PROP_CACHE_FILL if caching was not + * possible. */ -extern JS_REQUIRES_STACK void +extern JS_REQUIRES_STACK JSPropCacheEntry * js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, uintN scopeIndex, uintN protoIndex, - JSObject *pobj, JSScopeProperty *sprop, - JSPropCacheEntry **entryp); + JSObject *pobj, JSScopeProperty *sprop); /* * Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index fce932678ed..c042d4e9899 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -375,7 +375,7 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) *vp = OBJECT_TO_JSVAL(iterobj); } else { atom = cx->runtime->atomState.iteratorAtom; - if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), vp, NULL)) + if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), false, vp)) goto bad; if (JSVAL_IS_VOID(*vp)) { default_iter: diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 35fba1b97bf..e6cc8ccd6b8 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3683,8 +3683,8 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs, JSProperty **propp) { - return js_DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, - 0, 0, propp); + return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, + 0, 0, propp); } /* @@ -3710,15 +3710,16 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, } \ JS_END_MACRO -JSBool +JSPropCacheEntry * js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs, uintN flags, intN shortid, JSProperty **propp, - JSPropCacheEntry** entryp /* = NULL */) + JSBool cacheResult /* = JS_FALSE */) { JSClass *clasp; JSScope *scope; JSScopeProperty *sprop; + JSPropCacheEntry *entry; js_LeaveTraceIfGlobalObject(cx, obj); @@ -3747,7 +3748,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, * the property cache line for (obj, id) to map sprop. */ if (!js_LookupProperty(cx, obj, id, &pobj, &prop)) - return JS_FALSE; + return NULL; sprop = (JSScopeProperty *) prop; if (sprop && pobj == obj && @@ -3814,10 +3815,11 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, js_RemoveScopeProperty(cx, scope, id); goto bad); - if (entryp) { + entry = JS_NO_PROP_CACHE_FILL; + if (cacheResult) { JS_ASSERT_NOT_ON_TRACE(cx); if (!(attrs & JSPROP_SHARED)) - js_FillPropertyCache(cx, obj, shape, 0, 0, obj, sprop, entryp); + entry = js_FillPropertyCache(cx, obj, shape, 0, 0, obj, sprop); else PCMETER(JS_PROPERTY_CACHE(cx).nofills++); } @@ -3825,11 +3827,11 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, *propp = (JSProperty *) sprop; else JS_UNLOCK_OBJ(cx, obj); - return JS_TRUE; + return entry; bad: JS_UNLOCK_OBJ(cx, obj); - return JS_FALSE; + return NULL; } JS_FRIEND_API(JSBool) @@ -4032,22 +4034,22 @@ IsCacheableNonGlobalScope(JSObject *obj) return cacheable; } -int -js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp, - JSObject **pobjp, JSProperty **propp, - JSPropCacheEntry **entryp) +JSPropCacheEntry * +js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult, + JSObject **objp, JSObject **pobjp, JSProperty **propp) { JSObject *scopeChain, *obj, *parent, *pobj; uint32 shape; + JSPropCacheEntry *entry; int scopeIndex, protoIndex; JSProperty *prop; - JSScopeProperty *sprop; - JS_ASSERT_IF(entryp, !JS_ON_TRACE(cx)); + JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx)); scopeChain = js_GetTopStackFrame(cx)->scopeChain; shape = OBJ_SHAPE(scopeChain); /* Scan entries on the scope chain that we can cache across. */ + entry = JS_NO_PROP_CACHE_FILL; obj = scopeChain; parent = OBJ_GET_PARENT(cx, obj); for (scopeIndex = 0; @@ -4059,7 +4061,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp, js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop); if (protoIndex < 0) - return false; + return NULL; if (prop) { #ifdef DEBUG @@ -4082,11 +4084,10 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp, } } #endif - if (entryp) { - sprop = (JSScopeProperty *) prop; - js_FillPropertyCache(cx, scopeChain, shape, - scopeIndex, protoIndex, pobj, sprop, - entryp); + if (cacheResult) { + entry = js_FillPropertyCache(cx, scopeChain, shape, + scopeIndex, protoIndex, pobj, + (JSScopeProperty *) prop); } SCOPE_DEPTH_ACCUM(&rt->scopeSearchDepthStats, scopeIndex); goto out; @@ -4102,11 +4103,9 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp, for (;;) { if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) - return false; + return NULL; if (prop) { PCMETER(JS_PROPERTY_CACHE(cx).nofills++); - if (entryp) - *entryp = NULL; goto out; } @@ -4127,19 +4126,18 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp, *objp = obj; *pobjp = pobj; *propp = prop; - return true; + return entry; } JS_FRIEND_API(JSBool) js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp, JSProperty **propp) { - return js_FindPropertyHelper(cx, id, objp, pobjp, propp, NULL) >= 0; + return !!js_FindPropertyHelper(cx, id, false, objp, pobjp, propp); } JSObject * -js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id, - JSPropCacheEntry *entry) +js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id) { /* * This function should not be called for a global object or from the @@ -4147,7 +4145,6 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id, */ JS_ASSERT(OBJ_GET_PARENT(cx, scopeChain)); JS_ASSERT(!JS_ON_TRACE(cx)); - JS_ASSERT_IF(OBJ_IS_NATIVE(scopeChain), entry); JSObject *obj = scopeChain; @@ -4168,9 +4165,13 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id, if (prop) { JS_ASSERT(OBJ_IS_NATIVE(pobj)); JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == OBJ_GET_CLASS(cx, obj)); +#ifdef DEBUG + JSPropCacheEntry *entry = +#endif js_FillPropertyCache(cx, scopeChain, OBJ_SHAPE(scopeChain), scopeIndex, protoIndex, pobj, - (JSScopeProperty *) prop, &entry); + (JSScopeProperty *) prop); + JS_ASSERT(entry); JS_UNLOCK_OBJ(cx, pobj); return obj; } @@ -4310,8 +4311,8 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp) } JSBool -js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, - JSPropCacheEntry **entryp) +js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult, + jsval *vp) { JSObject *aobj, *obj2; uint32 shape; @@ -4319,7 +4320,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, JSProperty *prop; JSScopeProperty *sprop; - JS_ASSERT_IF(entryp, !JS_ON_TRACE(cx)); + JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx)); /* Convert string indices to integers if appropriate. */ CHECK_FOR_STRING_INDEX(id); @@ -4335,10 +4336,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, if (!OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, ID_TO_VALUE(id), vp)) return JS_FALSE; - if (entryp) { - PCMETER(JS_PROPERTY_CACHE(cx).nofills++); - *entryp = NULL; - } + PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).nofills++); /* * Give a strict warning if foo.bar is evaluated by a script for an @@ -4401,9 +4399,9 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, if (!js_NativeGet(cx, obj, obj2, sprop, vp)) return JS_FALSE; - if (entryp) { + if (cacheResult) { JS_ASSERT_NOT_ON_TRACE(cx); - js_FillPropertyCache(cx, aobj, shape, 0, protoIndex, obj2, sprop, entryp); + js_FillPropertyCache(cx, aobj, shape, 0, protoIndex, obj2, sprop); } JS_UNLOCK_OBJ(cx, obj2); return JS_TRUE; @@ -4412,18 +4410,18 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, JSBool js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - return js_GetPropertyHelper(cx, obj, id, vp, NULL); + return js_GetPropertyHelper(cx, obj, id, false, vp); } JSBool -js_GetMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp, - JSPropCacheEntry **entryp) +js_GetMethod(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult, + jsval *vp) { if (obj->map->ops == &js_ObjectOps || obj->map->ops->getProperty == js_GetProperty) { - return js_GetPropertyHelper(cx, obj, id, vp, entryp); + return js_GetPropertyHelper(cx, obj, id, cacheResult, vp); } - JS_ASSERT_IF(entryp, OBJ_IS_DENSE_ARRAY(cx, obj)); + JS_ASSERT_IF(cacheResult, OBJ_IS_DENSE_ARRAY(cx, obj)); #if JS_HAS_XML_SUPPORT if (OBJECT_IS_XML(cx, obj)) return js_GetXMLMethod(cx, obj, id, vp); @@ -4452,9 +4450,9 @@ js_CheckUndeclaredVarAssignment(JSContext *cx) JSMSG_UNDECLARED_VAR, bytes); } -JSBool -js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, - JSPropCacheEntry **entryp) +JSPropCacheEntry * +js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult, + jsval *vp) { uint32 shape; int protoIndex; @@ -4466,6 +4464,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, intN shortid; JSClass *clasp; JSPropertyOp getter, setter; + JSPropCacheEntry *entry; /* Convert string indices to integers if appropriate. */ CHECK_FOR_STRING_INDEX(id); @@ -4483,7 +4482,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop); if (protoIndex < 0) - return JS_FALSE; + return NULL; if (prop) { if (!OBJ_IS_NATIVE(pobj)) { OBJ_DROP_PROPERTY(cx, pobj, prop); @@ -4538,8 +4537,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, if (attrs & JSPROP_READONLY) { if (!JS_HAS_STRICT_OPTION(cx)) { /* Just return true per ECMA if not in strict mode. */ - PCMETER(!entryp || JS_PROPERTY_CACHE(cx).rofills++); - return JS_TRUE; + PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).rofills++); + return JS_NO_PROP_CACHE_FILL; } /* Strict mode: report a read-only strict warning. */ @@ -4567,17 +4566,15 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, * slot-based properties. */ if (attrs & JSPROP_SHARED) { - if (entryp) { - PCMETER(JS_PROPERTY_CACHE(cx).nofills++); - *entryp = NULL; - } - + PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).nofills++); if (SPROP_HAS_STUB_SETTER(sprop) && !(sprop->attrs & JSPROP_GETTER)) { - return JS_TRUE; + return JS_NO_PROP_CACHE_FILL; } - return js_SetSprop(cx, sprop, obj, vp); + return js_SetSprop(cx, sprop, obj, vp) + ? JS_NO_PROP_CACHE_FILL + : NULL; } /* Restore attrs to the ECMA default for new properties. */ @@ -4621,7 +4618,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, scope = js_GetMutableScope(cx, obj); if (!scope) { JS_UNLOCK_OBJ(cx, obj); - return JS_FALSE; + return NULL; } if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES) attrs |= JSPROP_SHARED; @@ -4629,7 +4626,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, SPROP_INVALID_SLOT, attrs, flags, shortid); if (!sprop) { JS_UNLOCK_SCOPE(cx, scope); - return JS_FALSE; + return NULL; } /* @@ -4644,32 +4641,36 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, vp, js_RemoveScopeProperty(cx, scope, id); JS_UNLOCK_SCOPE(cx, scope); - return JS_FALSE); + return NULL); } if (!js_NativeSet(cx, obj, sprop, vp)) - return JS_FALSE; + return NULL; - if (entryp) { + entry = JS_NO_PROP_CACHE_FILL; + if (cacheResult) { JS_ASSERT_NOT_ON_TRACE(cx); if (!(attrs & JSPROP_SHARED)) - js_FillPropertyCache(cx, obj, shape, 0, 0, obj, sprop, entryp); + entry = js_FillPropertyCache(cx, obj, shape, 0, 0, obj, sprop); else PCMETER(JS_PROPERTY_CACHE(cx).nofills++); + } JS_UNLOCK_SCOPE(cx, scope); - return JS_TRUE; + return entry; read_only_error: return js_ReportValueErrorFlags(cx, flags, JSMSG_READ_ONLY, JSDVG_IGNORE_STACK, ID_TO_VALUE(id), NULL, - NULL, NULL); + NULL, NULL) + ? JS_NO_PROP_CACHE_FILL + : NULL; } JSBool js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - return js_SetPropertyHelper(cx, obj, id, vp, NULL); + return !!js_SetPropertyHelper(cx, obj, id, false, vp); } JSBool @@ -5575,7 +5576,7 @@ js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom, older = JS_SetErrorReporter(cx, NULL); id = ATOM_TO_JSID(atom); fval = JSVAL_VOID; - ok = js_GetMethod(cx, obj, id, &fval, NULL); + ok = js_GetMethod(cx, obj, id, false, &fval); if (!ok) JS_ClearPendingException(cx); JS_SetErrorReporter(cx, older); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 5d29bc54bff..f84c2cd9698 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -647,11 +647,15 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, JSProperty **propp); #ifdef __cplusplus /* FIXME: bug 442399 removes this LiveConnect requirement. */ -extern JSBool + +/* + * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success. + */ +extern JSPropCacheEntry * js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs, uintN flags, intN shortid, JSProperty **propp, - JSPropCacheEntry** entryp = NULL); + JSBool cacheResult = JS_FALSE); #endif /* @@ -674,10 +678,12 @@ extern int js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp, JSProperty **propp); -extern JSBool -js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp, - JSObject **pobjp, JSProperty **propp, - JSPropCacheEntry **entryp); +/* + * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success. + */ +extern JSPropCacheEntry * +js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult, + JSObject **objp, JSObject **pobjp, JSProperty **propp); /* * Return the index along the scope chain in which id was found, or the last @@ -688,8 +694,7 @@ js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp, JSProperty **propp); extern JS_REQUIRES_STACK JSObject * -js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id, - JSPropCacheEntry *entry); +js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id); extern JSObject * js_FindVariableScope(JSContext *cx, JSFunction **funp); @@ -708,15 +713,15 @@ extern JSBool js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp); extern JSBool -js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, - JSPropCacheEntry **entryp); +js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult, + jsval *vp); extern JSBool js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); extern JSBool -js_GetMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp, - JSPropCacheEntry **entryp); +js_GetMethod(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult, + jsval *vp); /* * Check whether it is OK to assign an undeclared property of the global @@ -725,9 +730,12 @@ js_GetMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp, extern JS_FRIEND_API(JSBool) js_CheckUndeclaredVarAssignment(JSContext *cx); -extern JSBool -js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, - JSPropCacheEntry **entryp); +/* + * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success. + */ +extern JSPropCacheEntry * +js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult, + jsval *vp); extern JSBool js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 282b956ff33..104328cc5af 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -3633,14 +3633,14 @@ CheckDestructuring(JSContext *cx, BindData *data, if (data && data->binder == BindLet && OBJ_BLOCK_COUNT(cx, tc->blockChain) == 0) { - ok = js_DefineNativeProperty(cx, tc->blockChain, - ATOM_TO_JSID(cx->runtime-> - atomState.emptyAtom), - JSVAL_VOID, NULL, NULL, - JSPROP_ENUMERATE | - JSPROP_PERMANENT | - JSPROP_SHARED, - SPROP_HAS_SHORTID, 0, NULL); + ok = !!js_DefineNativeProperty(cx, tc->blockChain, + ATOM_TO_JSID(cx->runtime-> + atomState.emptyAtom), + JSVAL_VOID, NULL, NULL, + JSPROP_ENUMERATE | + JSPROP_PERMANENT | + JSPROP_SHARED, + SPROP_HAS_SHORTID, 0, NULL); if (!ok) goto out; } diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 1196c4d73f0..626a9e3b9a2 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -6021,12 +6021,17 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2 JSProperty* prop; if (JOF_OPMODE(*pc) == JOF_NAME) { JS_ASSERT(aobj == obj); - if (!js_FindPropertyHelper(cx, id, &obj, &obj2, &prop, &entry)) + entry = js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop); + + /* FIXME bug 488018 - this treats OOM as no-cache-fill. */ + if (!entry || entry == JS_NO_PROP_CACHE_FILL) ABORT_TRACE("failed to find name"); } else { int protoIndex = js_LookupPropertyWithFlags(cx, aobj, id, cx->resolveFlags, &obj2, &prop); + + /* FIXME bug 488018 - this treats OOM as no-cache-fill. */ if (protoIndex < 0) ABORT_TRACE("failed to lookup property"); @@ -6035,9 +6040,12 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2 OBJ_DROP_PROPERTY(cx, obj2, prop); ABORT_TRACE("property found on non-native object"); } - - js_FillPropertyCache(cx, aobj, OBJ_SHAPE(aobj), 0, protoIndex, obj2, - (JSScopeProperty*) prop, &entry); + entry = js_FillPropertyCache(cx, aobj, OBJ_SHAPE(aobj), 0, + protoIndex, obj2, + (JSScopeProperty*) prop); + JS_ASSERT(entry); + if (entry == JS_NO_PROP_CACHE_FILL) + entry = NULL; } } @@ -7556,7 +7564,7 @@ TraceRecorder::record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop JS_REQUIRES_STACK bool TraceRecorder::record_SetPropMiss(JSPropCacheEntry* entry) { - if (entry->kpc != cx->fp->regs->pc || !PCVAL_IS_SPROP(entry->vword)) + if (entry == JS_NO_PROP_CACHE_FILL || entry->kpc != cx->fp->regs->pc || !PCVAL_IS_SPROP(entry->vword)) ABORT_TRACE("can't trace uncacheable property set"); JSScopeProperty* sprop = PCVAL_TO_SPROP(entry->vword);