Bug 539829 - Encapsulate JSScope::flags. r=Waldo.

--HG--
extra : rebase_source : ced4f057e715075d8e4eff343e824d8934152a7e
This commit is contained in:
Jason Orendorff 2010-02-05 18:11:13 -06:00
Родитель da6fb77bda
Коммит 99f75d684d
15 изменённых файлов: 239 добавлений и 203 удалений

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

@ -2964,7 +2964,7 @@ JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
for (ok = JS_TRUE; ps->name; ps++) {
ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
ps->getter, ps->setter, ps->flags,
SPROP_HAS_SHORTID, ps->tinyid);
JSScopeProperty::HAS_SHORTID, ps->tinyid);
if (!ok)
break;
}
@ -2995,7 +2995,7 @@ JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
{
CHECK_REQUEST(cx);
return DefineProperty(cx, obj, name, value, getter, setter, attrs,
SPROP_HAS_SHORTID, tinyid);
JSScopeProperty::HAS_SHORTID, tinyid);
}
static JSBool
@ -3062,7 +3062,7 @@ JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
sprop = (JSScopeProperty *)prop;
ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
sprop->getter, sprop->setter, sprop->slot,
sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
sprop->attrs, sprop->getFlags() | JSScopeProperty::ALIAS,
sprop->shortid)
!= NULL);
}
@ -3564,7 +3564,7 @@ JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
{
CHECK_REQUEST(cx);
return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
attrs, SPROP_HAS_SHORTID, tinyid);
attrs, JSScopeProperty::HAS_SHORTID, tinyid);
}
JS_PUBLIC_API(JSBool)
@ -3735,7 +3735,7 @@ JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
sprop = (JSScopeProperty *)prop;
ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
sprop->getter, sprop->setter, sprop->slot,
sprop->attrs, sprop->flags | SPROP_IS_ALIAS,
sprop->attrs, sprop->getFlags() | JSScopeProperty::ALIAS,
sprop->shortid)
!= NULL);
obj->dropProperty(cx, prop);
@ -4008,11 +4008,8 @@ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
* line is not enumerable, or it's an alias, skip it and keep on trying
* to find an enumerable property that is still in scope.
*/
while (sprop &&
(!(sprop->attrs & JSPROP_ENUMERATE) ||
(sprop->flags & SPROP_IS_ALIAS))) {
while (sprop && (!sprop->enumerable() || sprop->isAlias()))
sprop = sprop->parent;
}
if (!sprop) {
*idp = JSVAL_VOID;

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

@ -266,7 +266,7 @@ js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
} else {
JSScopeProperty *sprop2 =
scope->addProperty(cx, sprop->id, sprop->getter, sprop->setter, SPROP_INVALID_SLOT,
sprop->attrs, sprop->flags, sprop->shortid);
sprop->attrs, sprop->getFlags(), sprop->shortid);
if (sprop2 != sprop)
goto exit_trace;
}

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

@ -623,9 +623,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
JS_LOCK_OBJ(cx, obj);
propid = ID_TO_VALUE(sprop->id);
userid = (sprop->flags & SPROP_HAS_SHORTID)
? INT_TO_JSVAL(sprop->shortid)
: propid;
userid = SPROP_USERID(sprop);
scope = OBJ_SCOPE(obj);
JS_UNLOCK_OBJ(cx, obj);
@ -880,7 +878,7 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval,
getter = sprop->getter;
setter = sprop->setter;
attrs = sprop->attrs;
flags = sprop->flags;
flags = sprop->getFlags();
shortid = sprop->shortid;
} else {
if (!pobj->getProperty(cx, propid, &value) ||

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

@ -1590,7 +1590,7 @@ js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt
scope = OBJ_SCOPE(obj);
sprop = scope->lookup(ATOM_TO_JSID(atom));
if (sprop) {
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT(sprop->hasShortID());
if (slotp) {
JS_ASSERT(JSVAL_IS_INT(obj->fslots[JSSLOT_BLOCK_DEPTH]));

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

@ -1207,7 +1207,7 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
}
}
if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, getter, setter,
attrs, SPROP_HAS_SHORTID, (int16) slot,
attrs, JSScopeProperty::HAS_SHORTID, (int16) slot,
NULL, JSDNP_DONT_PURGE)) {
return JS_FALSE;
}
@ -1506,7 +1506,7 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
if (!js_DefineNativeProperty(cx, obj,
ATOM_TO_JSID(atom), JSVAL_VOID,
fun_getProperty, JS_PropertyStub,
lfp->attrs, SPROP_HAS_SHORTID,
lfp->attrs, JSScopeProperty::HAS_SHORTID,
lfp->tinyid, NULL)) {
return JS_FALSE;
}

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

