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);
}
template <typename T, AllowGC allowGC>
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 <AllowGC allowGC>
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 <AllowGC allowGC>
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<JSObject, allowGC>(cx, kind, thingSize);
JSObject *obj = tryNewTenuredThing<JSObject, allowGC>(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 <AllowGC allowGC>
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 <typename T>
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<NoGC>(cx, kind, thingSize, nDynamicSlots);
return GCRuntime::tryNewTenuredObject<NoGC>(cx, kind, thingSize, nDynamicSlots);
JSContext *ncx = cx->asJSContext();
if (!CheckAllocatorState<allowGC>(ncx, kind))
JSRuntime *rt = ncx->runtime();
if (!rt->gc.checkAllocatorState<allowGC>(ncx, kind))
return nullptr;
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)
return obj;
@ -202,7 +193,7 @@ js::Allocate(ExclusiveContext *cx, AllocKind kind, size_t nDynamicSlots, Initial
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,
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<allowGC>(cx->asJSContext(), kind))
JSContext *ncx = cx->asJSContext();
if (!ncx->runtime()->gc.checkAllocatorState<allowGC>(ncx, kind))
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) \
@ -251,14 +243,14 @@ FOR_ALL_NON_OBJECT_GC_LAYOUTS(DECL_ALLOCATOR_INSTANCES)
#undef DECL_ALLOCATOR_INSTANCES
template <typename T, AllowGC allowGC>
T *
TryNewTenuredThing(ExclusiveContext *cx, AllocKind kind, size_t thingSize)
/* static */ T *
GCRuntime::tryNewTenuredThing(ExclusiveContext *cx, AllocKind kind, size_t thingSize)
{
T *t = reinterpret_cast<T *>(cx->arenas()->allocateFromFreeList(kind, thingSize));
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);
return t;
}

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

@ -821,10 +821,6 @@ class GCRuntime
bool isVerifyPreBarriersEnabled() const { return false; }
#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.
void freeUnusedLifoBlocksAfterSweeping(LifoAlloc *lifo);
void freeAllLifoBlocksAfterSweeping(LifoAlloc *lifo);
@ -834,6 +830,19 @@ class GCRuntime
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:
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 <typename T>
static void checkIncrementalZoneState(ExclusiveContext *cx, T *t);
template <AllowGC allowGC>
static void *refillFreeListFromAnyThread(ExclusiveContext *cx, AllocKind thingKind);
template <AllowGC allowGC>
static void *refillFreeListFromMainThread(JSContext *cx, AllocKind thingKind);
static void *tryRefillFreeListFromMainThread(JSContext *cx, AllocKind thingKind);