Bug 957723 - Decommit unused portions of the nursery; r=jonco

This commit is contained in:
Terrence Cole 2014-01-08 13:43:55 -08:00
Родитель af909242bc
Коммит 0988607fd4
5 изменённых файлов: 71 добавлений и 41 удалений

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

@ -181,7 +181,8 @@ struct GCSizes
{
#define FOR_EACH_SIZE(macro) \
macro(_, _, marker) \
macro(_, _, nursery) \
macro(_, _, nurseryCommitted) \
macro(_, _, nurseryDecommitted) \
macro(_, _, storeBufferVals) \
macro(_, _, storeBufferCells) \
macro(_, _, storeBufferSlots) \

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

@ -70,14 +70,14 @@ js::Nursery::init()
JSRuntime *rt = runtime();
rt->gcNurseryStart_ = uintptr_t(heap);
currentStart_ = start();
rt->gcNurseryEnd_ = chunk(LastNurseryChunk).end();
numActiveChunks_ = 1;
setCurrentChunk(0);
#ifdef JS_GC_ZEAL
JS_POISON(heap, FreshNursery, NurserySize);
#endif
for (int i = 0; i < NumNurseryChunks; ++i)
chunk(i).trailer.runtime = rt;
setCurrentChunk(0);
updateDecommittedRegion();
#ifdef PROFILE_NURSERY
char *env = getenv("JS_MINORGC_TIME");
@ -103,6 +103,7 @@ js::Nursery::enable()
return;
numActiveChunks_ = 1;
setCurrentChunk(0);
currentStart_ = position();
#ifdef JS_GC_ZEAL
if (runtime()->gcZeal_ == ZealGenerationalGCValue)
enterZealMode();
@ -112,11 +113,12 @@ js::Nursery::enable()
void
js::Nursery::disable()
{
JS_ASSERT(isEmpty());
if (!isEnabled())
return;
JS_ASSERT(isEmpty());
numActiveChunks_ = 0;
currentEnd_ = 0;
updateDecommittedRegion();
}
bool
@ -168,6 +170,7 @@ js::Nursery::allocate(size_t size)
{
JS_ASSERT(isEnabled());
JS_ASSERT(!runtime()->isHeapBusy());
JS_ASSERT(position() >= currentStart_);
if (position() + size > currentEnd()) {
if (currentChunk_ + 1 == numActiveChunks_)
@ -862,33 +865,35 @@ js::Nursery::sweep(JSRuntime *rt)
chunk(i).trailer.runtime = runtime();
if (rt->gcZeal_ == ZealGenerationalGCValue) {
/* Undo any grow or shrink the collection may have done. */
numActiveChunks_ = NumNurseryChunks;
MOZ_ASSERT(numActiveChunks_ == NumNurseryChunks);
/* Only reset the alloc point when we are close to the end. */
if (currentChunk_ + 1 == NumNurseryChunks)
setCurrentChunk(0);
/* Set current start position for isEmpty checks. */
currentStart_ = position();
return;
}
} else
#endif
{
setCurrentChunk(0);
}
setCurrentChunk(0);
/* Set current start position for isEmpty checks. */
currentStart_ = position();
}
void
js::Nursery::growAllocableSpace()
{
MOZ_ASSERT_IF(runtime()->gcZeal_ == ZealGenerationalGCValue, numActiveChunks_ == NumNurseryChunks);
numActiveChunks_ = Min(numActiveChunks_ * 2, NumNurseryChunks);
}
void
js::Nursery::shrinkAllocableSpace()
{
if (runtime()->gcZeal_ == ZealGenerationalGCValue)
return;
numActiveChunks_ = Max(numActiveChunks_ - 1, 1);
updateDecommittedRegion();
}
#endif /* JSGC_GENERATIONAL */

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

@ -15,6 +15,7 @@
#include "ds/BitArray.h"
#include "gc/Heap.h"
#include "gc/Memory.h"
#include "js/GCAPI.h"
#include "js/HashTable.h"
#include "js/HeapAPI.h"
@ -29,6 +30,7 @@ namespace js {
class ObjectElements;
class HeapSlot;
void SetGCZeal(JSRuntime *, uint8_t, uint32_t);
namespace gc {
class Cell;
@ -123,27 +125,8 @@ class Nursery
/* Forward a slots/elements pointer stored in an Ion frame. */
void forwardBufferPointer(HeapSlot **pSlotsElems);
size_t sizeOfHeap() { return start() ? NurserySize : 0; }
#ifdef JS_GC_ZEAL
/*
* In debug and zeal builds, these bytes indicate the state of an unused
* segment of nursery-allocated memory.
*/
static const uint8_t FreshNursery = 0x2a;
static const uint8_t SweptNursery = 0x2b;
static const uint8_t AllocatedThing = 0x2c;
void enterZealMode() {
if (isEnabled())
numActiveChunks_ = NumNurseryChunks;
}
void leaveZealMode() {
if (isEnabled()) {
JS_ASSERT(isEmpty());
setCurrentChunk(0);
}
}
#endif
size_t sizeOfHeapCommitted() { return numActiveChunks_ * gc::ChunkSize; }
size_t sizeOfHeapDecommitted() { return (NumNurseryChunks - numActiveChunks_) * gc::ChunkSize; }
private:
/*
@ -156,7 +139,7 @@ class Nursery
/* Pointer to the first unallocated byte in the nursery. */
uintptr_t position_;
/* Pointer to the logic start of the Nursery. */
/* Pointer to the logical start of the Nursery. */
uintptr_t currentStart_;
/* Pointer to the last byte of space in the current chunk. */
@ -211,8 +194,18 @@ class Nursery
JS_ASSERT(chunkno < numActiveChunks_);
currentChunk_ = chunkno;
position_ = chunk(chunkno).start();
currentStart_ = chunk(0).start();
currentEnd_ = chunk(chunkno).end();
chunk(chunkno).trailer.runtime = runtime();
}
void updateDecommittedRegion() {
#ifndef JS_GC_ZEAL
if (numActiveChunks_ < NumNurseryChunks) {
uintptr_t decommitStart = chunk(numActiveChunks_).start();
JS_ASSERT(decommitStart == AlignBytes(decommitStart, 1 << 20));
gc::MarkPagesUnused(runtime(), (void *)decommitStart, heapEnd() - decommitStart);
}
#endif
}
MOZ_ALWAYS_INLINE uintptr_t allocationEnd() const {
@ -284,11 +277,36 @@ class Nursery
static void MinorGCCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind);
#ifdef JS_GC_ZEAL
/*
* In debug and zeal builds, these bytes indicate the state of an unused
* segment of nursery-allocated memory.
*/
static const uint8_t FreshNursery = 0x2a;
static const uint8_t SweptNursery = 0x2b;
static const uint8_t AllocatedThing = 0x2c;
void enterZealMode() {
if (isEnabled())
numActiveChunks_ = NumNurseryChunks;
}
void leaveZealMode() {
if (isEnabled()) {
JS_ASSERT(isEmpty());
setCurrentChunk(0);
currentStart_ = start();
}
}
#else
void enterZealMode() {}
void leaveZealMode() {}
#endif
friend class gc::MinorCollectionTracer;
friend class jit::CodeGenerator;
friend class jit::MacroAssembler;
friend class jit::ICStubCompiler;
friend class jit::BaselineCompiler;
friend void SetGCZeal(JSRuntime *, uint8_t, uint32_t);
};
} /* namespace js */

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