@ -3555,7 +3555,7 @@ js_DefineBlockVariable(JSContext *cx, JSObject *obj, jsid id, intN index)
return js_DefineNativeProperty(cx, obj, id, JSVAL_VOID,
block_getProperty, block_setProperty,
JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED,
SPROP_HAS_SHORTID, index, NULL);
JSScopeProperty::HAS_SHORTID, index, NULL);
}
#if JS_HAS_XDR
@ -3658,7 +3658,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp)
do {
/* If sprop is NULL, this is the first property. */
sprop = sprop ? sprop->parent : OBJ_SCOPE(obj)->lastProperty();
} while (!(sprop->flags & SPROP_HAS_SHORTID));
} while (!sprop->hasShortID());
JS_ASSERT(sprop->getter == block_getProperty);
propid = sprop->id;
@ -4401,7 +4401,7 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
JSScope *scope;
JSScopeProperty *sprop;
JS_ASSERT(!(flags & SPROP_IS_METHOD));
JS_ASSERT(!(flags & JSScopeProperty::METHOD));
/*
* Purge the property cache of now-shadowed id in obj's scope chain. Do
@ -4582,7 +4582,7 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSObject *funobj = JSVAL_TO_OBJECT(value);
if (FUN_OBJECT(GET_FUNCTION_PRIVATE(cx, funobj)) == funobj) {
flags |= SPROP_IS_METHOD;
flags |= JSScopeProperty::METHOD;
getter = js_CastAsPropertyOp(funobj);
}
}
@ -5398,8 +5398,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
* shortid, not id, when they are called on the shadow we are
* about to create in obj's scope.
*/
if (sprop->flags & SPROP_HAS_SHORTID) {
flags = SPROP_HAS_SHORTID;
if (sprop->hasShortID()) {
flags = JSScopeProperty::HAS_SHORTID;
shortid = sprop->shortid;
getter = sprop->getter;
setter = sprop->setter;
@ -5447,7 +5447,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
JSObject *funobj = JSVAL_TO_OBJECT(*vp);
if (FUN_OBJECT(GET_FUNCTION_PRIVATE(cx, funobj)) == funobj) {
flags |= SPROP_IS_METHOD;
flags |= JSScopeProperty::METHOD;
getter = js_CastAsPropertyOp(funobj);
}
}
@ -5852,10 +5852,8 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
JSScope *scope = OBJ_SCOPE(obj);
length = 0;
for (JSScopeProperty *sprop = scope->lastProperty(); sprop; sprop = sprop->parent) {
if ((sprop->attrs & JSPROP_ENUMERATE) &&
!(sprop->flags & SPROP_IS_ALIAS)) {
if (sprop->enumerable() && !sprop->isAlias())
length++;
}
}
if (length == 0) {
/*
@ -5885,8 +5883,7 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
jsid *ids = ne->ids;
for (JSScopeProperty *sprop = scope->lastProperty(); sprop; sprop = sprop->parent) {
if ((sprop->attrs & JSPROP_ENUMERATE) &&
!(sprop->flags & SPROP_IS_ALIAS)) {
if (sprop->enumerable() && !sprop->isAlias()) {
JS_ASSERT(ids < ne->ids + length);
*ids++ = sprop->id;
}
@ -6947,7 +6944,7 @@ dumpScopeProp(JSScopeProperty *sprop)
if (attrs & JSPROP_GETTER) fprintf(stderr, "getter ");
if (attrs & JSPROP_SETTER) fprintf(stderr, "setter ");
if (attrs & JSPROP_SHARED) fprintf(stderr, "shared ");
if (sprop->flags & SPROP_IS_ALIAS) fprintf(stderr, "alias ");
if (sprop->isAlias()) fprintf(stderr, "alias ");
if (JSID_IS_ATOM(id))
dumpString(JSVAL_TO_STRING(ID_TO_VALUE(id)));
else if (JSID_IS_INT(id))

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

@ -836,8 +836,8 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
const uintN JSDNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */
const uintN JSDNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */
const uintN JSDNP_SET_METHOD = 4; /* js_{DefineNativeProperty,SetPropertyHelper}
must pass the SPROP_IS_METHOD flag on to
js_AddScopeProperty */
must pass the JSScopeProperty::METHOD
flag on to js_AddScopeProperty */
/*
* On error, return false. On success, if propp is non-null, return true with

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

@ -2639,7 +2639,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
goto enterblock_out)
for (sprop = OBJ_SCOPE(obj)->lastProperty(); sprop;
sprop = sprop->parent) {
if (!(sprop->flags & SPROP_HAS_SHORTID))
if (!sprop->hasShortID())
continue;
LOCAL_ASSERT_OUT(sprop->shortid < argc);
atomv[sprop->shortid] = JSID_TO_ATOM(sprop->id);

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

@ -1837,7 +1837,7 @@ BEGIN_CASE(JSOP_SETMETHOD)
scope->putProperty(cx, sprop->id,
sprop->getter, sprop->setter,
slot, sprop->attrs,
sprop->flags, sprop->shortid);
sprop->getFlags(), sprop->shortid);
if (!sprop2) {
js_FreeSlot(cx, obj, slot);
goto error;
@ -3474,7 +3474,7 @@ BEGIN_CASE(JSOP_INITMETHOD)
if (scope->table) {
JSScopeProperty *sprop2 =
scope->addProperty(cx, sprop->id, sprop->getter, sprop->setter, slot,
sprop->attrs, sprop->flags, sprop->shortid);
sprop->attrs, sprop->getFlags(), sprop->shortid);
if (!sprop2) {
js_FreeSlot(cx, obj, slot);
goto error;

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

@ -3996,7 +3996,7 @@ CheckDestructuring(JSContext *cx, BindData *data,
JSPROP_ENUMERATE |
JSPROP_PERMANENT |
JSPROP_SHARED,
SPROP_HAS_SHORTID, 0, NULL);
JSScopeProperty::HAS_SHORTID, 0, NULL);
if (!ok)
goto out;
}

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

@ -452,60 +452,13 @@ JSScope::changeTable(JSContext *cx, int change)
return true;
}
/*
* Take care to exclude the mark bits in case we're called from the GC.
*/
#define SPROP_FLAGS_NOT_MATCHED (SPROP_MARK | SPROP_FLAG_SHAPE_REGEN)
static JSDHashNumber
js_HashScopeProperty(JSDHashTable *table, const void *key)
{
const JSScopeProperty *sprop = (const JSScopeProperty *)key;
JSDHashNumber hash;
JSPropertyOp gsop;
/* Accumulate from least to most random so the low bits are most random. */
hash = 0;
JS_ASSERT_IF(sprop->isMethod(),
!sprop->setter || sprop->setter == js_watch_set);
gsop = sprop->getter;
if (gsop)
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsword(gsop);
gsop = sprop->setter;
if (gsop)
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsword(gsop);
hash = JS_ROTATE_LEFT32(hash, 4)
^ (sprop->flags & ~SPROP_FLAGS_NOT_MATCHED);
hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->attrs;
hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->shortid;
hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->slot;
hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->id;
return hash;
return sprop->hash();
}
#define SPROP_MATCH(sprop, child) \
SPROP_MATCH_PARAMS(sprop, (child)->id, (child)->getter, (child)->setter, \
(child)->slot, (child)->attrs, (child)->flags, \
(child)->shortid)
#define SPROP_MATCH_PARAMS(sprop, aid, agetter, asetter, aslot, aattrs, \
aflags, ashortid) \
(JS_ASSERT(!JSVAL_IS_NULL((sprop)->id)), JS_ASSERT(!JSVAL_IS_NULL(aid)), \
(sprop)->id == (aid) && \
SPROP_MATCH_PARAMS_AFTER_ID(sprop, agetter, asetter, aslot, aattrs, \
aflags, ashortid))
#define SPROP_MATCH_PARAMS_AFTER_ID(sprop, agetter, asetter, aslot, aattrs, \
aflags, ashortid) \
((sprop)->getter == (agetter) && \
(sprop)->setter == (asetter) && \
(sprop)->slot == (aslot) && \
(sprop)->attrs == (aattrs) && \
(((sprop)->flags ^ (aflags)) & ~SPROP_FLAGS_NOT_MATCHED) == 0 && \
(sprop)->shortid == (ashortid))
static JSBool
js_MatchScopeProperty(JSDHashTable *table,
const JSDHashEntryHdr *hdr,
@ -515,7 +468,7 @@ js_MatchScopeProperty(JSDHashTable *table,
const JSScopeProperty *sprop = entry->child;
const JSScopeProperty *kprop = (const JSScopeProperty *)key;
return SPROP_MATCH(sprop, kprop);
return sprop->matches(kprop);
}
static const JSDHashTableOps PropertyTreeHashOps = {
@ -659,7 +612,7 @@ InsertPropertyTreeChild(JSRuntime *rt, JSScopeProperty *parent,
* below), because the child's parent link will be null, which
* can't dangle.
*/
JS_ASSERT(sprop != child && SPROP_MATCH(sprop, child));
JS_ASSERT(sprop != child && sprop->matches(child));
JS_RUNTIME_METER(rt, duplicatePropTreeNodes);
}
} else {
@ -699,7 +652,7 @@ InsertPropertyTreeChild(JSRuntime *rt, JSScopeProperty *parent,
goto insert;
JS_ASSERT(sprop != child);
if (SPROP_MATCH(sprop, child)) {
if (sprop->matches(child)) {
/*
* Duplicate child, see comment above. In this
* case, we must let the duplicate be inserted at
@ -726,7 +679,7 @@ InsertPropertyTreeChild(JSRuntime *rt, JSScopeProperty *parent,
} else {
sprop = kids;
JS_ASSERT(sprop != child);
if (SPROP_MATCH(sprop, child)) {
if (sprop->matches(child)) {
/*
* Duplicate child, see comment above. Once again, we
* must let duplicates created by deletion pile up in a
@ -869,9 +822,9 @@ HashChunks(PropTreeKidsChunk *chunk, uintN n)
* We use rt->gcLock, not rt->rtLock, to avoid nesting the former inside the
* latter in js_GenerateShape below.
*/
static JSScopeProperty *
GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent,
const JSScopeProperty &child)
JSScopeProperty *
js_GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent,
const JSScopeProperty &child)
{
JSRuntime *rt;
JSDHashTable *table;
@ -949,13 +902,13 @@ GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent,
goto not_found;
}
if (SPROP_MATCH(sprop, &child))
if (sprop->matches(&child))
return sprop;
}
n += MAX_KIDS_PER_CHUNK;
} while ((chunk = chunk->next) != NULL);
} else {
if (SPROP_MATCH(sprop, &child))
if (sprop->matches(&child))
return sprop;
}
}
@ -1006,6 +959,7 @@ JSScope::getChildProperty(JSContext *cx, JSScopeProperty *parent,
JSScopeProperty &child)
{
JS_ASSERT(!JSVAL_IS_NULL(child.id));
JS_ASSERT(!child.inDictionary());
/*
* Aliases share another property's slot, passed in the |slot| parameter.
@ -1013,7 +967,7 @@ JSScope::getChildProperty(JSContext *cx, JSScopeProperty *parent,
* another property's slot allocate a slot here, but may lose it due to a
* JS_ClearScope call.
*/
if (!(child.flags & SPROP_IS_ALIAS)) {
if (!child.isAlias()) {
if (child.attrs & JSPROP_SHARED) {
child.slot = SPROP_INVALID_SLOT;
} else {
@ -1039,8 +993,7 @@ JSScope::getChildProperty(JSContext *cx, JSScopeProperty *parent,
return NULL;
}
child.flags &= ~SPROP_IN_DICTIONARY;
JSScopeProperty *sprop = GetPropertyTreeChild(cx, parent, child);
JSScopeProperty *sprop = js_GetPropertyTreeChild(cx, parent, child);
if (sprop) {
JS_ASSERT(sprop->parent == parent);
if (parent == lastProp) {
@ -1155,7 +1108,7 @@ JSScope::newDictionaryProperty(JSContext *cx, const JSScopeProperty &child,
dprop->setter = child.setter;
dprop->slot = child.slot;
dprop->attrs = child.attrs;
dprop->flags = child.flags | SPROP_IN_DICTIONARY;
dprop->flags = child.flags | JSScopeProperty::IN_DICTIONARY;
dprop->shortid = child.shortid;
dprop->shape = js_GenerateShape(cx, false);
@ -1284,7 +1237,7 @@ NormalizeGetterAndSetter(JSContext *cx, JSScope *scope,
{
if (setter == JS_PropertyStub)
setter = NULL;
if (flags & SPROP_IS_METHOD) {
if (flags & JSScopeProperty::METHOD) {
/* Here, getter is the method, a function object reference. */
JS_ASSERT(getter);
JS_ASSERT(!setter || setter == js_watch_set);
@ -1423,8 +1376,7 @@ JSScope::putProperty(JSContext *cx, jsid id,
SPROP_HAS_VALID_SLOT(sprop, this)) {
slot = sprop->slot;
}
if (SPROP_MATCH_PARAMS_AFTER_ID(sprop, getter, setter, slot, attrs,
flags, shortid)) {
if (sprop->matchesParamsAfterId(getter, setter, slot, attrs, flags, shortid)) {
METER(redundantPuts);
return sprop;
}
@ -1517,7 +1469,7 @@ JSScope::changeProperty(JSContext *cx, JSScopeProperty *sprop,
!(attrs & JSPROP_SHARED));
/* Don't allow method properties to be changed to accessor properties. */
JS_ASSERT(!(sprop->flags & SPROP_IS_METHOD));
JS_ASSERT(!sprop->isMethod());
if (getter == JS_PropertyStub)
getter = NULL;
@ -1720,12 +1672,13 @@ JSScope::methodShapeChange(JSContext *cx, JSScopeProperty *sprop, jsval toval)
/*
* Pass null to make a stub getter, but pass along sprop->setter to
* preserve watchpoints. Clear SPROP_IS_METHOD from flags as we are
* despecializing from a method memoized in the property tree to a
* preserve watchpoints. Clear JSScopeProperty::METHOD from flags as we
* are despecializing from a method memoized in the property tree to a
* plain old function-valued property.
*/
sprop = putProperty(cx, sprop->id, NULL, sprop->setter, sprop->slot,
sprop->attrs, sprop->flags & ~SPROP_IS_METHOD,
sprop->attrs,
sprop->getFlags() & ~JSScopeProperty::METHOD,
sprop->shortid);
if (!sprop)
return false;
@ -1828,7 +1781,7 @@ void
JSScopeProperty::trace(JSTracer *trc)
{
if (IS_GC_MARKING_TRACER(trc))
flags |= SPROP_MARK;
mark();
js_TraceId(trc, id);
#if JS_HAS_GETTER_SETTER
@ -1852,8 +1805,6 @@ JSScopeProperty::trace(JSTracer *trc)
#ifdef DEBUG
#include <stdio.h>
static void
MeterKidCount(JSBasicStats *bs, uintN nkids)
{
@ -1901,26 +1852,21 @@ js_MeterPropertyTree(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
return JS_DHASH_NEXT;
}
static void
DumpSubtree(JSContext *cx, JSScopeProperty *sprop, int level, FILE *fp)
void
JSScopeProperty::dump(JSContext *cx, FILE *fp)
{
jsval v;
JSString *str;
JSScopeProperty *kids, *kid;
PropTreeKidsChunk *chunk;
uintN i;
JS_ASSERT(!JSVAL_IS_NULL(id));
fprintf(fp, "%*sid ", level, "");
v = ID_TO_VALUE(sprop->id);
JS_ASSERT(!JSVAL_IS_NULL(v));
if (JSID_IS_INT(sprop->id)) {
fprintf(fp, "%d", JSVAL_TO_INT(v));
jsval idval = ID_TO_VALUE(id);
if (JSVAL_IS_INT(idval)) {
fprintf(fp, "[%ld]", (long) JSVAL_TO_INT(idval));
} else {
if (JSID_IS_ATOM(sprop->id)) {
str = JSVAL_TO_STRING(v);
JSString *str;
if (JSVAL_IS_STRING(idval)) {
str = JSVAL_TO_STRING(idval);
} else {
JS_ASSERT(JSID_IS_OBJECT(sprop->id));
str = js_ValueToString(cx, v);
JS_ASSERT(JSVAL_IS_OBJECT(idval));
str = js_ValueToString(cx, idval);
fputs("object ", fp);
}
if (!str)
@ -1929,27 +1875,65 @@ DumpSubtree(JSContext *cx, JSScopeProperty *sprop, int level, FILE *fp)
js_FileEscapedString(fp, str, '"');
}
fprintf(fp, " g/s %p/%p slot %u attrs %x flags %x shortid %d\n",
JS_FUNC_TO_DATA_PTR(void *, sprop->getter),
JS_FUNC_TO_DATA_PTR(void *, sprop->setter),
sprop->slot, sprop->attrs, sprop->flags, sprop->shortid);
kids = sprop->kids;
fprintf(fp, " g/s %p/%p slot %u attrs %x ",
JS_FUNC_TO_DATA_PTR(void *, getter),
JS_FUNC_TO_DATA_PTR(void *, setter),
slot, attrs);
if (attrs) {
int first = 1;
fputs("(", fp);
#define DUMP_ATTR(name, display) if (attrs & JSPROP_##name) fputs(" " #display + first, fp), first = 0
DUMP_ATTR(ENUMERATE, enumerate);
DUMP_ATTR(READONLY, readonly);
DUMP_ATTR(PERMANENT, permanent);
DUMP_ATTR(GETTER, getter);
DUMP_ATTR(SETTER, setter);
DUMP_ATTR(SHARED, shared);
#undef DUMP_ATTR
fputs(") ", fp);
}
fprintf(fp, "flags %x ", flags);
if (flags) {
int first = 1;
fputs("(", fp);
#define DUMP_FLAG(name, display) if (flags & name) fputs(" " #display + first, fp), first = 0
DUMP_FLAG(ALIAS, alias);
DUMP_FLAG(HAS_SHORTID, has_shortid);
DUMP_FLAG(METHOD, method);
DUMP_FLAG(MARK, mark);
DUMP_FLAG(SHAPE_REGEN, shape_regen);
DUMP_FLAG(IN_DICTIONARY, in_dictionary);
#undef DUMP_FLAG
fputs(") ", fp);
}
fprintf(fp, "shortid %d\n", shortid);
}
void
JSScopeProperty::dumpSubtree(JSContext *cx, int level, FILE *fp)
{
fprintf(fp, "%*sid ", level, "");
dump(cx, fp);
if (kids) {
++level;
if (KIDS_IS_CHUNKY(kids)) {
chunk = KIDS_TO_CHUNK(kids);
PropTreeKidsChunk *chunk = KIDS_TO_CHUNK(kids);
do {
for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
kid = chunk->kids[i];
for (uintN i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
JSScopeProperty *kid = chunk->kids[i];
if (!kid)
break;
JS_ASSERT(kid->parent == sprop);
DumpSubtree(cx, kid, level, fp);
JS_ASSERT(kid->parent == this);
kid->dumpSubtree(cx, level, fp);
}
} while ((chunk = chunk->next) != NULL);
} else {
kid = kids;
DumpSubtree(cx, kid, level, fp);
JSScopeProperty *kid = kids;
JS_ASSERT(kid->parent == this);
kid->dumpSubtree(cx, level, fp);
}
}
}
@ -2012,11 +1996,11 @@ js_SweepScopeProperties(JSContext *cx)
* during the mark phase, when live scopes' lastProp members are
* followed to update both scope->shape and lastProp->shape.
*/
if (sprop->flags & SPROP_MARK) {
sprop->flags &= ~SPROP_MARK;
if (sprop->marked()) {
sprop->clearMark();
if (rt->gcRegenShapes) {
if (sprop->flags & SPROP_FLAG_SHAPE_REGEN)
sprop->flags &= ~SPROP_FLAG_SHAPE_REGEN;
if (sprop->hasRegenFlag())
sprop->clearRegenFlag();
else
sprop->shape = js_RegenerateShapeForGC(cx);
}
@ -2024,7 +2008,7 @@ js_SweepScopeProperties(JSContext *cx)
continue;
}
if (!(sprop->flags & SPROP_IN_DICTIONARY)) {
if (!sprop->inDictionary()) {
/* Ok, sprop is garbage to collect: unlink it from its parent. */
freeChunk = RemovePropertyTreeChild(rt, sprop);
@ -2212,7 +2196,7 @@ js_SweepScopeProperties(JSContext *cx)
end = pte + JS_DHASH_TABLE_SIZE(&rt->propertyTreeHash);
while (pte < end) {
if (pte->child)
DumpSubtree(cx, pte->child, 0, dumpfp);
pte->child->dumpSubtree(cx, 0, dumpfp);
pte++;
}
fclose(dumpfp);

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

@ -43,6 +43,10 @@
/*
* JS symbol tables.
*/
#ifdef DEBUG
#include <stdio.h>
#endif
#include "jstypes.h"
#include "jslock.h"
#include "jsobj.h"
@ -549,13 +553,20 @@ js_CastAsObjectJSVal(JSPropertyOp op)
}
struct JSScopeProperty {
friend class JSScope;
friend void js_SweepScopeProperties(JSContext *cx);
friend JSScopeProperty * js_GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent,
const JSScopeProperty &child);
jsid id; /* int-tagged jsval/untagged JSAtom* */
JSPropertyOp getter; /* getter and setter hooks or objects */
JSPropertyOp setter; /* getter is JSObject* and setter is 0
if sprop->isMethod() */
uint32 slot; /* abstract index in object slots */
uint8 attrs; /* attributes, see jsapi.h JSPROP_* */
private:
uint8 flags; /* flags, see below for defines */
public:
int16 shortid; /* tinyid, or local arg/var index */
JSScopeProperty *parent; /* parent node, reverse for..in order */
union {
@ -568,17 +579,47 @@ struct JSScopeProperty {
};
uint32 shape; /* property cache shape identifier */
/* Bits stored in sprop->flags. */
#define SPROP_MARK 0x01
#define SPROP_IS_ALIAS 0x02
#define SPROP_HAS_SHORTID 0x04
#define SPROP_FLAG_SHAPE_REGEN 0x08
#define SPROP_IS_METHOD 0x10
#define SPROP_IN_DICTIONARY 0x20
private:
/* Implementation-private bits stored in sprop->flags. */
enum {
/* GC mark flag. */
MARK = 0x01,
/*
* Set during a shape-regenerating GC if the shape has already been
* regenerated. Unlike JSScope::SHAPE_REGEN, this does not toggle with
* each GC. js_SweepScopeProperties clears it.
*/
SHAPE_REGEN = 0x08,
/* Property stored in per-object dictionary, not shared property tree. */
IN_DICTIONARY = 0x20
};
bool marked() const { return (flags & MARK) != 0; }
void mark() { flags |= MARK; }
void clearMark() { flags &= ~MARK; }
bool hasRegenFlag() const { return (flags & SHAPE_REGEN) != 0; }
void setRegenFlag() { flags |= SHAPE_REGEN; }
void clearRegenFlag() { flags &= ~SHAPE_REGEN; }
bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; }
public:
/* Public bits stored in sprop->flags. */
enum {
ALIAS = 0x02,
HAS_SHORTID = 0x04,
METHOD = 0x10,
PUBLIC_FLAGS = ALIAS | HAS_SHORTID | METHOD
};
uintN getFlags() const { return flags & PUBLIC_FLAGS; }
bool isAlias() const { return (flags & ALIAS) != 0; }
bool hasShortID() const { return (flags & HAS_SHORTID) != 0; }
bool isMethod() const { return (flags & METHOD) != 0; }
bool isMethod() const {
return flags & SPROP_IS_METHOD;
}
JSObject *methodObject() const {
JS_ASSERT(isMethod());
return js_CastAsObject(getter);
@ -610,6 +651,11 @@ struct JSScopeProperty {
return setterVal;
}
inline JSDHashNumber hash() const;
inline bool matches(const JSScopeProperty *p) const;
inline bool matchesParamsAfterId(JSPropertyOp agetter, JSPropertyOp asetter, uint32 aslot,
uintN aattrs, uintN aflags, intN ashortid) const;
bool get(JSContext* cx, JSObject* obj, JSObject *pobj, jsval* vp);
bool set(JSContext* cx, JSObject* obj, jsval* vp);
@ -625,6 +671,11 @@ struct JSScopeProperty {
bool isAccessorDescriptor() {
return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) != 0;
}
#ifdef DEBUG
void dump(JSContext *cx, FILE *fp);
void dumpSubtree(JSContext *cx, int level, FILE *fp);
#endif
};
/* JSScopeProperty pointer tag bit indicating a collision. */
@ -693,11 +744,11 @@ inline void
JSScope::removeDictionaryProperty(JSScopeProperty *sprop)
{
JS_ASSERT(inDictionaryMode());
JS_ASSERT(sprop->flags & SPROP_IN_DICTIONARY);
JS_ASSERT(sprop->inDictionary());
JS_ASSERT(sprop->childp);
JS_ASSERT(!JSVAL_IS_NULL(sprop->id));
JS_ASSERT(lastProp->flags & SPROP_IN_DICTIONARY);
JS_ASSERT(lastProp->inDictionary());
JS_ASSERT(lastProp->childp == &lastProp);
JS_ASSERT_IF(lastProp != sprop, !JSVAL_IS_NULL(lastProp->id));
JS_ASSERT_IF(lastProp->parent, !JSVAL_IS_NULL(lastProp->parent->id));
@ -716,12 +767,12 @@ JSScope::insertDictionaryProperty(JSScopeProperty *sprop, JSScopeProperty **chil
* Don't assert inDictionaryMode() here because we may be called from
* toDictionaryMode via newDictionaryProperty.
*/
JS_ASSERT(sprop->flags & SPROP_IN_DICTIONARY);
JS_ASSERT(sprop->inDictionary());
JS_ASSERT(!sprop->childp);
JS_ASSERT(!JSVAL_IS_NULL(sprop->id));
JS_ASSERT_IF(*childp, (*childp)->flags & SPROP_IN_DICTIONARY);
JS_ASSERT_IF(lastProp, lastProp->flags & SPROP_IN_DICTIONARY);
JS_ASSERT_IF(*childp, (*childp)->inDictionary());
JS_ASSERT_IF(lastProp, lastProp->inDictionary());
JS_ASSERT_IF(lastProp, lastProp->childp == &lastProp);
JS_ASSERT_IF(lastProp, !JSVAL_IS_NULL(lastProp->id));
@ -734,12 +785,12 @@ JSScope::insertDictionaryProperty(JSScopeProperty *sprop, JSScopeProperty **chil
}
/*
* If SPROP_HAS_SHORTID is set in sprop->flags, we use sprop->shortid rather
* If SHORTID is set in sprop->flags, we use sprop->shortid rather
* than id when calling sprop's getter or setter.
*/
#define SPROP_USERID(sprop) \
(((sprop)->flags & SPROP_HAS_SHORTID) ? INT_TO_JSVAL((sprop)->shortid) \
: ID_TO_VALUE((sprop)->id))
((sprop)->hasShortID() ? INT_TO_JSVAL((sprop)->shortid) \
: ID_TO_VALUE((sprop)->id))
#define SLOT_IN_SCOPE(slot,scope) ((slot) < (scope)->freeslot)
#define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope)

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

@ -171,9 +171,9 @@ JSScope::trace(JSTracer *trc)
uint32 newShape;
if (sprop) {
if (!(sprop->flags & SPROP_FLAG_SHAPE_REGEN)) {
if (!sprop->hasRegenFlag()) {
sprop->shape = js_RegenerateShapeForGC(cx);
sprop->flags |= SPROP_FLAG_SHAPE_REGEN;
sprop->setRegenFlag();
}
newShape = sprop->shape;
}
@ -202,4 +202,45 @@ JSScope::trace(JSTracer *trc)
}
}
inline JSDHashNumber
JSScopeProperty::hash() const
{
JSDHashNumber hash = 0;
/* Accumulate from least to most random so the low bits are most random. */
JS_ASSERT_IF(isMethod(), !setter || setter == js_watch_set);
if (getter)
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsuword(getter);
if (setter)
hash = JS_ROTATE_LEFT32(hash, 4) ^ jsuword(setter);
hash = JS_ROTATE_LEFT32(hash, 4) ^ (flags & PUBLIC_FLAGS);
hash = JS_ROTATE_LEFT32(hash, 4) ^ attrs;
hash = JS_ROTATE_LEFT32(hash, 4) ^ shortid;
hash = JS_ROTATE_LEFT32(hash, 4) ^ slot;
hash = JS_ROTATE_LEFT32(hash, 4) ^ id;
return hash;
}
inline bool
JSScopeProperty::matches(const JSScopeProperty *p) const
{
JS_ASSERT(!JSVAL_IS_NULL(id));
JS_ASSERT(!JSVAL_IS_NULL(p->id));
return id == p->id &&
matchesParamsAfterId(p->getter, p->setter, p->slot, p->attrs, p->flags, p->shortid);
}
inline bool
JSScopeProperty::matchesParamsAfterId(JSPropertyOp agetter, JSPropertyOp asetter, uint32 aslot,
uintN aattrs, uintN aflags, intN ashortid) const
{
JS_ASSERT(!JSVAL_IS_NULL(id));
return getter == agetter &&
setter == asetter &&
slot == aslot &&
attrs == aattrs &&
((flags ^ aflags) & PUBLIC_FLAGS) == 0 &&
shortid == ashortid;
}
#endif /* jsscopeinlines_h___ */

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

@ -7883,7 +7883,7 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, jsval*& vp,
}
// Now assert that our use of sprop->shortid was in fact kosher.
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT(sprop->hasShortID());
if (frameIfInRange(obj)) {
// At this point we are guaranteed to be looking at an active call oject
@ -7932,7 +7932,7 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, jsval*& vp,
}
// Now assert that our use of sprop->shortid was in fact kosher.
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT(sprop->hasShortID());
LIns* base = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots));
LIns* val_ins = lir->insLoad(LIR_ldp, base, dslot_index * sizeof(jsval));
@ -7962,7 +7962,7 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, jsval*& vp,
}
// Now assert that our use of sprop->shortid was in fact kosher.
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT(sprop->hasShortID());
call_ins = lir->insCall(ci, args);
@ -11346,14 +11346,14 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty
JSStackFrame *fp = frameIfInRange(callobj);
if (fp) {
if (sprop->setter == SetCallArg) {
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT(sprop->hasShortID());
uintN slot = uint16(sprop->shortid);
jsval *vp2 = &fp->argv[slot];
set(vp2, v_ins);
return RECORD_CONTINUE;
}
if (sprop->setter == SetCallVar) {
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT(sprop->hasShortID());
uintN slot = uint16(sprop->shortid);
jsval *vp2 = &fp->slots[slot];
set(vp2, v_ins);
@ -11382,7 +11382,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty
// Now assert that the shortid get we did above was ok. Have to do it
// after the RETURN_STOP above, since in that case we may in fact not
// have a valid shortid; but we don't use it in that case anyway.
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
JS_ASSERT(sprop->hasShortID());
LIns* base = lir->insLoad(LIR_ldp, callobj_ins, offsetof(JSObject, dslots));
lir->insStorei(box_jsval(v, v_ins), base, dslot_index * sizeof(jsval));

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

@ -2013,42 +2013,10 @@ Tracing(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
static void
DumpScope(JSContext *cx, JSObject *obj, FILE *fp)
{
uintN i;
JSScopeProperty *sprop;
jsval v;
JSString *str;
i = 0;
sprop = NULL;
while (JS_PropertyIterator(obj, &sprop)) {
fprintf(fp, "%3u %p ", i, (void *)sprop);
v = ID_TO_VALUE(sprop->id);
if (JSID_IS_INT(sprop->id)) {
fprintf(fp, "[%ld]", (long)JSVAL_TO_INT(v));
} else {
if (JSID_IS_ATOM(sprop->id)) {
str = JSVAL_TO_STRING(v);
} else {
JS_ASSERT(JSID_IS_OBJECT(sprop->id));
str = js_ValueToString(cx, v);
fputs("object ", fp);
}
if (!str)
fputs("<error>", fp);
else
js_FileEscapedString(fp, str, '"');
}
#define DUMP_ATTR(name) if (sprop->attrs & JSPROP_##name) fputs(" " #name, fp)
DUMP_ATTR(ENUMERATE);
DUMP_ATTR(READONLY);
DUMP_ATTR(PERMANENT);
DUMP_ATTR(GETTER);
DUMP_ATTR(SETTER);
#undef DUMP_ATTR
fprintf(fp, " slot %lu flags %x shortid %d\n",
(unsigned long)sprop->slot, sprop->flags, sprop->shortid);
uintN i = 0;
for (JSScopeProperty *sprop = NULL; JS_PropertyIterator(obj, &sprop);) {
fprintf(fp, "%3u %p ", i++, (void *) sprop);
sprop->dump(cx, fp);
}
}