📄 jsscope.c
字号:
/* Copy only live entries, leaving removed and free ones behind. */ for (oldspp = oldtable; oldsize != 0; oldspp++) { sprop = SPROP_FETCH(oldspp); if (sprop) { spp = js_SearchScope(scope, sprop->id, JS_TRUE); JS_ASSERT(SPROP_IS_FREE(*spp)); *spp = sprop; } oldsize--; } /* Finally, free the old table storage. */ JS_free(cx, oldtable); return JS_TRUE;}/* * Take care to exclude the mark and duplicate bits, in case we're called from * the GC, or we are searching for a property that has not yet been flagged as * a duplicate when making a duplicate formal parameter. */#define SPROP_FLAGS_NOT_MATCHED (SPROP_MARK | SPROP_IS_DUPLICATE)JS_STATIC_DLL_CALLBACK(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; gsop = sprop->getter; if (gsop) hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ (jsword)gsop; gsop = sprop->setter; if (gsop) hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ (jsword)gsop; hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ (sprop->flags & ~SPROP_FLAGS_NOT_MATCHED); hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ sprop->attrs; hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ sprop->shortid; hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ sprop->slot; hash = (hash >> (JS_DHASH_BITS - 4)) ^ (hash << 4) ^ sprop->id; return 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) \ ((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))JS_STATIC_DLL_CALLBACK(JSBool)js_MatchScopeProperty(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key){ const JSPropertyTreeEntry *entry = (const JSPropertyTreeEntry *)hdr; const JSScopeProperty *sprop = entry->child; const JSScopeProperty *kprop = (const JSScopeProperty *)key; return SPROP_MATCH(sprop, kprop);}static const JSDHashTableOps PropertyTreeHashOps = { JS_DHashAllocTable, JS_DHashFreeTable, JS_DHashGetKeyStub, js_HashScopeProperty, js_MatchScopeProperty, JS_DHashMoveEntryStub, JS_DHashClearEntryStub, JS_DHashFinalizeStub, NULL};/* * A property tree node on rt->propertyFreeList overlays the following prefix * struct on JSScopeProperty. */typedef struct FreeNode { jsid id; JSScopeProperty *next; JSScopeProperty **prevp;} FreeNode;#define FREENODE(sprop) ((FreeNode *) (sprop))#define FREENODE_INSERT(list, sprop) \ JS_BEGIN_MACRO \ FREENODE(sprop)->next = (list); \ FREENODE(sprop)->prevp = &(list); \ if (list) \ FREENODE(list)->prevp = &FREENODE(sprop)->next; \ (list) = (sprop); \ JS_END_MACRO#define FREENODE_REMOVE(sprop) \ JS_BEGIN_MACRO \ *FREENODE(sprop)->prevp = FREENODE(sprop)->next; \ if (FREENODE(sprop)->next) \ FREENODE(FREENODE(sprop)->next)->prevp = FREENODE(sprop)->prevp; \ JS_END_MACRO/* NB: Called with the runtime lock held. */static JSScopeProperty *NewScopeProperty(JSRuntime *rt){ JSScopeProperty *sprop; sprop = rt->propertyFreeList; if (sprop) { FREENODE_REMOVE(sprop); } else { JS_ARENA_ALLOCATE_CAST(sprop, JSScopeProperty *, &rt->propertyArenaPool, sizeof(JSScopeProperty)); if (!sprop) return NULL; } JS_RUNTIME_METER(rt, livePropTreeNodes); JS_RUNTIME_METER(rt, totalPropTreeNodes); return sprop;}#define CHUNKY_KIDS_TAG ((jsuword)1)#define KIDS_IS_CHUNKY(kids) ((jsuword)(kids) & CHUNKY_KIDS_TAG)#define KIDS_TO_CHUNK(kids) ((PropTreeKidsChunk *) \ ((jsuword)(kids) & ~CHUNKY_KIDS_TAG))#define CHUNK_TO_KIDS(chunk) ((JSScopeProperty *) \ ((jsuword)(chunk) | CHUNKY_KIDS_TAG))#define MAX_KIDS_PER_CHUNK 10typedef struct PropTreeKidsChunk PropTreeKidsChunk;struct PropTreeKidsChunk { JSScopeProperty *kids[MAX_KIDS_PER_CHUNK]; PropTreeKidsChunk *next;};static PropTreeKidsChunk *NewPropTreeKidsChunk(JSRuntime *rt){ PropTreeKidsChunk *chunk; chunk = calloc(1, sizeof *chunk); if (!chunk) return NULL; JS_ASSERT(((jsuword)chunk & CHUNKY_KIDS_TAG) == 0); JS_RUNTIME_METER(rt, propTreeKidsChunks); return chunk;}static voidDestroyPropTreeKidsChunk(JSRuntime *rt, PropTreeKidsChunk *chunk){ JS_RUNTIME_UNMETER(rt, propTreeKidsChunks); free(chunk);}/* NB: Called with the runtime lock held. */static JSBoolInsertPropertyTreeChild(JSRuntime *rt, JSScopeProperty *parent, JSScopeProperty *child, PropTreeKidsChunk *sweptChunk){ JSPropertyTreeEntry *entry; JSScopeProperty **childp, *kids, *sprop; PropTreeKidsChunk *chunk, **chunkp; uintN i; JS_ASSERT(!parent || child->parent != parent); if (!parent) { entry = (JSPropertyTreeEntry *) JS_DHashTableOperate(&rt->propertyTreeHash, child, JS_DHASH_ADD); if (!entry) return JS_FALSE; childp = &entry->child; sprop = *childp; if (!sprop) { *childp = child; } else { /* * A "Duplicate child" case. * * We can't do away with child, as at least one live scope entry * still points at it. What's more, that scope's lastProp chains * through an ancestor line to reach child, and js_Enumerate and * others count on this linkage. We must leave child out of the * hash table, and not require it to be there when we eventually * GC it (see RemovePropertyTreeChild, below). * * It is necessary to leave the duplicate child out of the hash * table to preserve entry uniqueness. It is safe to leave the * child out of the hash table (unlike the duplicate child cases * below), because the child's parent link will be null, which * can't dangle. */ JS_ASSERT(sprop != child && SPROP_MATCH(sprop, child)); JS_RUNTIME_METER(rt, duplicatePropTreeNodes); } } else { childp = &parent->kids; kids = *childp; if (kids) { if (KIDS_IS_CHUNKY(kids)) { chunk = KIDS_TO_CHUNK(kids); do { for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { childp = &chunk->kids[i]; sprop = *childp; if (!sprop) goto insert; JS_ASSERT(sprop != child); if (SPROP_MATCH(sprop, child)) { /* * Duplicate child, see comment above. In this * case, we must let the duplicate be inserted at * this level in the tree, so we keep iterating, * looking for an empty slot in which to insert. */ JS_ASSERT(sprop != child); JS_RUNTIME_METER(rt, duplicatePropTreeNodes); } } chunkp = &chunk->next; } while ((chunk = *chunkp) != NULL); if (sweptChunk) { chunk = sweptChunk; } else { chunk = NewPropTreeKidsChunk(rt); if (!chunk) return JS_FALSE; } *chunkp = chunk; childp = &chunk->kids[0]; } else { sprop = kids; JS_ASSERT(sprop != child); if (SPROP_MATCH(sprop, child)) { /* * Duplicate child, see comment above. Once again, we * must let duplicates created by deletion pile up in a * kids-chunk-list, in order to find them when sweeping * and thereby avoid dangling parent pointers. */ JS_RUNTIME_METER(rt, duplicatePropTreeNodes); } if (sweptChunk) { chunk = sweptChunk; } else { chunk = NewPropTreeKidsChunk(rt); if (!chunk) return JS_FALSE; } parent->kids = CHUNK_TO_KIDS(chunk); chunk->kids[0] = sprop; childp = &chunk->kids[1]; } } insert: *childp = child; } child->parent = parent; return JS_TRUE;}/* NB: Called with the runtime lock held. */static PropTreeKidsChunk *RemovePropertyTreeChild(JSRuntime *rt, JSScopeProperty *child){ JSPropertyTreeEntry *entry; JSScopeProperty *parent, *kids, *kid; PropTreeKidsChunk *list, *chunk, **chunkp, *lastChunk; uintN i, j; parent = child->parent; if (!parent) { /* * Don't remove child if it is not in rt->propertyTreeHash, but only * matches a root child in the table that has compatible members. See * the "Duplicate child" comments in InsertPropertyTreeChild, above. */ entry = (JSPropertyTreeEntry *) JS_DHashTableOperate(&rt->propertyTreeHash, child, JS_DHASH_LOOKUP); if (entry->child == child) JS_DHashTableRawRemove(&rt->propertyTreeHash, &entry->hdr); } else { kids = parent->kids; if (KIDS_IS_CHUNKY(kids)) { list = chunk = KIDS_TO_CHUNK(kids); chunkp = &list; do { for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { if (chunk->kids[i] == child) { lastChunk = chunk; if (!lastChunk->next) { j = i + 1; } else { j = 0; do { chunkp = &lastChunk->next; lastChunk = *chunkp; } while (lastChunk->next); } for (; j < MAX_KIDS_PER_CHUNK; j++) { if (!lastChunk->kids[j]) break; } --j; if (chunk != lastChunk || j > i) chunk->kids[i] = lastChunk->kids[j]; lastChunk->kids[j] = NULL; if (j == 0) { *chunkp = NULL; if (!list) parent->kids = NULL; return lastChunk; } return NULL; } } chunkp = &chunk->next; } while ((chunk = *chunkp) != NULL); } else { kid = kids; if (kid == child) parent->kids = NULL; } } return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -