Bug 500431 part 2 - Replace macros with inline functions in jspropertycache. r=brendan.

--HG--
extra : rebase_source : efb0e75798145ff1bb64607262345aea67a51290
This commit is contained in:
Jason Orendorff 2010-03-24 16:16:45 -05:00
parent 25153c3c13
commit dbf25821e4
2 changed files with 105 additions and 79 deletions

View File

@ -49,42 +49,63 @@ JS_BEGIN_EXTERN_C
* polymorphic callsite method/get/set speedups. For details, see
* <https://developer.mozilla.org/en/SpiderMonkey/Internals/Property_cache>.
*/
#define PROPERTY_CACHE_LOG2 12
#define PROPERTY_CACHE_SIZE JS_BIT(PROPERTY_CACHE_LOG2)
#define PROPERTY_CACHE_MASK JS_BITMASK(PROPERTY_CACHE_LOG2)
enum {
PROPERTY_CACHE_LOG2 = 12,
PROPERTY_CACHE_SIZE = JS_BIT(PROPERTY_CACHE_LOG2),
PROPERTY_CACHE_MASK = JS_BITMASK(PROPERTY_CACHE_LOG2)
};
/*
* Add kshape rather than xor it to avoid collisions between nearby bytecode
* that are evolving an object by setting successive properties, incrementing
* the object's scope->shape on each set.
*/
#define PROPERTY_CACHE_HASH(pc,kshape) \
(((((jsuword)(pc) >> PROPERTY_CACHE_LOG2) ^ (jsuword)(pc)) + (kshape)) & \
PROPERTY_CACHE_MASK)
inline jsuword
PROPERTY_CACHE_HASH(jsbytecode *pc, jsuword kshape)
{
return ((((jsuword(pc) >> PROPERTY_CACHE_LOG2) ^ jsuword(pc)) + kshape) & PROPERTY_CACHE_MASK);
}
/*
* Property cache value capability macros.
*/
#define PCVCAP_PROTOBITS 4
#define PCVCAP_PROTOSIZE JS_BIT(PCVCAP_PROTOBITS)
#define PCVCAP_PROTOMASK JS_BITMASK(PCVCAP_PROTOBITS)
/* Property cache value capabilities. */
enum {
PCVCAP_PROTOBITS = 4,
PCVCAP_PROTOSIZE = JS_BIT(PCVCAP_PROTOBITS),
PCVCAP_PROTOMASK = JS_BITMASK(PCVCAP_PROTOBITS),
#define PCVCAP_SCOPEBITS 4
#define PCVCAP_SCOPESIZE JS_BIT(PCVCAP_SCOPEBITS)
#define PCVCAP_SCOPEMASK JS_BITMASK(PCVCAP_SCOPEBITS)
PCVCAP_SCOPEBITS = 4,
PCVCAP_SCOPESIZE = JS_BIT(PCVCAP_SCOPEBITS),
PCVCAP_SCOPEMASK = JS_BITMASK(PCVCAP_SCOPEBITS),
#define PCVCAP_TAGBITS (PCVCAP_PROTOBITS + PCVCAP_SCOPEBITS)
#define PCVCAP_TAGMASK JS_BITMASK(PCVCAP_TAGBITS)
#define PCVCAP_TAG(t) ((t) & PCVCAP_TAGMASK)
PCVCAP_TAGBITS = PCVCAP_PROTOBITS + PCVCAP_SCOPEBITS,
PCVCAP_TAGMASK = JS_BITMASK(PCVCAP_TAGBITS)
};
#define PCVCAP_MAKE(t,s,p) ((uint32(t) << PCVCAP_TAGBITS) | \
((s) << PCVCAP_PROTOBITS) | \
(p))
#define PCVCAP_SHAPE(t) ((t) >> PCVCAP_TAGBITS)
const uint32 SHAPE_OVERFLOW_BIT = JS_BIT(32 - PCVCAP_TAGBITS);
#define SHAPE_OVERFLOW_BIT JS_BIT(32 - PCVCAP_TAGBITS)
inline jsuword
PCVCAP_TAG(jsuword t)
{
return t & PCVCAP_TAGMASK;
}
struct JSPropCacheEntry {
inline jsuword
PCVCAP_MAKE(uint32 t, unsigned int s, unsigned int p)
{
JS_ASSERT(t < SHAPE_OVERFLOW_BIT);
JS_ASSERT(s <= PCVCAP_SCOPEMASK);
JS_ASSERT(p <= PCVCAP_PROTOMASK);
return (t << PCVCAP_TAGBITS) | (s << PCVCAP_PROTOBITS) | p;
}
inline uint32
PCVCAP_SHAPE(jsuword t)
{
return t >> PCVCAP_TAGBITS;
}
struct JSPropCacheEntry
{
jsbytecode *kpc; /* pc of cache-testing bytecode */
jsuword kshape; /* shape of direct (key) object */
jsuword vcap; /* value capability, see above */
@ -153,33 +174,37 @@ typedef struct JSPropertyCache {
/*
* Property cache value tagging/untagging macros.
*/
#define PCVAL_OBJECT 0
#define PCVAL_SLOT 1
#define PCVAL_SPROP 2
enum {
PCVAL_OBJECT = 0,
PCVAL_SLOT = 1,
PCVAL_SPROP = 2,
#define PCVAL_TAGBITS 2
#define PCVAL_TAGMASK JS_BITMASK(PCVAL_TAGBITS)
#define PCVAL_TAG(v) ((v) & PCVAL_TAGMASK)
#define PCVAL_CLRTAG(v) ((v) & ~(jsuword)PCVAL_TAGMASK)
#define PCVAL_SETTAG(v,t) ((jsuword)(v) | (t))
PCVAL_TAGBITS = 2,
PCVAL_TAGMASK = JS_BITMASK(PCVAL_TAGBITS),
#define PCVAL_NULL 0
#define PCVAL_IS_NULL(v) ((v) == PCVAL_NULL)
PCVAL_NULL = 0
};
#define PCVAL_IS_OBJECT(v) (PCVAL_TAG(v) == PCVAL_OBJECT)
#define PCVAL_TO_OBJECT(v) ((JSObject *) (v))
#define OBJECT_TO_PCVAL(obj) ((jsuword) (obj))
inline jsuword PCVAL_TAG(jsuword v) { return v & PCVAL_TAGMASK; }
inline jsuword PCVAL_CLRTAG(jsuword v) { return v & ~jsuword(PCVAL_TAGMASK); }
inline jsuword PCVAL_SETTAG(jsuword v, jsuword t) { return v | t; }
#define PCVAL_OBJECT_TO_JSVAL(v) OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v))
#define JSVAL_OBJECT_TO_PCVAL(v) OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v))
inline bool PCVAL_IS_NULL(jsuword v) { return v == PCVAL_NULL; }
#define PCVAL_IS_SLOT(v) ((v) & PCVAL_SLOT)
#define PCVAL_TO_SLOT(v) ((jsuint)(v) >> 1)
#define SLOT_TO_PCVAL(i) (((jsuword)(i) << 1) | PCVAL_SLOT)
inline bool PCVAL_IS_OBJECT(jsuword v) { return PCVAL_TAG(v) == PCVAL_OBJECT; }
inline JSObject *PCVAL_TO_OBJECT(jsuword v) { JS_ASSERT(PCVAL_IS_OBJECT(v)); return (JSObject *) v; }
inline jsuword OBJECT_TO_PCVAL(JSObject *obj) { return jsuword(obj); }
#define PCVAL_IS_SPROP(v) (PCVAL_TAG(v) == PCVAL_SPROP)
#define PCVAL_TO_SPROP(v) ((JSScopeProperty *) PCVAL_CLRTAG(v))
#define SPROP_TO_PCVAL(sprop) PCVAL_SETTAG(sprop, PCVAL_SPROP)
inline jsval PCVAL_OBJECT_TO_JSVAL(jsuword v) { return OBJECT_TO_JSVAL(PCVAL_TO_OBJECT(v)); }
inline jsuword JSVAL_OBJECT_TO_PCVAL(jsval v) { return OBJECT_TO_PCVAL(JSVAL_TO_OBJECT(v)); }
inline bool PCVAL_IS_SLOT(jsuword v) { return v & PCVAL_SLOT; }
inline jsuint PCVAL_TO_SLOT(jsuword v) { JS_ASSERT(PCVAL_IS_SLOT(v)); return jsuint(v) >> 1; }
inline jsuword SLOT_TO_PCVAL(jsuint i) { return (jsuword(i) << 1) | PCVAL_SLOT; }
inline bool PCVAL_IS_SPROP(jsuword v) { return PCVAL_TAG(v) == PCVAL_SPROP; }
inline JSScopeProperty *PCVAL_TO_SPROP(jsuword v) { JS_ASSERT(PCVAL_IS_SPROP(v)); return (JSScopeProperty *) PCVAL_CLRTAG(v); }
inline jsuword SPROP_TO_PCVAL(JSScopeProperty *sprop) { return PCVAL_SETTAG(jsuword(sprop), PCVAL_SPROP); }
/*
* Fill property cache entry for key cx->fp->pc, optimized value word computed

View File

@ -42,8 +42,7 @@
#ifndef jspropertycacheinlines_h___
#define jspropertycacheinlines_h___
#include "jsinterp.h"
#include "jslock.h"
#include "jspropertycache.h"
#include "jsscope.h"
/* static */ inline bool
@ -53,10 +52,10 @@ JSPropCacheEntry::matchShape(JSContext *cx, JSObject *obj, uint32 shape)
}
/*
* Property cache lookup macros. PROPERTY_CACHE_TEST is designed to inline the
* fast path in js_Interpret, so it makes "just-so" restrictions on parameters,
* e.g. pobj and obj should not be the same variable, since for JOF_PROP-mode
* opcodes, obj must not be changed because of a cache miss.
* PROPERTY_CACHE_TEST is designed to inline the fast path in js_Interpret, so
* it makes "just-so" restrictions on parameters, e.g. pobj and obj should not
* be the same variable, since for JOF_PROP-mode opcodes, obj must not be
* changed because of a cache miss.
*
* On return from PROPERTY_CACHE_TEST, if atom is null then obj points to the
* scope chain element in which the property was found, pobj is locked, and
@ -68,33 +67,35 @@ JSPropCacheEntry::matchShape(JSContext *cx, JSObject *obj, uint32 shape)
* be deleting a property from its scope, or otherwise invalidating property
* caches (on all threads) by re-generating scope->shape.
*/
#define PROPERTY_CACHE_TEST(cx, pc, obj, pobj, entry, atom) \
do { \
JSPropertyCache *cache_ = &JS_PROPERTY_CACHE(cx); \
uint32 kshape_ = (JS_ASSERT(OBJ_IS_NATIVE(obj)), OBJ_SHAPE(obj)); \
entry = &cache_->table[PROPERTY_CACHE_HASH(pc, kshape_)]; \
PCMETER(cache_->pctestentry = entry); \
PCMETER(cache_->tests++); \
JS_ASSERT(&obj != &pobj); \
if (entry->kpc == pc && entry->kshape == kshape_) { \
JSObject *tmp_; \
pobj = obj; \
if (PCVCAP_TAG(entry->vcap) == 1 && \
(tmp_ = pobj->getProto()) != NULL) { \
pobj = tmp_; \
} \
\
if (JSPropCacheEntry::matchShape(cx, pobj, \
PCVCAP_SHAPE(entry->vcap))) { \
PCMETER(cache_->pchits++); \
PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \
atom = NULL; \
break; \
} \
} \
atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, entry); \
if (atom) \
PCMETER(cache_->misses++); \
} while (0)
JS_ALWAYS_INLINE void
PROPERTY_CACHE_TEST(JSContext *cx, jsbytecode *pc, JSObject *&obj,
JSObject *&pobj, JSPropCacheEntry *&entry, JSAtom *&atom)
{
JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx);
JS_ASSERT(OBJ_IS_NATIVE(obj));
uint32 kshape = OBJ_SHAPE(obj);
entry = &cache->table[PROPERTY_CACHE_HASH(pc, kshape)];
PCMETER(cache->pctestentry = entry);
PCMETER(cache->tests++);
JS_ASSERT(&obj != &pobj);
if (entry->kpc == pc && entry->kshape == kshape) {
JSObject *tmp;
pobj = obj;
if (PCVCAP_TAG(entry->vcap) == 1 &&
(tmp = pobj->getProto()) != NULL) {
pobj = tmp;
}
if (JSPropCacheEntry::matchShape(cx, pobj, PCVCAP_SHAPE(entry->vcap))) {
PCMETER(cache->pchits++);
PCMETER(!PCVCAP_TAG(entry->vcap) || cache->protopchits++);
atom = NULL;
return;
}
}
atom = js_FullTestPropertyCache(cx, pc, &obj, &pobj, entry);
if (atom)
PCMETER(cache->misses++);
}
#endif /* jspropertycacheinlines_h___ */