зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1141234 - Part 6: Namespace the allocator into GCRuntime; r=sfink
This commit is contained in:
Родитель
01f2fccf3f
Коммит
5bcdbfd721
|
@ -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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче