Avoid needless prototype-shape purges (454035, r=igor).

This commit is contained in:
Brendan Eich 2008-09-09 11:24:03 -07:00
Родитель 4a06cffaf6
Коммит 3489dce8c9
8 изменённых файлов: 72 добавлений и 74 удалений

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

@ -1171,9 +1171,9 @@ js_MakeArraySlow(JSContext *cx, JSObject *obj)
? INT_TO_JSVAL(length) ? INT_TO_JSVAL(length)
: JSVAL_VOID; : JSVAL_VOID;
/* Make sure we preserve any flags borrowing bits in JSSLOT_CLASS. */ /* Make sure we preserve any flags borrowing bits in classword. */
obj->fslots[JSSLOT_CLASS] ^= (jsval) &js_ArrayClass; obj->classword ^= (jsuword) &js_ArrayClass;
obj->fslots[JSSLOT_CLASS] |= (jsval) &js_SlowArrayClass; obj->classword |= (jsuword) &js_SlowArrayClass;
/* Swap in our new map. */ /* Swap in our new map. */
oldmap = obj->map; oldmap = obj->map;

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

@ -469,12 +469,12 @@ js_FastNewArray(JSContext* cx, JSObject* proto)
if (!obj) if (!obj)
return NULL; return NULL;
JSClass* clasp = &js_ArrayClass;
obj->classword = jsuword(clasp);
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto); obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT]; obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
JSClass* clasp = &js_ArrayClass;
obj->fslots[JSSLOT_CLASS] = PRIVATE_TO_JSVAL(clasp);
obj->fslots[JSSLOT_ARRAY_LENGTH] = 0; obj->fslots[JSSLOT_ARRAY_LENGTH] = 0;
obj->fslots[JSSLOT_ARRAY_COUNT] = 0; obj->fslots[JSSLOT_ARRAY_COUNT] = 0;
for (unsigned i = JSSLOT_ARRAY_COUNT + 1; i != JS_INITIAL_NSLOTS; ++i) for (unsigned i = JSSLOT_ARRAY_COUNT + 1; i != JS_INITIAL_NSLOTS; ++i)
@ -514,9 +514,9 @@ js_FastNewObject(JSContext* cx, JSObject* ctor)
JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
JSObject* proto = JSVAL_TO_OBJECT(v); JSObject* proto = JSVAL_TO_OBJECT(v);
obj->classword = jsuword(clasp);
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto); obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
obj->fslots[JSSLOT_PARENT] = ctor->fslots[JSSLOT_PARENT]; obj->fslots[JSSLOT_PARENT] = ctor->fslots[JSSLOT_PARENT];
obj->fslots[JSSLOT_CLASS] = PRIVATE_TO_JSVAL(clasp);
for (unsigned i = JSSLOT_PRIVATE; i != JS_INITIAL_NSLOTS; ++i) for (unsigned i = JSSLOT_PRIVATE; i != JS_INITIAL_NSLOTS; ++i)
obj->fslots[i] = JSVAL_VOID; obj->fslots[i] = JSVAL_VOID;

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

