Bug 500431 part 5 - Make js::PropertyCache fields private. r=brendan.

This commit is contained in:
Jason Orendorff 2010-03-26 18:38:33 -05:00
Родитель 6eaa7e5cd1
Коммит b2a62b2dae
4 изменённых файлов: 164 добавлений и 123 удалений

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

@ -1677,10 +1677,9 @@ BEGIN_CASE(JSOP_SETMETHOD)
atom = NULL;
if (JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) {
PropertyCache *cache = &JS_PROPERTY_CACHE(cx);
uint32 kshape = OBJ_SHAPE(obj);
/*
* Open-code PropertyCache::test, specializing for two important
* Probe the property cache, specializing for two important
* set-property cases. First:
*
* function f(a, b, c) {
@ -1698,15 +1697,14 @@ BEGIN_CASE(JSOP_SETMETHOD)
* (possibly after the first iteration) always exist in native
* object o.
*/
entry = &cache->table[PropertyCache::hash(regs.pc, kshape)];
PCMETER(cache->pctestentry = entry);
PCMETER(cache->tests++);
PCMETER(cache->settests++);
if (entry->kpc == regs.pc && entry->kshape == kshape &&
PropertyCache::matchShape(cx, obj, kshape)) {
if (cache->testForSet(cx, regs.pc, obj, &entry, &obj2, &atom)) {
/*
* Property cache hit: either predicting a new property to be
* added directly to obj by this set, or on an existing "own"
* Fast property cache hit, only partially confirmed by
* testForSet. We know that the entry applies to regs.pc and
* that obj's shape matches.
*
* The entry predicts either a new property to be added
* directly to obj by this set, or on an existing "own"
* property, or on a prototype property that has a setter.
*/
JS_ASSERT(entry->vword.isSprop());
@ -1833,17 +1831,15 @@ BEGIN_CASE(JSOP_SETMETHOD)
break;
}
PCMETER(cache->setpcmisses++);
}
atom = cache->fullTest(cx, regs.pc, &obj, &obj2, entry);
if (atom) {
PCMETER(cache->misses++);
PCMETER(cache->setmisses++);
} else {
atom = NULL;
} else if (!atom) {
/*
* Slower property cache hit, fully confirmed by testForSet (in
* the slow path, via fullTest).
*/
ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
sprop = NULL;
if (obj == obj2) {
JS_ASSERT(entry->vword.isSprop());
sprop = entry->vword.toSprop();
JS_ASSERT(sprop->writable());
JS_ASSERT(!OBJ_SCOPE(obj2)->sealed());
@ -3359,6 +3355,7 @@ END_CASE(JSOP_ENDINIT)
BEGIN_CASE(JSOP_INITPROP)
BEGIN_CASE(JSOP_INITMETHOD)
{
/* Load the property's initial value into rval. */
JS_ASSERT(regs.sp - StackBase(fp) >= 2);
rval = FETCH_OPND(-1);
@ -3369,104 +3366,63 @@ BEGIN_CASE(JSOP_INITMETHOD)
JS_ASSERT(OBJ_IS_NATIVE(obj));
JS_ASSERT(!OBJ_GET_CLASS(cx, obj)->reserveSlots);
JS_ASSERT(!(obj->getClass()->flags & JSCLASS_SHARE_ALL_PROPERTIES));
do {
JSScope *scope;
uint32 kshape;
PropertyCache *cache;
PropertyCacheEntry *entry;
/*
* We can not assume that the object created by JSOP_NEWINIT is still
* single-threaded as the debugger can access it from other threads.
*/
if (!CX_OWNS_OBJECT_TITLE(cx, obj))
goto do_initprop_miss;
JSScope *scope = OBJ_SCOPE(obj);
PropertyCacheEntry *entry;
scope = OBJ_SCOPE(obj);
JS_ASSERT(scope->object == obj);
JS_ASSERT(!scope->sealed());
kshape = scope->shape;
cache = &JS_PROPERTY_CACHE(cx);
entry = &cache->table[PropertyCache::hash(regs.pc, kshape)];
PCMETER(cache->pctestentry = entry);
PCMETER(cache->tests++);
PCMETER(cache->initests++);
if (entry->kpc == regs.pc &&
entry->kshape == kshape &&
entry->vshape() == rt->protoHazardShape) {
JS_ASSERT(entry->vcapTag() == 0);
PCMETER(cache->pchits++);
PCMETER(cache->inipchits++);
JS_ASSERT(entry->vword.isSprop());
sprop = entry->vword.toSprop();
JS_ASSERT(sprop->writable());
/*
* If this property has a non-stub setter, it must be __proto__,
* __parent__, or another "shared prototype" built-in. Force a miss
* to save code size here and let the standard code path take care
* of business.
*/
if (!sprop->hasDefaultSetter())
goto do_initprop_miss;
/*
* Detect a repeated property name and force a miss to share the
* strict warning code and consolidate all the complexity managed
* by JSScope::addProperty.
*/
if (sprop->parent != scope->lastProperty())
goto do_initprop_miss;
/*
* Otherwise this entry must be for a direct property of obj, not a
* proto-property, and there cannot have been any deletions of
* prior properties.
*/
JS_ASSERT(!scope->inDictionaryMode());
JS_ASSERT_IF(scope->table, !scope->hasProperty(sprop));
slot = sprop->slot;
JS_ASSERT(slot == scope->freeslot);
if (slot < STOBJ_NSLOTS(obj)) {
++scope->freeslot;
} else {
if (!js_AllocSlot(cx, obj, &slot))
goto error;
JS_ASSERT(slot == sprop->slot);
}
JS_ASSERT(!scope->lastProperty() ||
scope->shape == scope->lastProperty()->shape);
if (scope->table) {
JSScopeProperty *sprop2 =
scope->addProperty(cx, sprop->id, sprop->getter(), sprop->setter(), slot,
sprop->attributes(), sprop->getFlags(), sprop->shortid);
if (!sprop2) {
js_FreeSlot(cx, obj, slot);
goto error;
}
JS_ASSERT(sprop2 == sprop);
} else {
JS_ASSERT(!scope->isSharedEmpty());
scope->extend(cx, sprop);
}
/*
* No method change check here because here we are adding a new
* property, not updating an existing slot's value that might
* contain a method of a branded scope.
*/
TRACE_2(SetPropHit, entry, sprop);
LOCKED_OBJ_SET_SLOT(obj, slot, rval);
break;
/*
* Probe the property cache.
*
* We can not assume that the object created by JSOP_NEWINIT is still
* single-threaded as the debugger can access it from other threads.
* So check first.
*
* On a hit, if the cached sprop has a non-default setter, it must be
* __proto__ or __parent__. If sprop->parent != scope->lastProperty(),
* there is a repeated property name. The fast path does not handle these
* two cases.
*/
if (CX_OWNS_OBJECT_TITLE(cx, obj) &&
JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, scope, &sprop, &entry) &&
sprop->hasDefaultSetter() &&
sprop->parent == scope->lastProperty())
{
/* Fast path. Property cache hit. */
slot = sprop->slot;
JS_ASSERT(slot == scope->freeslot);
if (slot < STOBJ_NSLOTS(obj)) {
++scope->freeslot;
} else {
if (!js_AllocSlot(cx, obj, &slot))
goto error;
JS_ASSERT(slot == sprop->slot);
}
do_initprop_miss:
PCMETER(cache->inipcmisses++);
JS_ASSERT(!scope->lastProperty() ||
scope->shape == scope->lastProperty()->shape);
if (scope->table) {
JSScopeProperty *sprop2 =
scope->addProperty(cx, sprop->id, sprop->getter(), sprop->setter(), slot,
sprop->attributes(), sprop->getFlags(), sprop->shortid);
if (!sprop2) {
js_FreeSlot(cx, obj, slot);
goto error;
}
JS_ASSERT(sprop2 == sprop);
} else {
JS_ASSERT(!scope->isSharedEmpty());
scope->extend(cx, sprop);
}
/*
* No method change check here because here we are adding a new
* property, not updating an existing slot's value that might
* contain a method of a branded scope.
*/
TRACE_2(SetPropHit, entry, sprop);
LOCKED_OBJ_SET_SLOT(obj, slot, rval);
} else {
PCMETER(JS_PROPERTY_CACHE(cx).inipcmisses++);
/* Get the immediate property name into id. */
LOAD_ATOM(0);
@ -3488,10 +3444,11 @@ BEGIN_CASE(JSOP_INITMETHOD)
defineHow))) {
goto error;
}
} while (0);
}
/* Common tail for property cache hit and miss cases. */
regs.sp--;
}
END_CASE(JSOP_INITPROP);
BEGIN_CASE(JSOP_INITELEM)

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

