mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
bug 506243 - eliminate GC thread-local lists pools. r=brendan
This commit is contained in:
parent
769c24ef85
commit
83b4dee9ba
@ -927,16 +927,12 @@ JS_PUBLIC_API(void)
|
||||
JS_BeginRequest(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JSRuntime *rt;
|
||||
|
||||
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
|
||||
if (!cx->requestDepth) {
|
||||
JS_ASSERT(cx->gcLocalFreeLists == &js_GCEmptyFreeListSet);
|
||||
|
||||
/* Wait until the GC is finished. */
|
||||
rt = cx->runtime;
|
||||
JSRuntime *rt = cx->runtime;
|
||||
JS_LOCK_GC(rt);
|
||||
|
||||
/* Wait until the GC is finished. */
|
||||
if (rt->gcThread != cx->thread) {
|
||||
while (rt->gcLevel > 0)
|
||||
JS_AWAIT_GC_DONE(rt);
|
||||
@ -974,7 +970,6 @@ JS_EndRequest(JSContext *cx)
|
||||
cx->outstandingRequests--;
|
||||
|
||||
js_ShareWaitingTitles(cx);
|
||||
js_RevokeGCLocalFreeLists(cx);
|
||||
|
||||
/* Give the GC a chance to run if this was the last request running. */
|
||||
JS_ASSERT(rt->requestCount > 0);
|
||||
|
@ -263,6 +263,7 @@ thread_purger(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 /* index */,
|
||||
return JS_DHASH_REMOVE;
|
||||
}
|
||||
PurgeThreadData(cx, &thread->data);
|
||||
memset(thread->gcFreeLists, 0, sizeof(thread->gcFreeLists));
|
||||
return JS_DHASH_NEXT;
|
||||
}
|
||||
|
||||
@ -379,9 +380,6 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
|
||||
cx->stackLimit = (jsuword) -1;
|
||||
#endif
|
||||
cx->scriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA;
|
||||
#ifdef JS_THREADSAFE
|
||||
cx->gcLocalFreeLists = (JSGCFreeListSet *) &js_GCEmptyFreeListSet;
|
||||
#endif
|
||||
JS_STATIC_ASSERT(JSVERSION_DEFAULT == 0);
|
||||
JS_ASSERT(cx->version == JSVERSION_DEFAULT);
|
||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||
@ -633,7 +631,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
||||
*/
|
||||
if (cx->requestDepth == 0)
|
||||
js_WaitForGC(rt);
|
||||
js_RevokeGCLocalFreeLists(cx);
|
||||
#endif
|
||||
JS_REMOVE_LINK(&cx->link);
|
||||
last = (rt->contextList.next == &rt->contextList);
|
||||
|
@ -273,6 +273,8 @@ struct JSThread {
|
||||
/* Indicates that the thread is waiting in ClaimTitle from jslock.cpp. */
|
||||
JSTitle *titleToShare;
|
||||
|
||||
JSGCThing *gcFreeLists[GC_NUM_FREELISTS];
|
||||
|
||||
/* Factored out of JSThread for !JS_THREADSAFE embedding in JSRuntime. */
|
||||
JSThreadData data;
|
||||
};
|
||||
@ -365,7 +367,6 @@ struct JSRuntime {
|
||||
JSGCChunkInfo *gcChunkList;
|
||||
JSGCArenaList gcArenaList[GC_NUM_FREELISTS];
|
||||
JSGCDoubleArenaList gcDoubleArenaList;
|
||||
JSGCFreeListSet *gcFreeListsPool;
|
||||
JSDHashTable gcRootsHash;
|
||||
JSDHashTable *gcLocksHash;
|
||||
jsrefcount gcKeepAtoms;
|
||||
@ -1009,10 +1010,6 @@ struct JSContext {
|
||||
/* Stack of thread-stack-allocated temporary GC roots. */
|
||||
JSTempValueRooter *tempValueRooters;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JSGCFreeListSet *gcLocalFreeLists;
|
||||
#endif
|
||||
|
||||
/* List of pre-allocated doubles. */
|
||||
JSGCDoubleCell *doubleFreeList;
|
||||
|
||||
|
127
js/src/jsgc.cpp
127
js/src/jsgc.cpp
@ -1473,11 +1473,6 @@ static void
|
||||
CheckLeakedRoots(JSRuntime *rt);
|
||||
#endif
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
static void
|
||||
TrimGCFreeListsPool(JSRuntime *rt, uintN keepCount);
|
||||
#endif
|
||||
|
||||
void
|
||||
js_FinishGC(JSRuntime *rt)
|
||||
{
|
||||
@ -1489,10 +1484,6 @@ js_FinishGC(JSRuntime *rt)
|
||||
#endif
|
||||
|
||||
FreePtrTable(&rt->gcIteratorTable, &iteratorTableInfo);
|
||||
#ifdef JS_THREADSAFE
|
||||
TrimGCFreeListsPool(rt, 0);
|
||||
JS_ASSERT(!rt->gcFreeListsPool);
|
||||
#endif
|
||||
FinishGCArenaLists(rt);
|
||||
|
||||
if (rt->gcRootsHash.ops) {
|
||||
@ -1732,74 +1723,6 @@ static struct GCHist {
|
||||
unsigned gchpos = 0;
|
||||
#endif
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
const JSGCFreeListSet js_GCEmptyFreeListSet = {
|
||||
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, NULL
|
||||
};
|
||||
|
||||
static void
|
||||
TrimGCFreeListsPool(JSRuntime *rt, uintN keepCount)
|
||||
{
|
||||
JSGCFreeListSet **cursor, *freeLists, *link;
|
||||
|
||||
cursor = &rt->gcFreeListsPool;
|
||||
while (keepCount != 0) {
|
||||
--keepCount;
|
||||
freeLists = *cursor;
|
||||
if (!freeLists)
|
||||
return;
|
||||
memset(freeLists->array, 0, sizeof freeLists->array);
|
||||
cursor = &freeLists->link;
|
||||
}
|
||||
freeLists = *cursor;
|
||||
if (freeLists) {
|
||||
*cursor = NULL;
|
||||
do {
|
||||
link = freeLists->link;
|
||||
free(freeLists);
|
||||
} while ((freeLists = link) != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
js_RevokeGCLocalFreeLists(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(!cx->gcLocalFreeLists->link);
|
||||
if (cx->gcLocalFreeLists != &js_GCEmptyFreeListSet) {
|
||||
cx->gcLocalFreeLists->link = cx->runtime->gcFreeListsPool;
|
||||
cx->runtime->gcFreeListsPool = cx->gcLocalFreeLists;
|
||||
cx->gcLocalFreeLists = (JSGCFreeListSet *) &js_GCEmptyFreeListSet;
|
||||
}
|
||||
}
|
||||
|
||||
static JSGCFreeListSet *
|
||||
EnsureLocalFreeList(JSContext *cx)
|
||||
{
|
||||
JSGCFreeListSet *freeLists;
|
||||
|
||||
freeLists = cx->gcLocalFreeLists;
|
||||
if (freeLists != &js_GCEmptyFreeListSet) {
|
||||
JS_ASSERT(freeLists);
|
||||
return freeLists;
|
||||
}
|
||||
|
||||
freeLists = cx->runtime->gcFreeListsPool;
|
||||
if (freeLists) {
|
||||
cx->runtime->gcFreeListsPool = freeLists->link;
|
||||
freeLists->link = NULL;
|
||||
} else {
|
||||
/* JS_malloc is not used as the caller reports out-of-memory itself. */
|
||||
freeLists = (JSGCFreeListSet *) calloc(1, sizeof *freeLists);
|
||||
if (!freeLists)
|
||||
return NULL;
|
||||
}
|
||||
cx->gcLocalFreeLists = freeLists;
|
||||
return freeLists;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
JSRuntime::setGCTriggerFactor(uint32 factor)
|
||||
{
|
||||
@ -1853,7 +1776,6 @@ NewGCThing(JSContext *cx, uintN flags)
|
||||
#ifdef JS_THREADSAFE
|
||||
JSBool gcLocked;
|
||||
uintN localMallocBytes;
|
||||
JSGCFreeListSet *freeLists;
|
||||
JSGCThing **lastptr;
|
||||
JSGCThing *tmpthing;
|
||||
uint8 *tmpflagp;
|
||||
@ -1873,12 +1795,13 @@ NewGCThing(JSContext *cx, uintN flags)
|
||||
#ifdef JS_THREADSAFE
|
||||
gcLocked = JS_FALSE;
|
||||
JS_ASSERT(cx->thread);
|
||||
freeLists = cx->gcLocalFreeLists;
|
||||
thing = freeLists->array[flindex];
|
||||
|
||||
JSGCThing *&freeList = cx->thread->gcFreeLists[flindex];
|
||||
thing = freeList;
|
||||
localMallocBytes = JS_THREAD_DATA(cx)->gcMallocBytes;
|
||||
if (thing && rt->gcMaxMallocBytes - rt->gcMallocBytes > localMallocBytes) {
|
||||
flagp = thing->flagp;
|
||||
freeLists->array[flindex] = thing->next;
|
||||
freeList = thing->next;
|
||||
METER(astats->localalloc++);
|
||||
goto success;
|
||||
}
|
||||
@ -1937,19 +1860,13 @@ NewGCThing(JSContext *cx, uintN flags)
|
||||
#ifdef JS_THREADSAFE
|
||||
/*
|
||||
* Refill the local free list by taking several things from the
|
||||
* global free list unless we are still at rt->gcMaxMallocBytes
|
||||
* barrier or the free list is already populated. The former
|
||||
* happens when GC is canceled due to gcCallback(cx, JSGC_BEGIN)
|
||||
* returning false. The latter is caused via allocating new
|
||||
* things in gcCallback(cx, JSGC_END).
|
||||
* global free list unless the free list is already populated or
|
||||
* we are still at rt->gcMaxMallocBytes barrier. The former is
|
||||
* caused via allocating new things in gcCallback(cx, JSGC_END).
|
||||
* The latter happens when GC is canceled due to
|
||||
* gcCallback(cx, JSGC_BEGIN) returning false.
|
||||
*/
|
||||
if (rt->gcMallocBytes >= rt->gcMaxMallocBytes)
|
||||
break;
|
||||
|
||||
freeLists = EnsureLocalFreeList(cx);
|
||||
if (!freeLists)
|
||||
goto fail;
|
||||
if (freeLists->array[flindex])
|
||||
if (freeList || rt->gcMallocBytes >= rt->gcMaxMallocBytes)
|
||||
break;
|
||||
|
||||
tmpthing = arenaList->freeList;
|
||||
@ -1961,7 +1878,7 @@ NewGCThing(JSContext *cx, uintN flags)
|
||||
tmpthing = tmpthing->next;
|
||||
} while (--maxFreeThings != 0);
|
||||
|
||||
freeLists->array[flindex] = arenaList->freeList;
|
||||
freeList = arenaList->freeList;
|
||||
arenaList->freeList = tmpthing->next;
|
||||
tmpthing->next = NULL;
|
||||
}
|
||||
@ -2019,15 +1936,9 @@ testReservedObjects:
|
||||
* arena. Prefer to order free things by ascending address in the
|
||||
* (unscientific) hope of better cache locality.
|
||||
*/
|
||||
if (rt->gcMallocBytes >= rt->gcMaxMallocBytes)
|
||||
if (freeList || rt->gcMallocBytes >= rt->gcMaxMallocBytes)
|
||||
break;
|
||||
|
||||
freeLists = EnsureLocalFreeList(cx);
|
||||
if (!freeLists)
|
||||
goto fail;
|
||||
if (freeLists->array[flindex])
|
||||
break;
|
||||
lastptr = &freeLists->array[flindex];
|
||||
lastptr = &freeList;
|
||||
maxFreeThings = thingsLimit - arenaList->lastCount;
|
||||
if (maxFreeThings > MAX_THREAD_LOCAL_THINGS)
|
||||
maxFreeThings = MAX_THREAD_LOCAL_THINGS;
|
||||
@ -3046,10 +2957,6 @@ js_TraceContext(JSTracer *trc, JSContext *acx)
|
||||
} \
|
||||
JS_END_MACRO
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
js_RevokeGCLocalFreeLists(acx);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Release the stackPool's arenas if the stackPool has existed for
|
||||
* longer than the limit specified by gcEmptyArenaPoolLifespan.
|
||||
@ -3779,14 +3686,6 @@ js_GC(JSContext *cx, JSGCInvocationKind gckind)
|
||||
nlivearenas, nkilledarenas, nthings));
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
/*
|
||||
* Release all but two free list sets to avoid allocating a new set in
|
||||
* js_NewGCThing.
|
||||
*/
|
||||
TrimGCFreeListsPool(rt, 2);
|
||||
#endif
|
||||
|
||||
ap = &rt->gcDoubleArenaList.first;
|
||||
METER((nlivearenas = 0, nkilledarenas = 0, nthings = 0));
|
||||
while ((a = *ap) != NULL) {
|
||||
|
@ -309,18 +309,6 @@ typedef struct JSGCDoubleArenaList {
|
||||
things */
|
||||
} JSGCDoubleArenaList;
|
||||
|
||||
typedef struct JSGCFreeListSet JSGCFreeListSet;
|
||||
|
||||
struct JSGCFreeListSet {
|
||||
JSGCThing *array[GC_NUM_FREELISTS];
|
||||
JSGCFreeListSet *link;
|
||||
};
|
||||
|
||||
extern const JSGCFreeListSet js_GCEmptyFreeListSet;
|
||||
|
||||
extern void
|
||||
js_RevokeGCLocalFreeLists(JSContext *cx);
|
||||
|
||||
extern void
|
||||
js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user