📄 jsscope.c
字号:
scope->lastProp = overwriting; } else { sprop = GetPropertyTreeChild(cx, sprop, overwriting); if (sprop) { JS_ASSERT(sprop != overwriting); scope->lastProp = sprop; } overwriting = sprop; } break; } if (sprop == overwriting) break; } if (overwriting) { if (scope->table) SPROP_STORE_PRESERVING_COLLISION(spp, overwriting); scope->entryCount++; } CHECK_ANCESTOR_LINE(scope, JS_TRUE); } METER(addFailures); return NULL;}JSScopeProperty *js_ChangeScopePropertyAttrs(JSContext *cx, JSScope *scope, JSScopeProperty *sprop, uintN attrs, uintN mask, JSPropertyOp getter, JSPropertyOp setter){ JSScopeProperty child, *newsprop, **spp; CHECK_ANCESTOR_LINE(scope, JS_TRUE); /* Allow only shared (slot-less) => unshared (slot-full) transition. */ attrs |= sprop->attrs & mask; JS_ASSERT(!((attrs ^ sprop->attrs) & JSPROP_SHARED) || !(attrs & JSPROP_SHARED)); if (getter == JS_PropertyStub) getter = NULL; if (setter == JS_PropertyStub) setter = NULL; if (sprop->attrs == attrs && sprop->getter == getter && sprop->setter == setter) { return sprop; } child.id = sprop->id; child.getter = getter; child.setter = setter; child.slot = sprop->slot; child.attrs = attrs; child.flags = sprop->flags; child.shortid = sprop->shortid; if (SCOPE_LAST_PROP(scope) == sprop) { /* * Optimize the case where the last property added to scope is changed * to have a different attrs, getter, or setter. In the last property * case, we need not fork the property tree. But since we do not call * js_AddScopeProperty, we may need to allocate a new slot directly. */ if ((sprop->attrs & JSPROP_SHARED) && !(attrs & JSPROP_SHARED)) { JS_ASSERT(child.slot == SPROP_INVALID_SLOT); if (!js_AllocSlot(cx, scope->object, &child.slot)) return NULL; } newsprop = GetPropertyTreeChild(cx, sprop->parent, &child); if (newsprop) { spp = js_SearchScope(scope, sprop->id, JS_FALSE); JS_ASSERT(SPROP_FETCH(spp) == sprop); if (scope->table) SPROP_STORE_PRESERVING_COLLISION(spp, newsprop); scope->lastProp = newsprop; CHECK_ANCESTOR_LINE(scope, JS_TRUE); } } else { /* * Let js_AddScopeProperty handle this |overwriting| case, including * the conservation of sprop->slot (if it's valid). We must not call * js_RemoveScopeProperty here, it will free a valid sprop->slot and * js_AddScopeProperty won't re-allocate it. */ newsprop = js_AddScopeProperty(cx, scope, child.id, child.getter, child.setter, child.slot, child.attrs, child.flags, child.shortid); }#ifdef DEBUG_brendan if (!newsprop) METER(changeFailures);#endif return newsprop;}JSBooljs_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id){ JSScopeProperty **spp, *stored, *sprop; uint32 size; JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope)); CHECK_ANCESTOR_LINE(scope, JS_TRUE); if (SCOPE_IS_SEALED(scope)) { ReportReadOnlyScope(cx, scope); return JS_FALSE; } METER(removes); spp = js_SearchScope(scope, id, JS_FALSE); stored = *spp; sprop = SPROP_CLEAR_COLLISION(stored); if (!sprop) { METER(uselessRemoves); return JS_TRUE; } /* Convert from a list to a hash so we can handle "middle deletes". */ if (!scope->table && sprop != scope->lastProp) { if (!CreateScopeTable(scope)) { JS_ReportOutOfMemory(cx); return JS_FALSE; } spp = js_SearchScope(scope, id, JS_FALSE); stored = *spp; sprop = SPROP_CLEAR_COLLISION(stored); } /* First, if sprop is unshared and not cleared, free its slot number. */ if (SPROP_HAS_VALID_SLOT(sprop, scope)) js_FreeSlot(cx, scope->object, sprop->slot); /* Next, remove id by setting its entry to a removed or free sentinel. */ if (SPROP_HAD_COLLISION(stored)) { JS_ASSERT(scope->table); *spp = SPROP_REMOVED; scope->removedCount++; } else { METER(removeFrees); if (scope->table) *spp = NULL; } scope->entryCount--; JS_RUNTIME_UNMETER(cx->runtime, liveScopeProps); /* Update scope->lastProp directly, or set its deferred update flag. */ if (sprop == SCOPE_LAST_PROP(scope)) { do { SCOPE_REMOVE_LAST_PROP(scope); if (!SCOPE_HAD_MIDDLE_DELETE(scope)) break; sprop = SCOPE_LAST_PROP(scope); } while (sprop && !SCOPE_HAS_PROPERTY(scope, sprop)); } else if (!SCOPE_HAD_MIDDLE_DELETE(scope)) { SCOPE_SET_MIDDLE_DELETE(scope); } CHECK_ANCESTOR_LINE(scope, JS_TRUE); /* Last, consider shrinking scope's table if its load factor is <= .25. */ size = SCOPE_CAPACITY(scope); if (size > MIN_SCOPE_SIZE && scope->entryCount <= size >> 2) { METER(shrinks); (void) ChangeScope(cx, scope, -1); } return JS_TRUE;}voidjs_ClearScope(JSContext *cx, JSScope *scope){ CHECK_ANCESTOR_LINE(scope, JS_TRUE);#ifdef DEBUG JS_LOCK_RUNTIME_VOID(cx->runtime, cx->runtime->liveScopeProps -= scope->entryCount);#endif if (scope->table) free(scope->table); SCOPE_CLR_MIDDLE_DELETE(scope); InitMinimalScope(scope);}#ifdef DEBUG_brendan#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;}#endif /* DEBUG_brendan */voidjs_SweepScopeProperties(JSRuntime *rt){ JSArena **ap, *a; JSScopeProperty *limit, *sprop, *parent, *kids, *kid; uintN liveCount; PropTreeKidsChunk *chunk, *nextChunk; uintN i;#ifdef DEBUG_brendan 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., var = 0., sigma = 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.) ? sqrt(var) : 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. */ RemovePropertyTreeChild(rt, sprop); /* Take care to reparent all sprop's kids to their grandparent. */ kids = sprop->kids; if (kids) { sprop->kids = NULL; parent = sprop->parent; 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); InsertPropertyTreeChild(rt, parent, kid); } nextChunk = chunk->next; DestroyPropTreeKidsChunk(rt, chunk); } while ((chunk = nextChunk) != NULL); } else { kid = kids; InsertPropertyTreeChild(rt, parent, kid); } } /* 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 DEBUG_brendan livePropCapacity += limit - (JSScopeProperty *) a->base; totalLiveCount += liveCount;#endif ap = &a->next; } }#ifdef DEBUG_brendan fprintf(logfp, " arenautil %g%%\n", (totalLiveCount * 100.) / livePropCapacity); fflush(logfp);#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 + -