js_SetPropertyHelper does not null *entryp for read-only properties (489171, r=gal,brendan).

This commit is contained in:
igor 2009-04-20 17:00:59 -07:00
parent be23b17c5d
commit 48c3925a9a
8 changed files with 158 additions and 147 deletions

View File

@ -2985,8 +2985,8 @@ DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
{ {
if (flags != 0 && OBJ_IS_NATIVE(obj)) { if (flags != 0 && OBJ_IS_NATIVE(obj)) {
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
return js_DefineNativeProperty(cx, obj, id, value, getter, setter, return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter,
attrs, flags, tinyid, NULL); attrs, flags, tinyid, NULL);
} }
return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs, return OBJ_DEFINE_PROPERTY(cx, obj, id, value, getter, setter, attrs,
NULL); NULL);
@ -3029,9 +3029,9 @@ DefineUCProperty(JSContext *cx, JSObject *obj,
return JS_FALSE; return JS_FALSE;
if (flags != 0 && OBJ_IS_NATIVE(obj)) { if (flags != 0 && OBJ_IS_NATIVE(obj)) {
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
return js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value, return !!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
getter, setter, attrs, flags, tinyid, getter, setter, attrs, flags, tinyid,
NULL); NULL);
} }
return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value, return OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), value,
getter, setter, attrs, NULL); getter, setter, attrs, NULL);
@ -3548,7 +3548,7 @@ JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
if (!js_GetMethod(cx, obj, id, vp, NULL)) if (!js_GetMethod(cx, obj, id, false, vp))
return JS_FALSE; return JS_FALSE;
if (objp) if (objp)
*objp = obj; *objp = obj;

View File

