Bug 1141234 - Part 6: Namespace the allocator into GCRuntime; r=sfink

This commit is contained in:
Terrence Cole 2015-03-11 11:09:31 -07:00
Родитель 01f2fccf3f
Коммит 5bcdbfd721
2 изменённых файлов: 54 добавлений и 47 удалений

Просмотреть файл

@ -35,29 +35,21 @@ MakeSlotArray(ExclusiveContext *cx, size_t count)
return UniqueSlots(slots); return UniqueSlots(slots);
} }
template <typename T, AllowGC allowGC> // Attempt to allocate a new GC thing out of the nursery. If there is not enough
T * // room in the nursery or there is an OOM, this method will return nullptr.
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.
*/
template <AllowGC allowGC> template <AllowGC allowGC>
inline JSObject * JSObject *
TryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots, const Class *clasp) GCRuntime::tryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots, const Class *clasp)
{ {
MOZ_ASSERT(!IsAtomsCompartment(cx->compartment())); MOZ_ASSERT(!IsAtomsCompartment(cx->compartment()));
JSRuntime *rt = cx->runtime();
Nursery &nursery = rt->gc.nursery;
JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp); JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp);
if (obj) if (obj)
return obj; return obj;
if (allowGC && !rt->mainThread.suppressGC) { 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()) { if (nursery.isEnabled()) {
JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp); JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp);
MOZ_ASSERT(obj); MOZ_ASSERT(obj);
@ -68,14 +60,15 @@ TryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots, const
} }
template <AllowGC allowGC> template <AllowGC allowGC>
inline JSObject * JSObject *
TryNewTenuredObject(ExclusiveContext *cx, AllocKind kind, size_t thingSize, size_t nDynamicSlots) GCRuntime::tryNewTenuredObject(ExclusiveContext *cx, AllocKind kind, size_t thingSize,
size_t nDynamicSlots)
{ {
UniqueSlots slots = MakeSlotArray(cx, nDynamicSlots); UniqueSlots slots = MakeSlotArray(cx, nDynamicSlots);
if (nDynamicSlots && !slots) if (nDynamicSlots && !slots)
return nullptr; return nullptr;
JSObject *obj = TryNewTenuredThing<JSObject, allowGC>(cx, kind, thingSize); JSObject *obj = tryNewTenuredThing<JSObject, allowGC>(cx, kind, thingSize);
if (obj) if (obj)
obj->setInitialSlotsMaybeNonNative(slots.release()); obj->setInitialSlotsMaybeNonNative(slots.release());
@ -83,45 +76,42 @@ TryNewTenuredObject(ExclusiveContext *cx, AllocKind kind, size_t thingSize, size
return obj; return obj;
} }
static inline bool bool
GCIfNeeded(JSContext *cx) GCRuntime::gcIfNeededPerAllocation(JSContext *cx)
{ {
JSRuntime *rt = cx->runtime();
#ifdef JS_GC_ZEAL #ifdef JS_GC_ZEAL
if (rt->gc.needZealousGC()) if (needZealousGC())
rt->gc.runDebugGC(); runDebugGC();
#endif #endif
// Invoking the interrupt callback can fail and we can't usefully // Invoking the interrupt callback can fail and we can't usefully
// handle that here. Just check in case we need to collect instead. // handle that here. Just check in case we need to collect instead.
if (rt->hasPendingInterrupt()) if (rt->hasPendingInterrupt())
rt->gc.gcIfRequested(cx); gcIfRequested(cx);
// If we have grown past our GC heap threshold while in the middle of // 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 // 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. // 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()) cx->zone()->usage.gcBytes() > cx->zone()->threshold.gcTriggerBytes())
{ {
PrepareZoneForGC(cx->zone()); PrepareZoneForGC(cx->zone());
AutoKeepAtoms keepAtoms(cx->perThreadData); AutoKeepAtoms keepAtoms(cx->perThreadData);
rt->gc.gc(GC_NORMAL, JS::gcreason::INCREMENTAL_TOO_SLOW); gc(GC_NORMAL, JS::gcreason::INCREMENTAL_TOO_SLOW);
} }
return true; return true;
} }
template <AllowGC allowGC> template <AllowGC allowGC>
static inline bool bool
CheckAllocatorState(JSContext *cx, AllocKind kind) GCRuntime::checkAllocatorState(JSContext *cx, AllocKind kind)
{ {
if (allowGC) { if (allowGC) {
if (!GCIfNeeded(cx)) if (!gcIfNeededPerAllocation(cx))
return false; return false;
} }
JSRuntime *rt = cx->runtime();
#if defined(JS_GC_ZEAL) || defined(DEBUG) #if defined(JS_GC_ZEAL) || defined(DEBUG)
MOZ_ASSERT_IF(rt->isAtomsCompartment(cx->compartment()), MOZ_ASSERT_IF(rt->isAtomsCompartment(cx->compartment()),
kind == FINALIZE_STRING || kind == FINALIZE_STRING ||
@ -129,7 +119,7 @@ CheckAllocatorState(JSContext *cx, AllocKind kind)
kind == FINALIZE_SYMBOL || kind == FINALIZE_SYMBOL ||
kind == FINALIZE_JITCODE); kind == FINALIZE_JITCODE);
MOZ_ASSERT(!rt->isHeapBusy()); MOZ_ASSERT(!rt->isHeapBusy());
MOZ_ASSERT(rt->gc.isAllocAllowed()); MOZ_ASSERT(isAllocAllowed());
#endif #endif
// Crash if we perform a GC action when it is not safe. // Crash if we perform a GC action when it is not safe.
@ -146,8 +136,8 @@ CheckAllocatorState(JSContext *cx, AllocKind kind)
} }
template <typename T> template <typename T>
static inline void /* static */ void
CheckIncrementalZoneState(ExclusiveContext *cx, T *t) GCRuntime::checkIncrementalZoneState(ExclusiveContext *cx, T *t)
{ {
#ifdef DEBUG #ifdef DEBUG
if (!cx->isJSContext()) 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. // Off-main-thread alloc cannot trigger GC or make runtime assertions.
if (!cx->isJSContext()) if (!cx->isJSContext())
return TryNewTenuredObject<NoGC>(cx, kind, thingSize, nDynamicSlots); return GCRuntime::tryNewTenuredObject<NoGC>(cx, kind, thingSize, nDynamicSlots);
JSContext *ncx = cx->asJSContext(); JSContext *ncx = cx->asJSContext();
if (!CheckAllocatorState<allowGC>(ncx, kind)) JSRuntime *rt = ncx->runtime();
if (!rt->gc.checkAllocatorState<allowGC>(ncx, kind))
return nullptr; return nullptr;
if (ncx->nursery().isEnabled() && heap != TenuredHeap) { if (ncx->nursery().isEnabled() && heap != TenuredHeap) {
JSObject *obj = TryNewNurseryObject<allowGC>(ncx, thingSize, nDynamicSlots, clasp); JSObject *obj = rt->gc.tryNewNurseryObject<allowGC>(ncx, thingSize, nDynamicSlots, clasp);
if (obj) if (obj)
return obj; return obj;
@ -202,7 +193,7 @@ js::Allocate(ExclusiveContext *cx, AllocKind kind, size_t nDynamicSlots, Initial
return nullptr; return nullptr;
} }
return TryNewTenuredObject<allowGC>(cx, kind, thingSize, nDynamicSlots); return GCRuntime::tryNewTenuredObject<allowGC>(cx, kind, thingSize, nDynamicSlots);
} }
template JSObject *js::Allocate<JSObject, NoGC>(ExclusiveContext *cx, gc::AllocKind kind, template JSObject *js::Allocate<JSObject, NoGC>(ExclusiveContext *cx, gc::AllocKind kind,
size_t nDynamicSlots, gc::InitialHeap heap, size_t nDynamicSlots, gc::InitialHeap heap,
@ -224,11 +215,12 @@ js::Allocate(ExclusiveContext *cx)
MOZ_ASSERT(thingSize == Arena::thingSize(kind)); MOZ_ASSERT(thingSize == Arena::thingSize(kind));
if (cx->isJSContext()) { if (cx->isJSContext()) {
if (!CheckAllocatorState<allowGC>(cx->asJSContext(), kind)) JSContext *ncx = cx->asJSContext();
if (!ncx->runtime()->gc.checkAllocatorState<allowGC>(ncx, kind))
return nullptr; return nullptr;
} }
return TryNewTenuredThing<T, allowGC>(cx, kind, thingSize); return GCRuntime::tryNewTenuredThing<T, allowGC>(cx, kind, thingSize);
} }
#define FOR_ALL_NON_OBJECT_GC_LAYOUTS(macro) \ #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 #undef DECL_ALLOCATOR_INSTANCES
template <typename T, AllowGC allowGC> template <typename T, AllowGC allowGC>
T * /* static */ T *
TryNewTenuredThing(ExclusiveContext *cx, AllocKind kind, size_t thingSize) GCRuntime::tryNewTenuredThing(ExclusiveContext *cx, AllocKind kind, size_t thingSize)
{ {
T *t = reinterpret_cast<T *>(cx->arenas()->allocateFromFreeList(kind, thingSize)); T *t = reinterpret_cast<T *>(cx->arenas()->allocateFromFreeList(kind, thingSize));
if (!t) if (!t)
t = reinterpret_cast<T *>(GCRuntime::refillFreeListFromAnyThread<allowGC>(cx, kind)); t = reinterpret_cast<T *>(refillFreeListFromAnyThread<allowGC>(cx, kind));
CheckIncrementalZoneState(cx, t); checkIncrementalZoneState(cx, t);
TraceTenuredAlloc(t, kind); TraceTenuredAlloc(t, kind);
return t; return t;
} }

Просмотреть файл

@ -821,10 +821,6 @@ class GCRuntime
bool isVerifyPreBarriersEnabled() const { return false; } bool isVerifyPreBarriersEnabled() const { return false; }
#endif #endif
template <AllowGC allowGC>
static void *refillFreeListFromAnyThread(ExclusiveContext *cx, AllocKind thingKind);
static void *refillFreeListInGC(Zone *zone, AllocKind thingKind);
// Free certain LifoAlloc blocks from the background sweep thread. // Free certain LifoAlloc blocks from the background sweep thread.
void freeUnusedLifoBlocksAfterSweeping(LifoAlloc *lifo); void freeUnusedLifoBlocksAfterSweeping(LifoAlloc *lifo);
void freeAllLifoBlocksAfterSweeping(LifoAlloc *lifo); void freeAllLifoBlocksAfterSweeping(LifoAlloc *lifo);
@ -834,6 +830,19 @@ class GCRuntime
void releaseHeldRelocatedArenas(); void releaseHeldRelocatedArenas();
// Allocator
template <AllowGC allowGC>
bool checkAllocatorState(JSContext *cx, AllocKind kind);
template <AllowGC allowGC>
JSObject *tryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots,
const Class *clasp);
template <AllowGC allowGC>
static JSObject *tryNewTenuredObject(ExclusiveContext *cx, AllocKind kind, size_t thingSize,
size_t nDynamicSlots);
template <typename T, AllowGC allowGC>
static T *tryNewTenuredThing(ExclusiveContext *cx, AllocKind kind, size_t thingSize);
static void *refillFreeListInGC(Zone *zone, AllocKind thingKind);
private: private:
enum IncrementalProgress enum IncrementalProgress
{ {
@ -850,6 +859,12 @@ class GCRuntime
ArenaHeader *allocateArena(Chunk *chunk, Zone *zone, AllocKind kind, const AutoLockGC &lock); ArenaHeader *allocateArena(Chunk *chunk, Zone *zone, AllocKind kind, const AutoLockGC &lock);
inline void arenaAllocatedDuringGC(JS::Zone *zone, ArenaHeader *arena); inline void arenaAllocatedDuringGC(JS::Zone *zone, ArenaHeader *arena);
// Allocator internals
bool gcIfNeededPerAllocation(JSContext *cx);
template <typename T>
static void checkIncrementalZoneState(ExclusiveContext *cx, T *t);
template <AllowGC allowGC>
static void *refillFreeListFromAnyThread(ExclusiveContext *cx, AllocKind thingKind);
template <AllowGC allowGC> template <AllowGC allowGC>
static void *refillFreeListFromMainThread(JSContext *cx, AllocKind thingKind); static void *refillFreeListFromMainThread(JSContext *cx, AllocKind thingKind);
static void *tryRefillFreeListFromMainThread(JSContext *cx, AllocKind thingKind); static void *tryRefillFreeListFromMainThread(JSContext *cx, AllocKind thingKind);