@ -147,8 +147,9 @@ struct PropertyCacheEntry
#define JS_PROPERTY_CACHE_METERING 1
#endif
struct PropertyCache
class PropertyCache
{
private:
enum {
SIZE_LOG2 = 12,
SIZE = JS_BIT(SIZE_LOG2),
@ -158,6 +159,7 @@ struct PropertyCache
PropertyCacheEntry table[SIZE];
JSBool empty;
#ifdef JS_PROPERTY_CACHE_METERING
public:
PropertyCacheEntry *pctestentry; /* entry of the last PC-based test */
uint32 fills; /* number of cache entry fills */
uint32 nofills; /* couldn't fill (e.g. default get) */
@ -187,6 +189,7 @@ struct PropertyCache
uint32 misses; /* cache misses */
uint32 flushes; /* cache flushes */
uint32 pcpurges; /* shadowing purges on proto chain */
private:
# define PCMETER(x) x
#else
# define PCMETER(x) ((void)0)
@ -205,12 +208,46 @@ struct PropertyCache
static inline bool matchShape(JSContext *cx, JSObject *obj, uint32 shape);
JS_REQUIRES_STACK JSAtom *fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp,
JSObject **pobjp, PropertyCacheEntry *entry);
#ifdef DEBUG
void assertEmpty();
#else
inline void assertEmpty() {}
#endif
public:
JS_ALWAYS_INLINE JS_REQUIRES_STACK void test(JSContext *cx, jsbytecode *pc,
JSObject *&obj, JSObject *&pobj,
PropertyCacheEntry *&entry, JSAtom *&atom);
JS_REQUIRES_STACK JSAtom *fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp,
JSObject **pobjp, PropertyCacheEntry *entry);
/*
* Test for cached information about a property set on *objp at pc.
*
* On a fast hit, set *entryp to the entry and return true.
*
* On a slow hit, set *entryp to the entry, set *obj2p to the object that
* owns the property (either obj or a prototype), set *atomp to NULL, and
* return false.
*
* On a miss, set *atomp to the name of the property being set and return false.
*/
JS_ALWAYS_INLINE bool testForSet(JSContext *cx, jsbytecode *pc, JSObject *obj,
PropertyCacheEntry **entryp, JSObject **obj2p,
JSAtom **atomp);
/*
* Test for cached information about creating a new own data property on obj at pc.
*
* On a hit, set *spropp to an sprop from the property tree describing the
* new property as well as all existing properties on obj and return
* true. Otherwise return false.
*
* Hit or miss, *entryp receives a pointer to the property cache entry.
*/
JS_ALWAYS_INLINE bool testForInit(JSRuntime *rt, jsbytecode *pc, JSObject *obj, JSScope *scope,
JSScopeProperty **spropp, PropertyCacheEntry **entryp);
/*
* Fill property cache entry for key cx->fp->pc, optimized value word
@ -226,12 +263,6 @@ struct PropertyCache
void purge(JSContext *cx);
void purgeForScript(JSScript *script);
#ifdef DEBUG
void assertEmpty();
#else
inline void assertEmpty() {}
#endif
};
} /* namespace js */

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