@ -107,11 +107,10 @@ js_GenerateShape(JSContext *cx, JSBool gcLocked)
return shape; return shape;
} }
JS_REQUIRES_STACK void JS_REQUIRES_STACK JSPropCacheEntry *
js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
uintN scopeIndex, uintN protoIndex, uintN scopeIndex, uintN protoIndex,
JSObject *pobj, JSScopeProperty *sprop, JSObject *pobj, JSScopeProperty *sprop)
JSPropCacheEntry **entryp)
{ {
JSPropertyCache *cache; JSPropertyCache *cache;
jsbytecode *pc; jsbytecode *pc;
@ -130,8 +129,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
/* FIXME bug 489098: consider enabling the property cache for eval. */ /* FIXME bug 489098: consider enabling the property cache for eval. */
if (js_IsPropertyCacheDisabled(cx) || (cx->fp->flags & JSFRAME_EVAL)) { if (js_IsPropertyCacheDisabled(cx) || (cx->fp->flags & JSFRAME_EVAL)) {
PCMETER(cache->disfills++); PCMETER(cache->disfills++);
*entryp = NULL; return JS_NO_PROP_CACHE_FILL;
return;
} }
/* /*
@ -142,8 +140,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
JS_ASSERT(scope->object == pobj); JS_ASSERT(scope->object == pobj);
if (!SCOPE_HAS_PROPERTY(scope, sprop)) { if (!SCOPE_HAS_PROPERTY(scope, sprop)) {
PCMETER(cache->oddfills++); PCMETER(cache->oddfills++);
*entryp = NULL; return JS_NO_PROP_CACHE_FILL;
return;
} }
/* /*
@ -176,8 +173,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
*/ */
if (!tmp || !OBJ_IS_NATIVE(tmp)) { if (!tmp || !OBJ_IS_NATIVE(tmp)) {
PCMETER(cache->noprotos++); PCMETER(cache->noprotos++);
*entryp = NULL; return JS_NO_PROP_CACHE_FILL;
return;
} }
if (tmp == pobj) if (tmp == pobj)
break; break;
@ -186,8 +182,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
} }
if (scopeIndex > PCVCAP_SCOPEMASK || protoIndex > PCVCAP_PROTOMASK) { if (scopeIndex > PCVCAP_SCOPEMASK || protoIndex > PCVCAP_PROTOMASK) {
PCMETER(cache->longchains++); PCMETER(cache->longchains++);
*entryp = NULL; return JS_NO_PROP_CACHE_FILL;
return;
} }
/* /*
@ -241,8 +236,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
* js_GenerateShape could not recover from * js_GenerateShape could not recover from
* rt->shapeGen's overflow. * rt->shapeGen's overflow.
*/ */
*entryp = NULL; return JS_NO_PROP_CACHE_FILL;
return;
} }
SCOPE_SET_BRANDED(scope); SCOPE_SET_BRANDED(scope);
if (OBJ_SCOPE(obj) == scope) if (OBJ_SCOPE(obj) == scope)
@ -322,10 +316,10 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
entry->kshape = kshape; entry->kshape = kshape;
entry->vcap = PCVCAP_MAKE(scope->shape, scopeIndex, protoIndex); entry->vcap = PCVCAP_MAKE(scope->shape, scopeIndex, protoIndex);
entry->vword = vword; entry->vword = vword;
*entryp = entry;
cache->empty = JS_FALSE; cache->empty = JS_FALSE;
PCMETER(cache->fills++); PCMETER(cache->fills++);
return entry;
} }
JS_REQUIRES_STACK JSAtom * JS_REQUIRES_STACK JSAtom *
@ -991,7 +985,7 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp)
MUST_FLOW_THROUGH("out"); MUST_FLOW_THROUGH("out");
id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); 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) if (!ok)
goto out; goto out;
if (JSVAL_IS_PRIMITIVE(tvr.u.value)) { if (JSVAL_IS_PRIMITIVE(tvr.u.value)) {
@ -3648,7 +3642,7 @@ js_Interpret(JSContext *cx)
LOAD_ATOM(0); LOAD_ATOM(0);
} }
id = ATOM_TO_JSID(atom); id = ATOM_TO_JSID(atom);
obj = js_FindIdentifierBase(cx, fp->scopeChain, id, entry); obj = js_FindIdentifierBase(cx, fp->scopeChain, id);
if (!obj) if (!obj)
goto error; goto error;
} while (0); } while (0);
@ -4158,11 +4152,10 @@ js_Interpret(JSContext *cx)
LOAD_ATOM(0); LOAD_ATOM(0);
} }
} else { } else {
entry = NULL;
LOAD_ATOM(0); LOAD_ATOM(0);
} }
id = ATOM_TO_JSID(atom); 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; goto error;
if (!prop) if (!prop)
goto atom_not_defined; goto atom_not_defined;
@ -4416,7 +4409,7 @@ js_Interpret(JSContext *cx)
} }
id = ATOM_TO_JSID(atom); id = ATOM_TO_JSID(atom);
if (entry if (entry
? !js_GetPropertyHelper(cx, obj, id, &rval, &entry) ? !js_GetPropertyHelper(cx, obj, id, true, &rval)
: !OBJ_GET_PROPERTY(cx, obj, id, &rval)) { : !OBJ_GET_PROPERTY(cx, obj, id, &rval)) {
goto error; goto error;
} }
@ -4512,13 +4505,13 @@ js_Interpret(JSContext *cx)
id = ATOM_TO_JSID(atom); id = ATOM_TO_JSID(atom);
PUSH(JSVAL_NULL); PUSH(JSVAL_NULL);
if (!JSVAL_IS_PRIMITIVE(lval)) { 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; goto error;
STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
STORE_OPND(-2, rval); STORE_OPND(-2, rval);
} else { } else {
JS_ASSERT(obj->map->ops->getProperty == js_GetProperty); 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; goto error;
STORE_OPND(-1, lval); STORE_OPND(-1, lval);
STORE_OPND(-2, rval); STORE_OPND(-2, rval);
@ -4747,18 +4740,15 @@ js_Interpret(JSContext *cx)
LOAD_ATOM(0); LOAD_ATOM(0);
id = ATOM_TO_JSID(atom); id = ATOM_TO_JSID(atom);
if (entry) { if (entry) {
if (!js_SetPropertyHelper(cx, obj, id, &rval, &entry)) entry = js_SetPropertyHelper(cx, obj, id, true, &rval);
if (!entry)
goto error; goto error;
#ifdef JS_TRACER TRACE_1(SetPropMiss, entry);
if (entry)
TRACE_1(SetPropMiss, entry);
#endif
} else { } else {
if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
goto error; goto error;
ABORT_RECORDING(cx, "Non-native set");
} }
if (!entry)
ABORT_RECORDING(cx, "SetPropUncached");
} while (0); } while (0);
END_SET_CASE_STORE_RVAL(JSOP_SETPROP, 2); END_SET_CASE_STORE_RVAL(JSOP_SETPROP, 2);
@ -4809,7 +4799,7 @@ js_Interpret(JSContext *cx)
END_CASE(JSOP_GETELEM) END_CASE(JSOP_GETELEM)
BEGIN_CASE(JSOP_CALLELEM) 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_HAS_NO_SUCH_METHOD
if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) { if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) {
regs.sp[-2] = regs.sp[-1]; regs.sp[-2] = regs.sp[-1];
@ -5245,12 +5235,11 @@ js_Interpret(JSContext *cx)
goto do_native_get; goto do_native_get;
} }
} else { } else {
entry = NULL;
LOAD_ATOM(0); LOAD_ATOM(0);
} }
id = ATOM_TO_JSID(atom); 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; goto error;
if (!prop) { if (!prop) {
/* Kludge to allow (typeof foo == "undefined") tests. */ /* Kludge to allow (typeof foo == "undefined") tests. */
@ -5269,7 +5258,6 @@ js_Interpret(JSContext *cx)
OBJ_DROP_PROPERTY(cx, obj2, prop); OBJ_DROP_PROPERTY(cx, obj2, prop);
if (!OBJ_GET_PROPERTY(cx, obj, id, &rval)) if (!OBJ_GET_PROPERTY(cx, obj, id, &rval))
goto error; goto error;
entry = NULL;
} else { } else {
sprop = (JSScopeProperty *)prop; sprop = (JSScopeProperty *)prop;
do_native_get: do_native_get:
@ -6395,17 +6383,15 @@ js_Interpret(JSContext *cx)
NULL, NULL)) { NULL, NULL)) {
goto error; goto error;
} }
if (JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
? !js_SetPropertyHelper(cx, obj, id, &rval, &entry) entry = JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
: !js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL, ? js_SetPropertyHelper(cx, obj, id, true, &rval)
JSPROP_ENUMERATE, 0, 0, NULL, : js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
&entry)) { JSPROP_ENUMERATE, 0, 0, NULL,
true);
if (!entry)
goto error; goto error;
} TRACE_1(SetPropMiss, entry);
#ifdef JS_TRACER
if (entry)
TRACE_1(SetPropMiss, entry);
#endif
} while (0); } while (0);
/* Common tail for property cache hit and miss cases. */ /* Common tail for property cache hit and miss cases. */

