📄 jsscope.c
字号:
? JS_GetStringBytes(ATOM_TO_STRING(atom)) : "unknown"; } else if (JSID_IS_INT(sprop->id)) { JS_snprintf(buf2, sizeof buf2, "%d", JSID_TO_INT(sprop->id)); id = buf2; } else { id = "<object>"; }#endif if (sprop->attrs & JSPROP_GETTER) {#ifdef GC_MARK_DEBUG JS_snprintf(buf, sizeof buf, "%s %s", id, js_getter_str);#endif GC_MARK(cx, JSVAL_TO_GCTHING((jsval) sprop->getter), buf); } if (sprop->attrs & JSPROP_SETTER) {#ifdef GC_MARK_DEBUG JS_snprintf(buf, sizeof buf, "%s %s", id, js_setter_str);#endif GC_MARK(cx, JSVAL_TO_GCTHING((jsval) sprop->setter), buf); } }#endif /* JS_HAS_GETTER_SETTER */}#ifdef DUMP_SCOPE_STATS#include <stdio.h>#include <math.h>uint32 js_nkids_max;uint32 js_nkids_sum;double js_nkids_sqsum;uint32 js_nkids_hist[11];static voidMeterKidCount(uintN nkids){ if (nkids) { js_nkids_sum += nkids; js_nkids_sqsum += (double)nkids * nkids; if (nkids > js_nkids_max) js_nkids_max = nkids; } js_nkids_hist[JS_MIN(nkids, 10)]++;}static voidMeterPropertyTree(JSScopeProperty *node){ uintN i, nkids; JSScopeProperty *kids, *kid; PropTreeKidsChunk *chunk; nkids = 0; kids = node->kids; if (kids) { if (KIDS_IS_CHUNKY(kids)) { for (chunk = KIDS_TO_CHUNK(kids); chunk; chunk = chunk->next) { for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { kid = chunk->kids[i]; if (!kid) break; MeterPropertyTree(kid); nkids++; } } } else { MeterPropertyTree(kids); nkids = 1; } } MeterKidCount(nkids);}JS_STATIC_DLL_CALLBACK(JSDHashOperator)js_MeterPropertyTree(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, void *arg){ JSPropertyTreeEntry *entry = (JSPropertyTreeEntry *)hdr; MeterPropertyTree(entry->child); return JS_DHASH_NEXT;}static voidDumpSubtree(JSScopeProperty *sprop, int level, FILE *fp){ char buf[10]; JSScopeProperty *kids, *kid; PropTreeKidsChunk *chunk; uintN i; fprintf(fp, "%*sid %s g/s %p/%p slot %lu attrs %x flags %x shortid %d\n", level, "", JSID_IS_ATOM(sprop->id) ? JS_GetStringBytes(ATOM_TO_STRING(JSID_TO_ATOM(sprop->id))) : JSID_IS_OBJECT(sprop->id) ? js_ValueToPrintableString(cx, OBJECT_JSID_TO_JSVAL(sprop->id)) : (JS_snprintf(buf, sizeof buf, "%ld", JSVAL_TO_INT(sprop->id)), buf) (void *) sprop->getter, (void *) sprop->setter, (unsigned long) sprop->slot, sprop->attrs, sprop->flags, sprop->shortid); kids = sprop->kids; if (kids) { ++level; if (KIDS_IS_CHUNKY(kids)) { chunk = KIDS_TO_CHUNK(kids); do { for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { kid = chunk->kids[i]; if (!kid) break; JS_ASSERT(kid->parent == sprop); DumpSubtree(kid, level, fp); } } while ((chunk = chunk->next) != NULL); } else { kid = kids; DumpSubtree(kid, level, fp); } }}#endif /* DUMP_SCOPE_STATS */voidjs_SweepScopeProperties(JSRuntime *rt){ JSArena **ap, *a; JSScopeProperty *limit, *sprop, *parent, *kids, *kid; uintN liveCount; PropTreeKidsChunk *chunk, *nextChunk, *freeChunk; uintN i;#ifdef DUMP_SCOPE_STATS uint32 livePropCapacity = 0, totalLiveCount = 0; static FILE *logfp; if (!logfp) logfp = fopen("/tmp/proptree.stats", "a"); MeterKidCount(rt->propertyTreeHash.entryCount); JS_DHashTableEnumerate(&rt->propertyTreeHash, js_MeterPropertyTree, NULL); { double mean = 0.0, var = 0.0, sigma = 0.0; double nodesum = rt->livePropTreeNodes; double kidsum = js_nkids_sum; if (nodesum > 0 && kidsum >= 0) { mean = kidsum / nodesum; var = nodesum * js_nkids_sqsum - kidsum * kidsum; if (var < 0.0 || nodesum <= 1) var = 0.0; else var /= nodesum * (nodesum - 1); /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */ sigma = (var != 0.0) ? sqrt(var) : 0.0; } fprintf(logfp, "props %u nodes %g beta %g meankids %g sigma %g max %u", rt->liveScopeProps, nodesum, nodesum / rt->liveScopeProps, mean, sigma, js_nkids_max); } fprintf(logfp, " histogram %u %u %u %u %u %u %u %u %u %u %u", js_nkids_hist[0], js_nkids_hist[1], js_nkids_hist[2], js_nkids_hist[3], js_nkids_hist[4], js_nkids_hist[5], js_nkids_hist[6], js_nkids_hist[7], js_nkids_hist[8], js_nkids_hist[9], js_nkids_hist[10]); js_nkids_sum = js_nkids_max = 0; js_nkids_sqsum = 0; memset(js_nkids_hist, 0, sizeof js_nkids_hist);#endif ap = &rt->propertyArenaPool.first.next; while ((a = *ap) != NULL) { limit = (JSScopeProperty *) a->avail; liveCount = 0; for (sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) { /* If the id is null, sprop is already on the freelist. */ if (sprop->id == JSVAL_NULL) continue; /* If the mark bit is set, sprop is alive, so we skip it. */ if (sprop->flags & SPROP_MARK) { sprop->flags &= ~SPROP_MARK; liveCount++; continue; } /* Ok, sprop is garbage to collect: unlink it from its parent. */ freeChunk = RemovePropertyTreeChild(rt, sprop); /* * Take care to reparent all sprop's kids to their grandparent. * InsertPropertyTreeChild can potentially fail for two reasons: * * 1. If parent is null, insertion into the root property hash * table may fail. We are forced to leave the kid out of the * table (as can already happen with duplicates) but ensure * that the kid's parent pointer is set to null. * * 2. If parent is non-null, allocation of a new KidsChunk can * fail. To prevent this from happening, we allow sprops's own * chunks to be reused by the grandparent, which removes the * need for InsertPropertyTreeChild to malloc a new KidsChunk. * * If sprop does not have chunky kids, then we rely on the * RemovePropertyTreeChild call above (which removed sprop from * its parent) either leaving one free entry, or else returning * the now-unused chunk to us so we can reuse it. * * We also require the grandparent to have either no kids or else * chunky kids. A single non-chunky kid would force a new chunk to * be malloced in some cases (if sprop had a single non-chunky * kid, or a multiple of MAX_KIDS_PER_CHUNK kids). Note that * RemovePropertyTreeChild never converts a single-entry chunky * kid back to a non-chunky kid, so we are assured of correct * behaviour. */ kids = sprop->kids; if (kids) { sprop->kids = NULL; parent = sprop->parent; /* Validate that grandparent has no kids or chunky kids. */ JS_ASSERT(!parent || !parent->kids || KIDS_IS_CHUNKY(parent->kids)); if (KIDS_IS_CHUNKY(kids)) { chunk = KIDS_TO_CHUNK(kids); do { nextChunk = chunk->next; chunk->next = NULL; for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) { kid = chunk->kids[i]; if (!kid) break; JS_ASSERT(kid->parent == sprop); /* * Clear a space in the kids array for possible * re-use by InsertPropertyTreeChild. */ chunk->kids[i] = NULL; if (!InsertPropertyTreeChild(rt, parent, kid, chunk)) { /* * This can happen only if we failed to add an * entry to the root property hash table. */ JS_ASSERT(!parent); kid->parent = NULL; } } if (!chunk->kids[0]) { /* The chunk wasn't reused, so we must free it. */ DestroyPropTreeKidsChunk(rt, chunk); } } while ((chunk = nextChunk) != NULL); } else { kid = kids; if (!InsertPropertyTreeChild(rt, parent, kid, freeChunk)) { /* * This can happen only if we failed to add an entry * to the root property hash table. */ JS_ASSERT(!parent); kid->parent = NULL; } } } if (freeChunk && !freeChunk->kids[0]) { /* The chunk wasn't reused, so we must free it. */ DestroyPropTreeKidsChunk(rt, freeChunk); } /* Clear id so we know (above) that sprop is on the freelist. */ sprop->id = JSVAL_NULL; FREENODE_INSERT(rt->propertyFreeList, sprop); JS_RUNTIME_UNMETER(rt, livePropTreeNodes); } /* If a contains no live properties, return it to the malloc heap. */ if (liveCount == 0) { for (sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) FREENODE_REMOVE(sprop); JS_ARENA_DESTROY(&rt->propertyArenaPool, a, ap); } else {#ifdef DUMP_SCOPE_STATS livePropCapacity += limit - (JSScopeProperty *) a->base; totalLiveCount += liveCount;#endif ap = &a->next; } }#ifdef DUMP_SCOPE_STATS fprintf(logfp, " arenautil %g%%\n", (totalLiveCount * 100.0) / livePropCapacity); fflush(logfp);#endif#ifdef DUMP_PROPERTY_TREE { FILE *dumpfp = fopen("/tmp/proptree.dump", "w"); if (dumpfp) { JSPropertyTreeEntry *pte, *end; pte = (JSPropertyTreeEntry *) rt->propertyTreeHash.entryStore; end = pte + JS_DHASH_TABLE_SIZE(&rt->propertyTreeHash); while (pte < end) { if (pte->child) DumpSubtree(pte->child, 0, dumpfp); pte++; } fclose(dumpfp); } }#endif}JSBooljs_InitPropertyTree(JSRuntime *rt){ if (!JS_DHashTableInit(&rt->propertyTreeHash, &PropertyTreeHashOps, NULL, sizeof(JSPropertyTreeEntry), JS_DHASH_MIN_SIZE)) { rt->propertyTreeHash.ops = NULL; return JS_FALSE; } JS_InitArenaPool(&rt->propertyArenaPool, "properties", 256 * sizeof(JSScopeProperty), sizeof(void *)); return JS_TRUE;}voidjs_FinishPropertyTree(JSRuntime *rt){ if (rt->propertyTreeHash.ops) { JS_DHashTableFinish(&rt->propertyTreeHash); rt->propertyTreeHash.ops = NULL; } JS_FinishArenaPool(&rt->propertyArenaPool);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -