From 5bcdbfd72120d4831196725773f4d9fcd9fc09ff Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Wed, 11 Mar 2015 11:09:31 -0700 Subject: [PATCH] Bug 1141234 - Part 6: Namespace the allocator into GCRuntime; r=sfink --- js/src/gc/Allocator.cpp | 78 ++++++++++++++++++----------------------- js/src/gc/GCRuntime.h | 23 +++++++++--- 2 files changed, 54 insertions(+), 47 deletions(-) diff --git a/js/src/gc/Allocator.cpp b/js/src/gc/Allocator.cpp index 75dc0de4ea96..bbae0b975f29 100644 --- a/js/src/gc/Allocator.cpp +++ b/js/src/gc/Allocator.cpp @@ -35,29 +35,21 @@ MakeSlotArray(ExclusiveContext *cx, size_t count) return UniqueSlots(slots); } -template -T * -TryNewTenuredThing(ExclusiveContext *cx, AllocKind kind, size_t thingSize); - -/* - * Attempt to allocate a new GC thing out of the nursery. If there is not enough - * room in the nursery or there is an OOM, this method will return nullptr. - */ +// Attempt to allocate a new GC thing out of the nursery. If there is not enough +// room in the nursery or there is an OOM, this method will return nullptr. template -inline JSObject * -TryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots, const Class *clasp) +JSObject * +GCRuntime::tryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots, const Class *clasp) { MOZ_ASSERT(!IsAtomsCompartment(cx->compartment())); - JSRuntime *rt = cx->runtime(); - Nursery &nursery = rt->gc.nursery; JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp); if (obj) return obj; if (allowGC && !rt->mainThread.suppressGC) { - cx->minorGC(JS::gcreason::OUT_OF_NURSERY); + minorGC(cx, JS::gcreason::OUT_OF_NURSERY); - /* Exceeding gcMaxBytes while tenuring can disable the Nursery. */ + // Exceeding gcMaxBytes while tenuring can disable the Nursery. if (nursery.isEnabled()) { JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp); MOZ_ASSERT(obj); @@ -68,14 +60,15 @@ TryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots, const } template -inline JSObject * -TryNewTenuredObject(ExclusiveContext *cx, AllocKind kind, size_t thingSize, size_t nDynamicSlots) +JSObject * +GCRuntime::tryNewTenuredObject(ExclusiveContext *cx, AllocKind kind, size_t thingSize, + size_t nDynamicSlots) { UniqueSlots slots = MakeSlotArray(cx, nDynamicSlots); if (nDynamicSlots && !slots) return nullptr; - JSObject *obj = TryNewTenuredThing(cx, kind, thingSize); + JSObject *obj = tryNewTenuredThing(cx, kind, thingSize); if (obj) obj->setInitialSlotsMaybeNonNative(slots.release()); @@ -83,45 +76,42 @@ TryNewTenuredObject(ExclusiveContext *cx, AllocKind kind, size_t thingSize, size return obj; } -static inline bool -GCIfNeeded(JSContext *cx) +bool +GCRuntime::gcIfNeededPerAllocation(JSContext *cx) { - JSRuntime *rt = cx->runtime(); - #ifdef JS_GC_ZEAL - if (rt->gc.needZealousGC()) - rt->gc.runDebugGC(); + if (needZealousGC()) + runDebugGC(); #endif // Invoking the interrupt callback can fail and we can't usefully // handle that here. Just check in case we need to collect instead. if (rt->hasPendingInterrupt()) - rt->gc.gcIfRequested(cx); + gcIfRequested(cx); // If we have grown past our GC heap threshold while in the middle of // an incremental GC, we're growing faster than we're GCing, so stop // the world and do a full, non-incremental GC right now, if possible. - if (rt->gc.isIncrementalGCInProgress() && + if (isIncrementalGCInProgress() && cx->zone()->usage.gcBytes() > cx->zone()->threshold.gcTriggerBytes()) { PrepareZoneForGC(cx->zone()); AutoKeepAtoms keepAtoms(cx->perThreadData); - rt->gc.gc(GC_NORMAL, JS::gcreason::INCREMENTAL_TOO_SLOW); + gc(GC_NORMAL, JS::gcreason::INCREMENTAL_TOO_SLOW); } return true; } template -static inline bool -CheckAllocatorState(JSContext *cx, AllocKind kind) +bool +GCRuntime::checkAllocatorState(JSContext *cx, AllocKind kind) { if (allowGC) { - if (!GCIfNeeded(cx)) + if (!gcIfNeededPerAllocation(cx)) return false; } - JSRuntime *rt = cx->runtime(); #if defined(JS_GC_ZEAL) || defined(DEBUG) MOZ_ASSERT_IF(rt->isAtomsCompartment(cx->compartment()), kind == FINALIZE_STRING || @@ -129,7 +119,7 @@ CheckAllocatorState(JSContext *cx, AllocKind kind) kind == FINALIZE_SYMBOL || kind == FINALIZE_JITCODE); MOZ_ASSERT(!rt->isHeapBusy()); - MOZ_ASSERT(rt->gc.isAllocAllowed()); + MOZ_ASSERT(isAllocAllowed()); #endif // Crash if we perform a GC action when it is not safe. @@ -146,8 +136,8 @@ CheckAllocatorState(JSContext *cx, AllocKind kind) } template -static inline void -CheckIncrementalZoneState(ExclusiveContext *cx, T *t) +/* static */ void +GCRuntime::checkIncrementalZoneState(ExclusiveContext *cx, T *t) { #ifdef DEBUG if (!cx->isJSContext()) @@ -182,14 +172,15 @@ js::Allocate(ExclusiveContext *cx, AllocKind kind, size_t nDynamicSlots, Initial // Off-main-thread alloc cannot trigger GC or make runtime assertions. if (!cx->isJSContext()) - return TryNewTenuredObject(cx, kind, thingSize, nDynamicSlots); + return GCRuntime::tryNewTenuredObject(cx, kind, thingSize, nDynamicSlots); JSContext *ncx = cx->asJSContext(); - if (!CheckAllocatorState(ncx, kind)) + JSRuntime *rt = ncx->runtime(); + if (!rt->gc.checkAllocatorState(ncx, kind)) return nullptr; if (ncx->nursery().isEnabled() && heap != TenuredHeap) { - JSObject *obj = TryNewNurseryObject(ncx, thingSize, nDynamicSlots, clasp); + JSObject *obj = rt->gc.tryNewNurseryObject(ncx, thingSize, nDynamicSlots, clasp); if (obj) return obj; @@ -202,7 +193,7 @@ js::Allocate(ExclusiveContext *cx, AllocKind kind, size_t nDynamicSlots, Initial return nullptr; } - return TryNewTenuredObject(cx, kind, thingSize, nDynamicSlots); + return GCRuntime::tryNewTenuredObject(cx, kind, thingSize, nDynamicSlots); } template JSObject *js::Allocate(ExclusiveContext *cx, gc::AllocKind kind, size_t nDynamicSlots, gc::InitialHeap heap, @@ -224,11 +215,12 @@ js::Allocate(ExclusiveContext *cx) MOZ_ASSERT(thingSize == Arena::thingSize(kind)); if (cx->isJSContext()) { - if (!CheckAllocatorState(cx->asJSContext(), kind)) + JSContext *ncx = cx->asJSContext(); + if (!ncx->runtime()->gc.checkAllocatorState(ncx, kind)) return nullptr; } - return TryNewTenuredThing(cx, kind, thingSize); + return GCRuntime::tryNewTenuredThing(cx, kind, thingSize); } #define FOR_ALL_NON_OBJECT_GC_LAYOUTS(macro) \ @@ -251,14 +243,14 @@ FOR_ALL_NON_OBJECT_GC_LAYOUTS(DECL_ALLOCATOR_INSTANCES) #undef DECL_ALLOCATOR_INSTANCES template -T * -TryNewTenuredThing(ExclusiveContext *cx, AllocKind kind, size_t thingSize) +/* static */ T * +GCRuntime::tryNewTenuredThing(ExclusiveContext *cx, AllocKind kind, size_t thingSize) { T *t = reinterpret_cast(cx->arenas()->allocateFromFreeList(kind, thingSize)); if (!t) - t = reinterpret_cast(GCRuntime::refillFreeListFromAnyThread(cx, kind)); + t = reinterpret_cast(refillFreeListFromAnyThread(cx, kind)); - CheckIncrementalZoneState(cx, t); + checkIncrementalZoneState(cx, t); TraceTenuredAlloc(t, kind); return t; } diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index 942ead8b8ffb..f6551298a688 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -821,10 +821,6 @@ class GCRuntime bool isVerifyPreBarriersEnabled() const { return false; } #endif - template - static void *refillFreeListFromAnyThread(ExclusiveContext *cx, AllocKind thingKind); - static void *refillFreeListInGC(Zone *zone, AllocKind thingKind); - // Free certain LifoAlloc blocks from the background sweep thread. void freeUnusedLifoBlocksAfterSweeping(LifoAlloc *lifo); void freeAllLifoBlocksAfterSweeping(LifoAlloc *lifo); @@ -834,6 +830,19 @@ class GCRuntime void releaseHeldRelocatedArenas(); + // Allocator + template + bool checkAllocatorState(JSContext *cx, AllocKind kind); + template + JSObject *tryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots, + const Class *clasp); + template + static JSObject *tryNewTenuredObject(ExclusiveContext *cx, AllocKind kind, size_t thingSize, + size_t nDynamicSlots); + template + static T *tryNewTenuredThing(ExclusiveContext *cx, AllocKind kind, size_t thingSize); + static void *refillFreeListInGC(Zone *zone, AllocKind thingKind); + private: enum IncrementalProgress { @@ -850,6 +859,12 @@ class GCRuntime ArenaHeader *allocateArena(Chunk *chunk, Zone *zone, AllocKind kind, const AutoLockGC &lock); inline void arenaAllocatedDuringGC(JS::Zone *zone, ArenaHeader *arena); + // Allocator internals + bool gcIfNeededPerAllocation(JSContext *cx); + template + static void checkIncrementalZoneState(ExclusiveContext *cx, T *t); + template + static void *refillFreeListFromAnyThread(ExclusiveContext *cx, AllocKind thingKind); template static void *refillFreeListFromMainThread(JSContext *cx, AllocKind thingKind); static void *tryRefillFreeListFromMainThread(JSContext *cx, AllocKind thingKind);