diff --git a/mozilla/js/src/jscntxt.h b/mozilla/js/src/jscntxt.h index bea884226ea..c2bffdcc2f9 100644 --- a/mozilla/js/src/jscntxt.h +++ b/mozilla/js/src/jscntxt.h @@ -210,10 +210,6 @@ struct JSRuntime { */ JSPtrTable gcIteratorTable; -#ifdef JS_GCMETER - JSGCStats gcStats; -#endif - /* * The trace operation and its data argument to trace embedding-specific * GC roots. @@ -383,6 +379,12 @@ struct JSRuntime { /* Literal table maintained by jsatom.c functions. */ JSAtomState atomState; + /* + * Various metering fields are defined at the end of JSRuntime. In this + * way there is no need to recompile all the code that refers to other + * fields of JSRuntime after enabling the corresponding metering macro. + */ + #if defined DEBUG || defined JS_DUMP_PROPTREE_STATS /* Function invocation metering. */ jsrefcount inlineCalls; @@ -434,6 +436,10 @@ struct JSRuntime { JSBasicStats hostenvScopeDepthStats; JSBasicStats lexicalScopeDepthStats; #endif + +#ifdef JS_GCMETER + JSGCStats gcStats; +#endif }; #ifdef DEBUG diff --git a/mozilla/js/src/jsgc.c b/mozilla/js/src/jsgc.c index fabf71dc488..b0fde3936c2 100644 --- a/mozilla/js/src/jsgc.c +++ b/mozilla/js/src/jsgc.c @@ -506,11 +506,16 @@ ShrinkPtrTable(JSPtrTable *table, const JSPtrTableInfo *info, } #ifdef JS_GCMETER -# define METER(x) x +# define METER(x) ((void) (x)) +# define METER_IF(condition, x) ((void) ((condition) && (x))) #else -# define METER(x) ((void) 0) +# define METER(x) ((void) 0) +# define METER_IF(condition, x) ((void) 0) #endif +#define METER_UPDATE_MAX(maxLval, rval) \ + METER_IF((maxLval) < (rval), (maxLval) = (rval)) + /* * For chunks allocated via over-sized malloc, get a pointer to store the gap * between the malloc's result and the first arena in the chunk. @@ -738,7 +743,6 @@ InitGCArenaLists(JSRuntime *rt) arenaList->lastCount = THINGS_PER_ARENA(thingSize); arenaList->thingSize = (uint16)thingSize; arenaList->freeList = NULL; - METER(memset(&arenaList->stats, 0, sizeof arenaList->stats)); } } @@ -759,7 +763,7 @@ FinishGCArenaLists(JSRuntime *rt) arenaList->last = NULL; arenaList->lastCount = THINGS_PER_ARENA(arenaList->thingSize); arenaList->freeList = NULL; - METER(arenaList->stats.narenas = 0); + METER(rt->gcStats.arenas[i].narenas = 0); } rt->gcBytes = 0; JS_ASSERT(rt->gcChunkList == 0); @@ -899,6 +903,7 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes) */ rt->gcMaxBytes = rt->gcMaxMallocBytes = maxbytes; + METER(memset(&rt->gcStats, 0, sizeof rt->gcStats)); return JS_TRUE; } @@ -911,12 +916,15 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp) size_t totalThings, totalMaxThings, totalBytes; size_t sumArenas, sumTotalArenas; size_t sumFreeSize, sumTotalFreeSize; + JSGCArenaList *list; + JSGCArenaStats *stats; fprintf(fp, "\nGC allocation statistics:\n"); #define UL(x) ((unsigned long)(x)) #define ULSTAT(x) UL(rt->gcStats.x) totalThings = 0; + totalMaxThings = 0; totalBytes = 0; sumArenas = 0; @@ -924,8 +932,8 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp) sumFreeSize = 0; sumTotalFreeSize = 0; for (i = 0; i < GC_NUM_FREELISTS; i++) { - JSGCArenaList *list = &rt->gcArenaList[i]; - JSGCArenaStats *stats = &list->stats; + list = &rt->gcArenaList[i]; + stats = &rt->gcStats.arenas[i]; if (stats->maxarenas == 0) { fprintf(fp, "ARENA LIST %u (thing size %lu): NEVER USED\n", i, UL(GC_FREELIST_NBYTES(i))); @@ -1289,6 +1297,9 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes) JSGCThing *thing; uint8 *flagp; JSGCArenaList *arenaList; +#ifdef JS_GCMETER + JSGCArenaStats *listStats; +#endif JSGCArenaInfo *a; uintN thingsLimit; JSLocalRootStack *lrs; @@ -1299,13 +1310,13 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes) JSGCThing *tmpthing; uint8 *tmpflagp; uintN maxFreeThings; /* max to take from the global free list */ - METER(size_t nfree); #endif rt = cx->runtime; METER(rt->gcStats.alloc++); /* this is not thread-safe */ nbytes = JS_ROUNDUP(nbytes, sizeof(JSGCThing)); flindex = GC_FREELIST_INDEX(nbytes); + METER(listStats = &rt->gcStats.arenas[flindex]); #ifdef JS_THREADSAFE gcLocked = JS_FALSE; @@ -1366,8 +1377,8 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes) arenaList->freeList = thing->next; flagp = thing->flagp; JS_ASSERT(*flagp & GCF_FINAL); - METER(arenaList->stats.freelen--); - METER(arenaList->stats.recycle++); + METER(listStats->freelen--); + METER(listStats->recycle++); #ifdef JS_THREADSAFE /* @@ -1415,10 +1426,8 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes) } rt->gcBytes += GC_ARENA_SIZE; - METER(++arenaList->stats.narenas); - METER(arenaList->stats.maxarenas - = JS_MAX(arenaList->stats.maxarenas, - arenaList->stats.narenas)); + METER(listStats->narenas++); + METER_UPDATE_MAX(listStats->maxarenas, listStats->narenas); a->list = arenaList; a->prev = arenaList->last; @@ -1440,12 +1449,11 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes) */ if (rt->gcMallocBytes >= rt->gcMaxMallocBytes || flbase[flindex]) break; - METER(nfree = 0); lastptr = &flbase[flindex]; maxFreeThings = thingsLimit - arenaList->lastCount; if (maxFreeThings > MAX_THREAD_LOCAL_THINGS) maxFreeThings = MAX_THREAD_LOCAL_THINGS; - METER(arenaList->stats.freelen += maxFreeThings); + METER(listStats->freelen += maxFreeThings); while (maxFreeThings != 0) { --maxFreeThings; @@ -1503,19 +1511,13 @@ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes) if (++gchpos == NGCHIST) gchpos = 0; #endif -#ifdef JS_GCMETER - { - JSGCArenaStats *stats = &rt->gcArenaList[flindex].stats; - /* This is not thread-safe for thread-local allocations. */ - if (flags & GCF_LOCK) - rt->gcStats.lockborn++; - stats->totalnew++; - stats->nthings++; - if (stats->nthings > stats->maxthings) - stats->maxthings = stats->nthings; - } -#endif + /* This is not thread-safe for thread-local allocations. */ + METER_IF(flags & GCF_LOCK, rt->gcStats.lockborn++); + METER(listStats->totalnew++); + METER(listStats->nthings++); + METER_UPDATE_MAX(listStats->maxthings, listStats->nthings); + #ifdef JS_THREADSAFE if (gcLocked) JS_UNLOCK_GC(rt); @@ -1748,8 +1750,7 @@ DelayTracingChildren(JSRuntime *rt, uint8 *flagp) METER(rt->gcStats.untraced++); #ifdef DEBUG ++rt->gcTraceLaterCount; - METER(if (rt->gcTraceLaterCount > rt->gcStats.maxuntraced) - rt->gcStats.maxuntraced = rt->gcTraceLaterCount); + METER_UPDATE_MAX(rt->gcStats.maxuntraced, rt->gcTraceLaterCount); #endif a = FLAGP_TO_ARENA(flagp); @@ -2322,6 +2323,10 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) uint32 requestDebit; JSContext *acx, *iter; #endif +#ifdef JS_GCMETER + JSGCArenaStats *listStats; + size_t nfree; +#endif rt = cx->runtime; #ifdef JS_THREADSAFE @@ -2372,8 +2377,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) if (rt->gcThread == cx->thread) { JS_ASSERT(rt->gcLevel > 0); rt->gcLevel++; - METER(if (rt->gcLevel > rt->gcStats.maxlevel) - rt->gcStats.maxlevel = rt->gcLevel); + METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel); if (gckind != GC_LAST_DITCH) JS_UNLOCK_GC(rt); return; @@ -2423,8 +2427,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) if (rt->gcLevel > 0) { /* Bump gcLevel to restart the current GC, so it finds new garbage. */ rt->gcLevel++; - METER(if (rt->gcLevel > rt->gcStats.maxlevel) - rt->gcStats.maxlevel = rt->gcLevel); + METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel); /* Wait for the other thread to finish, then resume our request. */ while (rt->gcLevel > 0) @@ -2448,8 +2451,7 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind) /* Bump gcLevel and return rather than nest; the outer gc will restart. */ rt->gcLevel++; - METER(if (rt->gcLevel > rt->gcStats.maxlevel) - rt->gcStats.maxlevel = rt->gcLevel); + METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel); if (rt->gcLevel > 1) return; @@ -2580,23 +2582,25 @@ restart: JS_ASSERT(arenaList->lastCount > 0); arenaList->freeList = NULL; freeList = NULL; - METER(arenaList->stats.nthings = 0); - METER(arenaList->stats.freelen = 0); + + /* Here i is not the list index due to the above swap. */ + METER(listStats = &rt->gcStats.arenas[arenaList - &rt->gcArenaList[0]]); + METER(listStats->nthings = 0); + METER(listStats->freelen = 0); thingSize = arenaList->thingSize; indexLimit = THINGS_PER_ARENA(thingSize); flagp = THING_FLAGP(a, arenaList->lastCount - 1); for (;;) { - METER(size_t nfree = 0); - JS_ASSERT(a->prevUntracedPage == 0); JS_ASSERT(a->untracedThings == 0); allClear = JS_TRUE; + METER(nfree = 0); do { flags = *flagp; if (flags & (GCF_MARK | GCF_LOCK)) { *flagp &= ~GCF_MARK; allClear = JS_FALSE; - METER(++arenaList->stats.nthings); + METER(listStats->nthings++); } else { thing = FLAGP_TO_THING(flagp, thingSize); if (!(flags & GCF_FINAL)) { @@ -2661,9 +2665,9 @@ restart: } else { arenaList->freeList = freeList; ap = &a->prev; - METER(arenaList->stats.freelen += nfree); - METER(arenaList->stats.totalfreelen += nfree); - METER(++arenaList->stats.totalarenas); + METER(listStats->freelen += nfree); + METER(listStats->totalfreelen += nfree); + METER(listStats->totalarenas++); } if (!(a = *ap)) break; diff --git a/mozilla/js/src/jsgc.h b/mozilla/js/src/jsgc.h index f3fafd90966..b4507f8d1d2 100644 --- a/mozilla/js/src/jsgc.h +++ b/mozilla/js/src/jsgc.h @@ -256,12 +256,53 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind); extern void js_UpdateMallocCounter(JSContext *cx, size_t nbytes); +typedef struct JSGCArenaInfo JSGCArenaInfo; +typedef struct JSGCArenaList JSGCArenaList; +typedef struct JSGCChunkInfo JSGCChunkInfo; + +struct JSGCArenaList { + JSGCArenaInfo *last; /* last allocated GC arena */ + uint16 lastCount; /* number of allocated things in the last + arena */ + uint16 thingSize; /* size of things to allocate on this list + */ + JSGCThing *freeList; /* list of free GC things */ +}; + +struct JSWeakRoots { + /* Most recently created things by type, members of the GC's root set. */ + void *newborn[GCX_NTYPES]; + + /* Atom root for the last-looked-up atom on this context. */ + jsval lastAtom; + + /* Root for the result of the most recent js_InternalInvoke call. */ + jsval lastInternalResult; +}; + +JS_STATIC_ASSERT(JSVAL_NULL == 0); +#define JS_CLEAR_WEAK_ROOTS(wr) (memset((wr), 0, sizeof(JSWeakRoots))) + #ifdef DEBUG_notme #define JS_GCMETER 1 #endif #ifdef JS_GCMETER +typedef struct JSGCArenaStats { + uint32 narenas; /* number of arena in list */ + uint32 maxarenas; /* maximun number of allocated arenas */ + uint32 nthings; /* number of allocates JSGCThing */ + uint32 maxthings; /* maximum number number of allocates JSGCThing */ + uint32 totalnew; /* number of succeeded calls to js_NewGCThing */ + uint32 freelen; /* freeList lengths */ + uint32 recycle; /* number of things recycled through freeList */ + uint32 totalarenas; /* total number of arenas with live things that + GC scanned so far */ + uint32 totalfreelen; /* total number of things that GC put to free + list so far */ +} JSGCArenaStats; + typedef struct JSGCStats { #ifdef JS_THREADSAFE uint32 localalloc; /* number of succeeded allocations from local lists */ @@ -294,6 +335,8 @@ typedef struct JSGCStats { uint32 maxnclose; /* max number of objects with close hooks */ uint32 closelater; /* number of close hooks scheduled to run */ uint32 maxcloselater; /* max number of close hooks scheduled to run */ + + JSGCArenaStats arenas[GC_NUM_FREELISTS]; } JSGCStats; extern JS_FRIEND_API(void) @@ -301,54 +344,6 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp); #endif /* JS_GCMETER */ -typedef struct JSGCArenaInfo JSGCArenaInfo; -typedef struct JSGCArenaList JSGCArenaList; -typedef struct JSGCChunkInfo JSGCChunkInfo; - -#ifdef JS_GCMETER -typedef struct JSGCArenaStats JSGCArenaStats; - -struct JSGCArenaStats { - uint32 narenas; /* number of arena in list */ - uint32 maxarenas; /* maximun number of allocated arenas */ - uint32 nthings; /* number of allocates JSGCThing */ - uint32 maxthings; /* maximum number number of allocates JSGCThing */ - uint32 totalnew; /* number of succeeded calls to js_NewGCThing */ - uint32 freelen; /* freeList lengths */ - uint32 recycle; /* number of things recycled through freeList */ - uint32 totalarenas; /* total number of arenas with live things that - GC scanned so far */ - uint32 totalfreelen; /* total number of things that GC put to free - list so far */ -}; -#endif - -struct JSGCArenaList { - JSGCArenaInfo *last; /* last allocated GC arena */ - uint16 lastCount; /* number of allocated things in the last - arena */ - uint16 thingSize; /* size of things to allocate on this list - */ - JSGCThing *freeList; /* list of free GC things */ -#ifdef JS_GCMETER - JSGCArenaStats stats; -#endif -}; - -struct JSWeakRoots { - /* Most recently created things by type, members of the GC's root set. */ - void *newborn[GCX_NTYPES]; - - /* Atom root for the last-looked-up atom on this context. */ - jsval lastAtom; - - /* Root for the result of the most recent js_InternalInvoke call. */ - jsval lastInternalResult; -}; - -JS_STATIC_ASSERT(JSVAL_NULL == 0); -#define JS_CLEAR_WEAK_ROOTS(wr) (memset((wr), 0, sizeof(JSWeakRoots))) - JS_END_EXTERN_C #endif /* jsgc_h___ */