@ -628,7 +628,8 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim
rtSizes->gc.marker += gcMarker.sizeOfExcludingThis(mallocSizeOf);
#ifdef JSGC_GENERATIONAL
rtSizes->gc.nursery += gcNursery.sizeOfHeap();
rtSizes->gc.nurseryCommitted += gcNursery.sizeOfHeapCommitted();
rtSizes->gc.nurseryDecommitted += gcNursery.sizeOfHeapDecommitted();
gcStoreBuffer.addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc);
#endif
}

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

@ -2347,9 +2347,9 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
KIND_HEAP, rtStats.runtime.gc.marker,
"The GC mark stack and gray roots.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/nursery"),
KIND_NONHEAP, rtStats.runtime.gc.nursery,
"The GC nursery.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/nursery-committed"),
KIND_NONHEAP, rtStats.runtime.gc.nurseryCommitted,
"Memory being used by the GC's nursery.");
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/vals"),
KIND_HEAP, rtStats.runtime.gc.storeBufferVals,
@ -2393,6 +2393,11 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
"GC arenas in non-empty chunks that is decommitted, i.e. it takes up "
"address space but no physical memory or swap space.");
REPORT_GC_BYTES(rtPath2 + NS_LITERAL_CSTRING("runtime/gc/nursery-decommitted"),
rtStats.runtime.gc.nurseryDecommitted,
"Memory allocated to the GC's nursery this is decommitted, i.e. it takes up "
"address space but no physical memory or swap space.");
REPORT_GC_BYTES(rtPath + NS_LITERAL_CSTRING("gc-heap/unused-chunks"),
rtStats.gcHeapUnusedChunks,
"Empty GC chunks which will soon be released unless claimed for new "