diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 71de44cee7c6..843f4adab5b5 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -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; diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp index 0d23dd626ac3..ffcd533e04f7 100644 --- a/js/src/jsbuiltins.cpp +++ b/js/src/jsbuiltins.cpp @@ -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; } diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index dd9f8ea84955..3c53d2d7021b 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -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) || diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index 1a07d5d2a641..bdc48e8f90f3 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -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])); diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 9a5881d4feaf..f3aad04a505c 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -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; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index d6255de023fa..6d3ef640114b 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -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)) diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 4e211d6f31e7..5fe95f71b977 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -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 diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 02fbbd99d0af..9fa44d4d1a3a 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -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); diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp index 649714a230fb..595e03763c08 100644 --- a/js/src/jsops.cpp +++ b/js/src/jsops.cpp @@ -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; diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 5ef6d0a59974..23342798213f 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -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; } diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index 3ecaf52fb820..5afc5f12ed8f 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -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 - 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); diff --git a/js/src/jsscope.h b/js/src/jsscope.h index 14f2bfdb2390..8af933e91bca 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -43,6 +43,10 @@ /* * JS symbol tables. */ +#ifdef DEBUG +#include +#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) diff --git a/js/src/jsscopeinlines.h b/js/src/jsscopeinlines.h index 2168e4b2a308..642c64173d01 100644 --- a/js/src/jsscopeinlines.h +++ b/js/src/jsscopeinlines.h @@ -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___ */ diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 698419dc1496..89018d1520a8 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -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)); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 304d3dab4136..9289ef69ef97 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -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("", 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); } }