View File

@ -257,6 +257,12 @@ struct JSPropCacheEntry {
jsuword vword; /* value word, see PCVAL_* below */ 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 #if defined DEBUG_brendan || defined DEBUG_brendaneich
#define JS_PROPERTY_CACHE_METERING 1 #define JS_PROPERTY_CACHE_METERING 1
#endif #endif
@ -338,12 +344,14 @@ typedef struct JSPropertyCache {
* Fill property cache entry for key cx->fp->pc, optimized value word computed * 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), * from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj),
* 4-bit scopeIndex, and 4-bit protoIndex. * 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, js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
uintN scopeIndex, uintN protoIndex, uintN scopeIndex, uintN protoIndex,
JSObject *pobj, JSScopeProperty *sprop, JSObject *pobj, JSScopeProperty *sprop);
JSPropCacheEntry **entryp);
/* /*
* Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the * Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the

View File

@ -375,7 +375,7 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)
*vp = OBJECT_TO_JSVAL(iterobj); *vp = OBJECT_TO_JSVAL(iterobj);
} else { } else {
atom = cx->runtime->atomState.iteratorAtom; 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; goto bad;
if (JSVAL_IS_VOID(*vp)) { if (JSVAL_IS_VOID(*vp)) {
default_iter: default_iter:

View File

@ -3683,8 +3683,8 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter, uintN attrs, JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
JSProperty **propp) JSProperty **propp)
{ {
return js_DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter, attrs,
0, 0, propp); 0, 0, propp);
} }
/* /*
@ -3710,15 +3710,16 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
} \ } \
JS_END_MACRO JS_END_MACRO
JSBool JSPropCacheEntry *
js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter, uintN attrs, JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
uintN flags, intN shortid, JSProperty **propp, uintN flags, intN shortid, JSProperty **propp,
JSPropCacheEntry** entryp /* = NULL */) JSBool cacheResult /* = JS_FALSE */)
{ {
JSClass *clasp; JSClass *clasp;
JSScope *scope; JSScope *scope;
JSScopeProperty *sprop; JSScopeProperty *sprop;
JSPropCacheEntry *entry;
js_LeaveTraceIfGlobalObject(cx, obj); 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. * the property cache line for (obj, id) to map sprop.
*/ */
if (!js_LookupProperty(cx, obj, id, &pobj, &prop)) if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
return JS_FALSE; return NULL;
sprop = (JSScopeProperty *) prop; sprop = (JSScopeProperty *) prop;
if (sprop && if (sprop &&
pobj == obj && pobj == obj &&
@ -3814,10 +3815,11 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
js_RemoveScopeProperty(cx, scope, id); js_RemoveScopeProperty(cx, scope, id);
goto bad); goto bad);
if (entryp) { entry = JS_NO_PROP_CACHE_FILL;
if (cacheResult) {
JS_ASSERT_NOT_ON_TRACE(cx); JS_ASSERT_NOT_ON_TRACE(cx);
if (!(attrs & JSPROP_SHARED)) 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 else
PCMETER(JS_PROPERTY_CACHE(cx).nofills++); PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
} }
@ -3825,11 +3827,11 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
*propp = (JSProperty *) sprop; *propp = (JSProperty *) sprop;
else else
JS_UNLOCK_OBJ(cx, obj); JS_UNLOCK_OBJ(cx, obj);
return JS_TRUE; return entry;
bad: bad:
JS_UNLOCK_OBJ(cx, obj); JS_UNLOCK_OBJ(cx, obj);
return JS_FALSE; return NULL;
} }
JS_FRIEND_API(JSBool) JS_FRIEND_API(JSBool)
@ -4032,22 +4034,22 @@ IsCacheableNonGlobalScope(JSObject *obj)
return cacheable; return cacheable;
} }
int JSPropCacheEntry *
js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp, js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
JSObject **pobjp, JSProperty **propp, JSObject **objp, JSObject **pobjp, JSProperty **propp)
JSPropCacheEntry **entryp)
{ {
JSObject *scopeChain, *obj, *parent, *pobj; JSObject *scopeChain, *obj, *parent, *pobj;
uint32 shape; uint32 shape;
JSPropCacheEntry *entry;
int scopeIndex, protoIndex; int scopeIndex, protoIndex;
JSProperty *prop; 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; scopeChain = js_GetTopStackFrame(cx)->scopeChain;
shape = OBJ_SHAPE(scopeChain); shape = OBJ_SHAPE(scopeChain);
/* Scan entries on the scope chain that we can cache across. */ /* Scan entries on the scope chain that we can cache across. */
entry = JS_NO_PROP_CACHE_FILL;
obj = scopeChain; obj = scopeChain;
parent = OBJ_GET_PARENT(cx, obj); parent = OBJ_GET_PARENT(cx, obj);
for (scopeIndex = 0; for (scopeIndex = 0;
@ -4059,7 +4061,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp,
js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
&pobj, &prop); &pobj, &prop);
if (protoIndex < 0) if (protoIndex < 0)
return false; return NULL;
if (prop) { if (prop) {
#ifdef DEBUG #ifdef DEBUG
@ -4082,11 +4084,10 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp,
} }
} }
#endif #endif
if (entryp) { if (cacheResult) {
sprop = (JSScopeProperty *) prop; entry = js_FillPropertyCache(cx, scopeChain, shape,
js_FillPropertyCache(cx, scopeChain, shape, scopeIndex, protoIndex, pobj,
scopeIndex, protoIndex, pobj, sprop, (JSScopeProperty *) prop);
entryp);
} }
SCOPE_DEPTH_ACCUM(&rt->scopeSearchDepthStats, scopeIndex); SCOPE_DEPTH_ACCUM(&rt->scopeSearchDepthStats, scopeIndex);
goto out; goto out;
@ -4102,11 +4103,9 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp,
for (;;) { for (;;) {
if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop))
return false; return NULL;
if (prop) { if (prop) {
PCMETER(JS_PROPERTY_CACHE(cx).nofills++); PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
if (entryp)
*entryp = NULL;
goto out; goto out;
} }
@ -4127,19 +4126,18 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp,
*objp = obj; *objp = obj;
*pobjp = pobj; *pobjp = pobj;
*propp = prop; *propp = prop;
return true; return entry;
} }
JS_FRIEND_API(JSBool) JS_FRIEND_API(JSBool)
js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp, js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp,
JSProperty **propp) JSProperty **propp)
{ {
return js_FindPropertyHelper(cx, id, objp, pobjp, propp, NULL) >= 0; return !!js_FindPropertyHelper(cx, id, false, objp, pobjp, propp);
} }
JSObject * JSObject *
js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id, js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id)
JSPropCacheEntry *entry)
{ {
/* /*
* This function should not be called for a global object or from the * 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(OBJ_GET_PARENT(cx, scopeChain));
JS_ASSERT(!JS_ON_TRACE(cx)); JS_ASSERT(!JS_ON_TRACE(cx));
JS_ASSERT_IF(OBJ_IS_NATIVE(scopeChain), entry);
JSObject *obj = scopeChain; JSObject *obj = scopeChain;
@ -4168,9 +4165,13 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id,
if (prop) { if (prop) {
JS_ASSERT(OBJ_IS_NATIVE(pobj)); JS_ASSERT(OBJ_IS_NATIVE(pobj));
JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == OBJ_GET_CLASS(cx, obj)); JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == OBJ_GET_CLASS(cx, obj));
#ifdef DEBUG
JSPropCacheEntry *entry =
#endif
js_FillPropertyCache(cx, scopeChain, OBJ_SHAPE(scopeChain), js_FillPropertyCache(cx, scopeChain, OBJ_SHAPE(scopeChain),
scopeIndex, protoIndex, pobj, scopeIndex, protoIndex, pobj,
(JSScopeProperty *) prop, &entry); (JSScopeProperty *) prop);
JS_ASSERT(entry);
JS_UNLOCK_OBJ(cx, pobj); JS_UNLOCK_OBJ(cx, pobj);
return obj; return obj;
} }
@ -4310,8 +4311,8 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp)
} }
JSBool JSBool
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
JSPropCacheEntry **entryp) jsval *vp)
{ {
JSObject *aobj, *obj2; JSObject *aobj, *obj2;
uint32 shape; uint32 shape;
@ -4319,7 +4320,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
JSProperty *prop; JSProperty *prop;
JSScopeProperty *sprop; 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. */ /* Convert string indices to integers if appropriate. */
CHECK_FOR_STRING_INDEX(id); 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)) if (!OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, ID_TO_VALUE(id), vp))
return JS_FALSE; return JS_FALSE;
if (entryp) { PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).nofills++);
PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
*entryp = NULL;
}
/* /*
* Give a strict warning if foo.bar is evaluated by a script for an * 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)) if (!js_NativeGet(cx, obj, obj2, sprop, vp))
return JS_FALSE; return JS_FALSE;
if (entryp) { if (cacheResult) {
JS_ASSERT_NOT_ON_TRACE(cx); 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); JS_UNLOCK_OBJ(cx, obj2);
return JS_TRUE; return JS_TRUE;
@ -4412,18 +4410,18 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
JSBool JSBool
js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) 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 JSBool
js_GetMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp, js_GetMethod(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
JSPropCacheEntry **entryp) jsval *vp)
{ {
if (obj->map->ops == &js_ObjectOps || if (obj->map->ops == &js_ObjectOps ||
obj->map->ops->getProperty == js_GetProperty) { 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 JS_HAS_XML_SUPPORT
if (OBJECT_IS_XML(cx, obj)) if (OBJECT_IS_XML(cx, obj))
return js_GetXMLMethod(cx, obj, id, vp); return js_GetXMLMethod(cx, obj, id, vp);
@ -4452,9 +4450,9 @@ js_CheckUndeclaredVarAssignment(JSContext *cx)
JSMSG_UNDECLARED_VAR, bytes); JSMSG_UNDECLARED_VAR, bytes);
} }
JSBool JSPropCacheEntry *
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
JSPropCacheEntry **entryp) jsval *vp)
{ {
uint32 shape; uint32 shape;
int protoIndex; int protoIndex;
@ -4466,6 +4464,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
intN shortid; intN shortid;
JSClass *clasp; JSClass *clasp;
JSPropertyOp getter, setter; JSPropertyOp getter, setter;
JSPropCacheEntry *entry;
/* Convert string indices to integers if appropriate. */ /* Convert string indices to integers if appropriate. */
CHECK_FOR_STRING_INDEX(id); 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, protoIndex = js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
&pobj, &prop); &pobj, &prop);
if (protoIndex < 0) if (protoIndex < 0)
return JS_FALSE; return NULL;
if (prop) { if (prop) {
if (!OBJ_IS_NATIVE(pobj)) { if (!OBJ_IS_NATIVE(pobj)) {
OBJ_DROP_PROPERTY(cx, pobj, prop); 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 (attrs & JSPROP_READONLY) {
if (!JS_HAS_STRICT_OPTION(cx)) { if (!JS_HAS_STRICT_OPTION(cx)) {
/* Just return true per ECMA if not in strict mode. */ /* Just return true per ECMA if not in strict mode. */
PCMETER(!entryp || JS_PROPERTY_CACHE(cx).rofills++); PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).rofills++);
return JS_TRUE; return JS_NO_PROP_CACHE_FILL;
} }
/* Strict mode: report a read-only strict warning. */ /* 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. * slot-based properties.
*/ */
if (attrs & JSPROP_SHARED) { if (attrs & JSPROP_SHARED) {
if (entryp) { PCMETER(cacheResult && JS_PROPERTY_CACHE(cx).nofills++);
PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
*entryp = NULL;
}
if (SPROP_HAS_STUB_SETTER(sprop) && if (SPROP_HAS_STUB_SETTER(sprop) &&
!(sprop->attrs & JSPROP_GETTER)) { !(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. */ /* 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); scope = js_GetMutableScope(cx, obj);
if (!scope) { if (!scope) {
JS_UNLOCK_OBJ(cx, obj); JS_UNLOCK_OBJ(cx, obj);
return JS_FALSE; return NULL;
} }
if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES) if (clasp->flags & JSCLASS_SHARE_ALL_PROPERTIES)
attrs |= JSPROP_SHARED; attrs |= JSPROP_SHARED;
@ -4629,7 +4626,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
SPROP_INVALID_SLOT, attrs, flags, shortid); SPROP_INVALID_SLOT, attrs, flags, shortid);
if (!sprop) { if (!sprop) {
JS_UNLOCK_SCOPE(cx, scope); 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, ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, vp,
js_RemoveScopeProperty(cx, scope, id); js_RemoveScopeProperty(cx, scope, id);
JS_UNLOCK_SCOPE(cx, scope); JS_UNLOCK_SCOPE(cx, scope);
return JS_FALSE); return NULL);
} }
if (!js_NativeSet(cx, obj, sprop, vp)) 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); JS_ASSERT_NOT_ON_TRACE(cx);
if (!(attrs & JSPROP_SHARED)) 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 else
PCMETER(JS_PROPERTY_CACHE(cx).nofills++); PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
} }
JS_UNLOCK_SCOPE(cx, scope); JS_UNLOCK_SCOPE(cx, scope);
return JS_TRUE; return entry;
read_only_error: read_only_error:
return js_ReportValueErrorFlags(cx, flags, JSMSG_READ_ONLY, return js_ReportValueErrorFlags(cx, flags, JSMSG_READ_ONLY,
JSDVG_IGNORE_STACK, ID_TO_VALUE(id), NULL, JSDVG_IGNORE_STACK, ID_TO_VALUE(id), NULL,
NULL, NULL); NULL, NULL)
? JS_NO_PROP_CACHE_FILL
: NULL;
} }
JSBool JSBool
js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) 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 JSBool
@ -5575,7 +5576,7 @@ js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom,
older = JS_SetErrorReporter(cx, NULL); older = JS_SetErrorReporter(cx, NULL);
id = ATOM_TO_JSID(atom); id = ATOM_TO_JSID(atom);
fval = JSVAL_VOID; fval = JSVAL_VOID;
ok = js_GetMethod(cx, obj, id, &fval, NULL); ok = js_GetMethod(cx, obj, id, false, &fval);
if (!ok) if (!ok)
JS_ClearPendingException(cx); JS_ClearPendingException(cx);
JS_SetErrorReporter(cx, older); JS_SetErrorReporter(cx, older);

View File

@ -647,11 +647,15 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSProperty **propp); JSProperty **propp);
#ifdef __cplusplus /* FIXME: bug 442399 removes this LiveConnect requirement. */ #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, js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter, uintN attrs, JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
uintN flags, intN shortid, JSProperty **propp, uintN flags, intN shortid, JSProperty **propp,
JSPropCacheEntry** entryp = NULL); JSBool cacheResult = JS_FALSE);
#endif #endif
/* /*
@ -674,10 +678,12 @@ extern int
js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JSObject **objp, JSProperty **propp); JSObject **objp, JSProperty **propp);
extern JSBool /*
js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp, * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success.
JSObject **pobjp, JSProperty **propp, */
JSPropCacheEntry **entryp); 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 * 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); JSProperty **propp);
extern JS_REQUIRES_STACK JSObject * extern JS_REQUIRES_STACK JSObject *
js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id, js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id);
JSPropCacheEntry *entry);
extern JSObject * extern JSObject *
js_FindVariableScope(JSContext *cx, JSFunction **funp); js_FindVariableScope(JSContext *cx, JSFunction **funp);
@ -708,15 +713,15 @@ extern JSBool
js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp); js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, jsval *vp);
extern JSBool extern JSBool
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
JSPropCacheEntry **entryp); jsval *vp);
extern JSBool extern JSBool
js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
extern JSBool extern JSBool
js_GetMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp, js_GetMethod(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
JSPropCacheEntry **entryp); jsval *vp);
/* /*
* Check whether it is OK to assign an undeclared property of the global * 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) extern JS_FRIEND_API(JSBool)
js_CheckUndeclaredVarAssignment(JSContext *cx); js_CheckUndeclaredVarAssignment(JSContext *cx);
extern JSBool /*
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success.
JSPropCacheEntry **entryp); */
extern JSPropCacheEntry *
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, JSBool cacheResult,
jsval *vp);
extern JSBool extern JSBool
js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp);