@ -100,4 +100,57 @@ PropertyCache::test(JSContext *cx, jsbytecode *pc, JSObject *&obj,
PCMETER(misses++);
}
JS_ALWAYS_INLINE bool
PropertyCache::testForSet(JSContext *cx, jsbytecode *pc, JSObject *obj,
PropertyCacheEntry **entryp, JSObject **obj2p, JSAtom **atomp)
{
uint32 shape = OBJ_SHAPE(obj);
PropertyCacheEntry *entry = &table[hash(pc, shape)];
*entryp = entry;
PCMETER(pctestentry = entry);
PCMETER(tests++);
PCMETER(settests++);
if (entry->kpc == pc && entry->kshape == shape && matchShape(cx, obj, shape))
return true;
#ifdef DEBUG
JSObject *orig = obj;
#endif
JSAtom *atom = fullTest(cx, pc, &obj, obj2p, entry);
if (atom) {
PCMETER(misses++);
PCMETER(setmisses++);
} else {
JS_ASSERT(obj == orig);
}
*atomp = atom;
return false;
}
JS_ALWAYS_INLINE bool
PropertyCache::testForInit(JSRuntime *rt, jsbytecode *pc, JSObject *obj, JSScope *scope,
JSScopeProperty **spropp, PropertyCacheEntry **entryp)
{
JS_ASSERT(scope->object == obj);
JS_ASSERT(!scope->sealed());
uint32 kshape = scope->shape;
PropertyCacheEntry *entry = &table[hash(pc, kshape)];
*entryp = entry;
PCMETER(pctestentry = entry);
PCMETER(tests++);
PCMETER(initests++);
if (entry->kpc == pc &&
entry->kshape == kshape &&
entry->vshape() == rt->protoHazardShape) {
PCMETER(pchits++);
PCMETER(inipchits++);
JS_ASSERT(entry->vcapTag() == 0);
*spropp = entry->vword.toSprop();
JS_ASSERT((*spropp)->writable());
return true;
}
return false;
}
#endif /* jspropertycacheinlines_h___ */

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

@ -174,7 +174,7 @@ class HashSet;
class DeflatedStringCache;
struct PropertyCache;
class PropertyCache;
struct PropertyCacheEntry;
} /* namespace js */