@ -332,8 +332,7 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
PCMETER(JS_PROPERTY_CACHE(cx).idmisses++); PCMETER(JS_PROPERTY_CACHE(cx).idmisses++);
#ifdef DEBUG_notme #ifdef DEBUG_notme
entry = &JS_PROPERTY_CACHE(cx) entry = &JS_PROPERTY_CACHE(cx).table[PROPERTY_CACHE_HASH_PC(pc, OBJ_SHAPE(obj))];
.table[PROPERTY_CACHE_HASH_PC(pc, OBJ_SCOPE(obj)->shape)];
fprintf(stderr, fprintf(stderr,
"id miss for %s from %s:%u" "id miss for %s from %s:%u"
" (pc %u, kpc %u, kshape %u, shape %u)\n", " (pc %u, kpc %u, kshape %u, shape %u)\n",
@ -343,7 +342,7 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
pc - cx->fp->script->code, pc - cx->fp->script->code,
entry->kpc - cx->fp->script->code, entry->kpc - cx->fp->script->code,
entry->kshape, entry->kshape,
OBJ_SCOPE(obj)->shape); OBJ_SHAPE(obj));
js_Disassemble1(cx, cx->fp->script, pc, js_Disassemble1(cx, cx->fp->script, pc,
PTRDIFF(pc, cx->fp->script->code, jsbytecode), PTRDIFF(pc, cx->fp->script->code, jsbytecode),
JS_FALSE, stderr); JS_FALSE, stderr);
@ -384,7 +383,7 @@ js_FullTestPropertyCache(JSContext *cx, jsbytecode *pc,
--vcap; --vcap;
} }
if (PCVCAP_SHAPE(vcap) == OBJ_SCOPE(pobj)->shape) { if (PCVCAP_SHAPE(vcap) == OBJ_SHAPE(pobj)) {
#ifdef DEBUG #ifdef DEBUG
jsid id = ATOM_TO_JSID(atom); jsid id = ATOM_TO_JSID(atom);
@ -4420,7 +4419,7 @@ js_Interpret(JSContext *cx)
atom = NULL; atom = NULL;
if (JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) { if (JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) {
JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx); JSPropertyCache *cache = &JS_PROPERTY_CACHE(cx);
uint32 kshape = OBJ_SCOPE(obj)->shape; uint32 kshape = OBJ_SHAPE(obj);
/* /*
* Open-code JS_PROPERTY_CACHE_TEST, specializing for two * Open-code JS_PROPERTY_CACHE_TEST, specializing for two

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

@ -162,7 +162,7 @@ typedef struct JSInlineFrame {
PROPERTY_CACHE_HASH(pc, kshape) PROPERTY_CACHE_HASH(pc, kshape)
#define PROPERTY_CACHE_HASH_ATOM(atom,obj,pobj) \ #define PROPERTY_CACHE_HASH_ATOM(atom,obj,pobj) \
PROPERTY_CACHE_HASH((jsuword)(atom) >> 2, OBJ_SCOPE(obj)->shape) PROPERTY_CACHE_HASH((jsuword)(atom) >> 2, OBJ_SHAPE(obj))
/* /*
* Property cache value capability macros. * Property cache value capability macros.
@ -276,8 +276,8 @@ 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 OBJ_SCOPE(obj)->shape, * from obj and sprop, and entry capability forged from 24-bit OBJ_SHAPE(obj),
* scopeIndex, and protoIndex. * 4-bit scopeIndex, and 4-bit protoIndex.
*/ */
extern void extern void
js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape, js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
@ -304,8 +304,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
#define PROPERTY_CACHE_TEST(cx, pc, obj, pobj, entry, atom) \ #define PROPERTY_CACHE_TEST(cx, pc, obj, pobj, entry, atom) \
do { \ do { \
JSPropertyCache *cache_ = &JS_PROPERTY_CACHE(cx); \ JSPropertyCache *cache_ = &JS_PROPERTY_CACHE(cx); \
uint32 kshape_ = (JS_ASSERT(OBJ_IS_NATIVE(obj)), \ uint32 kshape_ = (JS_ASSERT(OBJ_IS_NATIVE(obj)), OBJ_SHAPE(obj)); \
OBJ_SCOPE(obj)->shape); \
entry = &cache_->table[PROPERTY_CACHE_HASH_PC(pc, kshape_)]; \ entry = &cache_->table[PROPERTY_CACHE_HASH_PC(pc, kshape_)]; \
PCMETER(cache_->tests++); \ PCMETER(cache_->tests++); \
JS_ASSERT(&obj != &pobj); \ JS_ASSERT(&obj != &pobj); \
@ -321,7 +320,7 @@ js_FillPropertyCache(JSContext *cx, JSObject *obj, jsuword kshape,
pobj = tmp_; \ pobj = tmp_; \
JS_LOCK_OBJ(cx, pobj); \ JS_LOCK_OBJ(cx, pobj); \
} \ } \
if (PCVCAP_SHAPE(entry->vcap) == OBJ_SCOPE(pobj)->shape) { \ if (PCVCAP_SHAPE(entry->vcap) == OBJ_SHAPE(pobj)) { \
PCMETER(cache_->pchits++); \ PCMETER(cache_->pchits++); \
PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \ PCMETER(!PCVCAP_TAG(entry->vcap) || cache_->protopchits++); \
pobj = OBJ_SCOPE(pobj)->object; \ pobj = OBJ_SCOPE(pobj)->object; \

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

@ -2559,18 +2559,19 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
obj->map = NULL; obj->map = NULL;
obj->dslots = NULL; obj->dslots = NULL;
/*
* Set the class slot with the initial value of the system and delegate
* flags set to false.
*/
JS_ASSERT(((jsuword) clasp & 3) == 0);
obj->classword = jsuword(clasp);
JS_ASSERT(!STOBJ_IS_DELEGATE(obj));
JS_ASSERT(!STOBJ_IS_SYSTEM(obj));
/* Set the proto and parent properties. */ /* Set the proto and parent properties. */
STOBJ_SET_PROTO(obj, proto); STOBJ_SET_PROTO(obj, proto);
STOBJ_SET_PARENT(obj, parent); STOBJ_SET_PARENT(obj, parent);
/*
* Set the class slot with the initial value of the system flag set to
* false.
*/
JS_ASSERT(((jsuword) clasp & 3) == 0);
STOBJ_SET_SLOT(obj, JSSLOT_CLASS, PRIVATE_TO_JSVAL(clasp));
JS_ASSERT(!STOBJ_IS_SYSTEM(obj));
/* Initialize the remaining fixed slots. */ /* Initialize the remaining fixed slots. */
for (i = JSSLOT_PRIVATE; i != JS_INITIAL_NSLOTS; ++i) for (i = JSSLOT_PRIVATE; i != JS_INITIAL_NSLOTS; ++i)
obj->fslots[i] = JSVAL_VOID; obj->fslots[i] = JSVAL_VOID;
@ -3026,6 +3027,9 @@ PurgeProtoChain(JSContext *cx, JSObject *obj, jsid id)
static void static void
PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id) PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id)
{ {
if (!OBJ_IS_DELEGATE(cx, obj))
return;
PurgeProtoChain(cx, OBJ_GET_PROTO(cx, obj), id); PurgeProtoChain(cx, OBJ_GET_PROTO(cx, obj), id);
while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL) { while ((obj = OBJ_GET_PARENT(cx, obj)) != NULL) {
if (PurgeProtoChain(cx, obj, id)) if (PurgeProtoChain(cx, obj, id))
@ -3491,13 +3495,13 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp,
JSPropCacheEntry **entryp) JSPropCacheEntry **entryp)
{ {
JSObject *obj, *pobj, *lastobj; JSObject *obj, *pobj, *lastobj;
uint32 type; uint32 shape;
int scopeIndex, protoIndex; int scopeIndex, protoIndex;
JSProperty *prop; JSProperty *prop;
JSScopeProperty *sprop; JSScopeProperty *sprop;
obj = cx->fp->scopeChain; obj = cx->fp->scopeChain;
type = OBJ_SCOPE(obj)->shape; shape = OBJ_SHAPE(obj);
for (scopeIndex = 0; ; scopeIndex++) { for (scopeIndex = 0; ; scopeIndex++) {
if (obj->map->ops->lookupProperty == js_LookupProperty) { if (obj->map->ops->lookupProperty == js_LookupProperty) {
protoIndex = protoIndex =
@ -3512,7 +3516,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSObject **objp,
if (entryp) { if (entryp) {
if (protoIndex >= 0 && OBJ_IS_NATIVE(pobj)) { if (protoIndex >= 0 && OBJ_IS_NATIVE(pobj)) {
sprop = (JSScopeProperty *) prop; sprop = (JSScopeProperty *) prop;
js_FillPropertyCache(cx, cx->fp->scopeChain, type, js_FillPropertyCache(cx, cx->fp->scopeChain, shape,
scopeIndex, protoIndex, pobj, sprop, scopeIndex, protoIndex, pobj, sprop,
entryp); entryp);
} else { } else {
@ -3687,7 +3691,7 @@ JSBool
js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
JSPropCacheEntry **entryp) JSPropCacheEntry **entryp)
{ {
uint32 type; uint32 shape;
int protoIndex; int protoIndex;
JSObject *obj2; JSObject *obj2;
JSProperty *prop; JSProperty *prop;
@ -3697,7 +3701,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
CHECK_FOR_STRING_INDEX(id); CHECK_FOR_STRING_INDEX(id);
JS_COUNT_OPERATION(cx, JSOW_GET_PROPERTY); JS_COUNT_OPERATION(cx, JSOW_GET_PROPERTY);
type = OBJ_SCOPE(obj)->shape; shape = OBJ_SHAPE(obj);
protoIndex = js_LookupPropertyWithFlags(cx, obj, id, 0, &obj2, &prop); protoIndex = js_LookupPropertyWithFlags(cx, obj, id, 0, &obj2, &prop);
if (protoIndex < 0) if (protoIndex < 0)
return JS_FALSE; return JS_FALSE;
@ -3767,10 +3771,8 @@ 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 (entryp)
js_FillPropertyCache(cx, obj, type, 0, protoIndex, obj2, sprop, js_FillPropertyCache(cx, obj, shape, 0, protoIndex, obj2, sprop, entryp);
entryp);
}
JS_UNLOCK_OBJ(cx, obj2); JS_UNLOCK_OBJ(cx, obj2);
return JS_TRUE; return JS_TRUE;
} }
@ -3785,7 +3787,7 @@ JSBool
js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
JSPropCacheEntry **entryp) JSPropCacheEntry **entryp)
{ {
uint32 type; uint32 shape;
int protoIndex; int protoIndex;
JSObject *pobj; JSObject *pobj;
JSProperty *prop; JSProperty *prop;
@ -3800,7 +3802,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
CHECK_FOR_STRING_INDEX(id); CHECK_FOR_STRING_INDEX(id);
JS_COUNT_OPERATION(cx, JSOW_SET_PROPERTY); JS_COUNT_OPERATION(cx, JSOW_SET_PROPERTY);
type = OBJ_SCOPE(obj)->shape; shape = OBJ_SHAPE(obj);
protoIndex = js_LookupPropertyWithFlags(cx, obj, id, 0, &pobj, &prop); protoIndex = js_LookupPropertyWithFlags(cx, obj, id, 0, &pobj, &prop);
if (protoIndex < 0) if (protoIndex < 0)
return JS_FALSE; return JS_FALSE;
@ -3868,16 +3870,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
* NB: Thanks to the immutable, garbage-collected property tree * NB: Thanks to the immutable, garbage-collected property tree
* maintained by jsscope.c in cx->runtime, we needn't worry about * maintained by jsscope.c in cx->runtime, we needn't worry about
* sprop going away behind our back after we've unlocked scope. * sprop going away behind our back after we've unlocked scope.
*
* But if we are shadowing (not sharing) the proto-property, then
* we need to regenerate the property cache shape id for scope, in
* case the cache contains the old type in an entry value that was
* filled by a get on obj that delegated up the prototype chain to
* pobj. Once we've shadowed the proto-property, that cache entry
* must not be hit.
*/ */
if (!(attrs & JSPROP_SHARED))
SCOPE_MAKE_UNIQUE_SHAPE(cx, scope);
JS_UNLOCK_SCOPE(cx, scope); JS_UNLOCK_SCOPE(cx, scope);
/* /*
@ -3979,7 +3972,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
if (entryp) { if (entryp) {
if (!(attrs & JSPROP_SHARED)) if (!(attrs & JSPROP_SHARED))
js_FillPropertyCache(cx, obj, type, 0, 0, obj, sprop, entryp); js_FillPropertyCache(cx, obj, shape, 0, 0, obj, sprop, entryp);
else else
PCMETER(JS_PROPERTY_CACHE(cx).nofills++); PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
} }

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

@ -120,7 +120,7 @@ struct JSObjectMap {
} \ } \
JS_END_MACRO JS_END_MACRO
#define JS_INITIAL_NSLOTS 6 #define JS_INITIAL_NSLOTS 5
/* /*
* When JSObject.dslots is not null, JSObject.dslots[-1] records the number of * When JSObject.dslots is not null, JSObject.dslots[-1] records the number of
@ -128,17 +128,17 @@ struct JSObjectMap {
*/ */
struct JSObject { struct JSObject {
JSObjectMap *map; JSObjectMap *map;
jsuword classword;
jsval fslots[JS_INITIAL_NSLOTS]; jsval fslots[JS_INITIAL_NSLOTS];
jsval *dslots; /* dynamically allocated slots */ jsval *dslots; /* dynamically allocated slots */
}; };
#define JSSLOT_PROTO 0 #define JSSLOT_PROTO 0
#define JSSLOT_PARENT 1 #define JSSLOT_PARENT 1
#define JSSLOT_CLASS 2 #define JSSLOT_PRIVATE 2
#define JSSLOT_PRIVATE 3
#define JSSLOT_START(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \ #define JSSLOT_START(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \
? JSSLOT_PRIVATE + 1 \ ? JSSLOT_PRIVATE + 1 \
: JSSLOT_CLASS + 1) : JSSLOT_PARENT + 1)
#define JSSLOT_FREE(clasp) (JSSLOT_START(clasp) \ #define JSSLOT_FREE(clasp) (JSSLOT_START(clasp) \
+ JSCLASS_RESERVED_SLOTS(clasp)) + JSCLASS_RESERVED_SLOTS(clasp))
@ -167,26 +167,29 @@ struct JSObject {
#define STOBJ_GET_PROTO(obj) \ #define STOBJ_GET_PROTO(obj) \
JSVAL_TO_OBJECT((obj)->fslots[JSSLOT_PROTO]) JSVAL_TO_OBJECT((obj)->fslots[JSSLOT_PROTO])
#define STOBJ_SET_PROTO(obj,proto) \ #define STOBJ_SET_PROTO(obj,proto) \
((obj)->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto)) (void)((!(proto) || STOBJ_SET_DELEGATE(proto)), \
(obj)->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto))
#define STOBJ_CLEAR_PROTO(obj) \ #define STOBJ_CLEAR_PROTO(obj) \
((obj)->fslots[JSSLOT_PROTO] = JSVAL_NULL) ((obj)->fslots[JSSLOT_PROTO] = JSVAL_NULL)
#define STOBJ_GET_PARENT(obj) \ #define STOBJ_GET_PARENT(obj) \
JSVAL_TO_OBJECT((obj)->fslots[JSSLOT_PARENT]) JSVAL_TO_OBJECT((obj)->fslots[JSSLOT_PARENT])
#define STOBJ_SET_PARENT(obj,parent) \ #define STOBJ_SET_PARENT(obj,parent) \
((obj)->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent)) (void)((!(parent) || STOBJ_SET_DELEGATE(parent)), \
(obj)->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent))
#define STOBJ_CLEAR_PARENT(obj) \ #define STOBJ_CLEAR_PARENT(obj) \
((obj)->fslots[JSSLOT_PARENT] = JSVAL_NULL) ((obj)->fslots[JSSLOT_PARENT] = JSVAL_NULL)
/* /*
* We use JSSLOT_CLASS to store both JSClass* and the system flag as an int- * We use JSObject.classword to store both JSClass* and the delegate and system
* tagged value (see jsapi.h for details) with the system flag stored in the * flags in the two least significant bits. We do *not* synchronize updates of
* second lowest bit. * obj->classword -- API clients must take care.
*/ */
#define STOBJ_GET_CLASS(obj) ((JSClass *)((obj)->fslots[JSSLOT_CLASS] & ~3)) #define STOBJ_GET_CLASS(obj) ((JSClass *)((obj)->classword & ~3))
#define STOBJ_IS_SYSTEM(obj) (((obj)->fslots[JSSLOT_CLASS] & 2) != 0) #define STOBJ_IS_DELEGATE(obj) (((obj)->classword & 1) != 0)
#define STOBJ_SET_DELEGATE(obj) ((obj)->classword |= 1)
#define STOBJ_SET_SYSTEM(obj) ((void)((obj)->fslots[JSSLOT_CLASS] |= 2)) #define STOBJ_IS_SYSTEM(obj) (((obj)->classword & 2) != 0)
#define STOBJ_SET_SYSTEM(obj) ((obj)->classword |= 2)
#define STOBJ_GET_PRIVATE(obj) \ #define STOBJ_GET_PRIVATE(obj) \
(JS_ASSERT(JSVAL_IS_INT(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE))), \ (JS_ASSERT(JSVAL_IS_INT(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE))), \
@ -227,7 +230,7 @@ struct JSObject {
(OBJ_CHECK_SLOT(obj, JSSLOT_PARENT), STOBJ_SET_PARENT(obj, parent)) (OBJ_CHECK_SLOT(obj, JSSLOT_PARENT), STOBJ_SET_PARENT(obj, parent))
#define LOCKED_OBJ_GET_CLASS(obj) \ #define LOCKED_OBJ_GET_CLASS(obj) \
(OBJ_CHECK_SLOT(obj, JSSLOT_CLASS), STOBJ_GET_CLASS(obj)) STOBJ_GET_CLASS(obj)
#define LOCKED_OBJ_GET_PRIVATE(obj) \ #define LOCKED_OBJ_GET_PRIVATE(obj) \
(OBJ_CHECK_SLOT(obj, JSSLOT_PRIVATE), STOBJ_GET_PRIVATE(obj)) (OBJ_CHECK_SLOT(obj, JSSLOT_PRIVATE), STOBJ_GET_PRIVATE(obj))
@ -276,7 +279,10 @@ struct JSObject {
#endif /* !JS_THREADSAFE */ #endif /* !JS_THREADSAFE */
/* Thread-safe proto, parent, and class access macros. */ /* Thread-safe delegate, proto, parent, and class access macros. */
#define OBJ_IS_DELEGATE(cx,obj) STOBJ_IS_DELEGATE(obj)
#define OBJ_SET_DELEGATE(cx,obj) STOBJ_SET_DELEGATE(obj)
#define OBJ_GET_PROTO(cx,obj) STOBJ_GET_PROTO(obj) #define OBJ_GET_PROTO(cx,obj) STOBJ_GET_PROTO(obj)
#define OBJ_SET_PROTO(cx,obj,proto) STOBJ_SET_PROTO(obj, proto) #define OBJ_SET_PROTO(cx,obj,proto) STOBJ_SET_PROTO(obj, proto)
#define OBJ_CLEAR_PROTO(cx,obj) STOBJ_CLEAR_PROTO(obj) #define OBJ_CLEAR_PROTO(cx,obj) STOBJ_CLEAR_PROTO(obj)
@ -286,7 +292,7 @@ struct JSObject {
#define OBJ_CLEAR_PARENT(cx,obj) STOBJ_CLEAR_PARENT(obj) #define OBJ_CLEAR_PARENT(cx,obj) STOBJ_CLEAR_PARENT(obj)
/* /*
* Class is invariant and comes from the fixed JSSLOT_CLASS. Thus no locking * Class is invariant and comes from the fixed clasp member. Thus no locking
* is necessary to read it. Same for the private slot. * is necessary to read it. Same for the private slot.
*/ */
#define OBJ_GET_CLASS(cx,obj) STOBJ_GET_CLASS(obj) #define OBJ_GET_CLASS(cx,obj) STOBJ_GET_CLASS(obj)

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

@ -218,6 +218,7 @@ JS_STATIC_ASSERT(offsetof(JSScope, title) == sizeof(JSObjectMap));
#define JS_IS_SCOPE_LOCKED(cx, scope) JS_IS_TITLE_LOCKED(cx, &(scope)->title) #define JS_IS_SCOPE_LOCKED(cx, scope) JS_IS_TITLE_LOCKED(cx, &(scope)->title)
#define OBJ_SCOPE(obj) ((JSScope *)(obj)->map) #define OBJ_SCOPE(obj) ((JSScope *)(obj)->map)
#define OBJ_SHAPE(obj) (OBJ_SCOPE(obj)->shape)
#define SCOPE_MAKE_UNIQUE_SHAPE(cx,scope) \ #define SCOPE_MAKE_UNIQUE_SHAPE(cx,scope) \
((scope)->shape = js_GenerateShape((cx), JS_FALSE)) ((scope)->shape = js_GenerateShape((cx), JS_FALSE))

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

@ -1314,7 +1314,7 @@ TraceRecorder::lazilyImportGlobalSlot(unsigned slot)
unsigned index = traceMonitor->globalSlots->length(); unsigned index = traceMonitor->globalSlots->length();
/* If this the first global we are adding, remember the shape of the global object. */ /* If this the first global we are adding, remember the shape of the global object. */
if (index == 0) if (index == 0)
traceMonitor->globalShape = OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->shape; traceMonitor->globalShape = OBJ_SHAPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain));
/* Add the slot to the list of interned global slots. */ /* Add the slot to the list of interned global slots. */
traceMonitor->globalSlots->add(slot); traceMonitor->globalSlots->add(slot);
uint8 type = getCoercedType(*vp); uint8 type = getCoercedType(*vp);
@ -2008,7 +2008,7 @@ bool
js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f) js_RecordTree(JSContext* cx, JSTraceMonitor* tm, Fragment* f)
{ {
/* Make sure the global type map didn't change on us. */ /* Make sure the global type map didn't change on us. */
uint32 globalShape = OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->shape; uint32 globalShape = OBJ_SHAPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain));
if (tm->globalShape != globalShape) { if (tm->globalShape != globalShape) {
debug_only_v(printf("Global shape mismatch (%u vs. %u) in RecordTree, flushing cache.\n", debug_only_v(printf("Global shape mismatch (%u vs. %u) in RecordTree, flushing cache.\n",
globalShape, tm->globalShape);) globalShape, tm->globalShape);)
@ -2233,11 +2233,11 @@ js_ExecuteTree(JSContext* cx, Fragment** treep, uintN& inlineCallCount,
the global type map must remain applicable at all times (we expect absolute type the global type map must remain applicable at all times (we expect absolute type
stability for globals). */ stability for globals). */
if (ngslots && if (ngslots &&
(OBJ_SCOPE(globalObj)->shape != tm->globalShape || (OBJ_SHAPE(globalObj) != tm->globalShape ||
!BuildNativeGlobalFrame(cx, ngslots, gslots, tm->globalTypeMap->data(), global))) { !BuildNativeGlobalFrame(cx, ngslots, gslots, tm->globalTypeMap->data(), global))) {
AUDIT(globalShapeMismatchAtEntry); AUDIT(globalShapeMismatchAtEntry);
debug_only_v(printf("Global shape mismatch (%u vs. %u), flushing cache.\n", debug_only_v(printf("Global shape mismatch (%u vs. %u), flushing cache.\n",
OBJ_SCOPE(globalObj)->shape, tm->globalShape);) OBJ_SHAPE(globalObj), tm->globalShape);)
const void* ip = f->ip; const void* ip = f->ip;
js_FlushJITCache(cx); js_FlushJITCache(cx);
*treep = tm->fragmento->newLoop(ip); *treep = tm->fragmento->newLoop(ip);
@ -2625,7 +2625,7 @@ js_FlushJITCache(JSContext* cx)
} }
memset(&tm->fcache, 0, sizeof(tm->fcache)); memset(&tm->fcache, 0, sizeof(tm->fcache));
if (cx->fp) { if (cx->fp) {
tm->globalShape = OBJ_SCOPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain))->shape; tm->globalShape = OBJ_SHAPE(JS_GetGlobalForObject(cx, cx->fp->scopeChain));
tm->globalSlots->clear(); tm->globalSlots->clear();
tm->globalTypeMap->clear(); tm->globalTypeMap->clear();
} }
@ -3249,7 +3249,7 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
ABORT_TRACE("failed to lookup property"); ABORT_TRACE("failed to lookup property");
if (prop) { if (prop) {
js_FillPropertyCache(cx, aobj, OBJ_SCOPE(aobj)->shape, 0, protoIndex, obj2, js_FillPropertyCache(cx, aobj, OBJ_SHAPE(aobj), 0, protoIndex, obj2,
(JSScopeProperty*) prop, &entry); (JSScopeProperty*) prop, &entry);
} }
} }
@ -3319,7 +3319,7 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
if (PCVCAP_TAG(entry->vcap) >= 1) { if (PCVCAP_TAG(entry->vcap) >= 1) {
jsuword vcap = entry->vcap; jsuword vcap = entry->vcap;
uint32 vshape = PCVCAP_SHAPE(vcap); uint32 vshape = PCVCAP_SHAPE(vcap);
JS_ASSERT(OBJ_SCOPE(obj2)->shape == vshape); JS_ASSERT(OBJ_SHAPE(obj2) == vshape);
LIns* obj2_ins = INS_CONSTPTR(obj2); LIns* obj2_ins = INS_CONSTPTR(obj2);
map_ins = lir->insLoad(LIR_ldp, obj2_ins, (int)offsetof(JSObject, map)); map_ins = lir->insLoad(LIR_ldp, obj2_ins, (int)offsetof(JSObject, map));
@ -3530,7 +3530,7 @@ TraceRecorder::guardClass(JSObject* obj, LIns* obj_ins, JSClass* clasp)
if (STOBJ_GET_CLASS(obj) != clasp) if (STOBJ_GET_CLASS(obj) != clasp)
return false; return false;
LIns* class_ins = stobj_get_fslot(obj_ins, JSSLOT_CLASS); LIns* class_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, classword));
class_ins = lir->ins2(LIR_piand, class_ins, lir->insImm(~3)); class_ins = lir->ins2(LIR_piand, class_ins, lir->insImm(~3));
char namebuf[32]; char namebuf[32];
@ -4263,7 +4263,7 @@ TraceRecorder::record_JSOP_SETPROP()
LIns* obj_ins = get(&l); LIns* obj_ins = get(&l);
JSPropertyCache* cache = &JS_PROPERTY_CACHE(cx); JSPropertyCache* cache = &JS_PROPERTY_CACHE(cx);
uint32 kshape = OBJ_SCOPE(obj)->shape; uint32 kshape = OBJ_SHAPE(obj);
jsbytecode* pc = cx->fp->regs->pc; jsbytecode* pc = cx->fp->regs->pc;
JSPropCacheEntry* entry = &cache->table[PROPERTY_CACHE_HASH_PC(pc, kshape)]; JSPropCacheEntry* entry = &cache->table[PROPERTY_CACHE_HASH_PC(pc, kshape)];