View File

@ -3633,14 +3633,14 @@ CheckDestructuring(JSContext *cx, BindData *data,
if (data && if (data &&
data->binder == BindLet && data->binder == BindLet &&
OBJ_BLOCK_COUNT(cx, tc->blockChain) == 0) { OBJ_BLOCK_COUNT(cx, tc->blockChain) == 0) {
ok = js_DefineNativeProperty(cx, tc->blockChain, ok = !!js_DefineNativeProperty(cx, tc->blockChain,
ATOM_TO_JSID(cx->runtime-> ATOM_TO_JSID(cx->runtime->
atomState.emptyAtom), atomState.emptyAtom),
JSVAL_VOID, NULL, NULL, JSVAL_VOID, NULL, NULL,
JSPROP_ENUMERATE | JSPROP_ENUMERATE |
JSPROP_PERMANENT | JSPROP_PERMANENT |
JSPROP_SHARED, JSPROP_SHARED,
SPROP_HAS_SHORTID, 0, NULL); SPROP_HAS_SHORTID, 0, NULL);
if (!ok) if (!ok)
goto out; goto out;
} }

View File

@ -6021,12 +6021,17 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
JSProperty* prop; JSProperty* prop;
if (JOF_OPMODE(*pc) == JOF_NAME) { if (JOF_OPMODE(*pc) == JOF_NAME) {
JS_ASSERT(aobj == obj); 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"); ABORT_TRACE("failed to find name");
} else { } else {
int protoIndex = js_LookupPropertyWithFlags(cx, aobj, id, int protoIndex = js_LookupPropertyWithFlags(cx, aobj, id,
cx->resolveFlags, cx->resolveFlags,
&obj2, &prop); &obj2, &prop);
/* FIXME bug 488018 - this treats OOM as no-cache-fill. */
if (protoIndex < 0) if (protoIndex < 0)
ABORT_TRACE("failed to lookup property"); 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); OBJ_DROP_PROPERTY(cx, obj2, prop);
ABORT_TRACE("property found on non-native object"); ABORT_TRACE("property found on non-native object");
} }
entry = js_FillPropertyCache(cx, aobj, OBJ_SHAPE(aobj), 0,
js_FillPropertyCache(cx, aobj, OBJ_SHAPE(aobj), 0, protoIndex, obj2, protoIndex, obj2,
(JSScopeProperty*) prop, &entry); (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 JS_REQUIRES_STACK bool
TraceRecorder::record_SetPropMiss(JSPropCacheEntry* entry) 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"); ABORT_TRACE("can't trace uncacheable property set");
JSScopeProperty* sprop = PCVAL_TO_SPROP(entry->vword); JSScopeProperty* sprop = PCVAL_TO_SPROP(entry->vword);