Bug 1034621 - Make it possible to configure nursery size r=terrence

--HG--
extra : rebase_source : 7bdf2b2b15712a31baa34501ef4adcfe0ef8bf7d
This commit is contained in:
Jon Coppeard 2014-07-11 09:59:05 +01:00
parent e339908a91
commit acf7c3159c
17 changed files with 85 additions and 50 deletions

View File

@ -88,6 +88,9 @@ AssertGCThingHasType(js::gc::Cell *cell, JSGCTraceKind kind) {}
namespace JS {
struct Zone;
/* Default size for the generational nursery in bytes. */
const uint32_t DefaultNurseryBytes = 16 * 1024 * 1024;
/*
* We cannot expose the class hierarchy: the implementation is hidden. Instead
* we provide cast functions with strong debug-mode assertions.

View File

@ -131,7 +131,7 @@ class GCRuntime
{
public:
explicit GCRuntime(JSRuntime *rt);
bool init(uint32_t maxbytes);
bool init(uint32_t maxbytes, uint32_t maxNurseryBytes);
void finish();
inline int zeal();

View File

@ -49,20 +49,27 @@ static int64_t GCReportThreshold = INT64_MAX;
#endif
bool
js::Nursery::init()
js::Nursery::init(uint32_t maxNurseryBytes)
{
/* maxNurseryBytes parameter is rounded down to a multiple of chunk size. */
numNurseryChunks_ = maxNurseryBytes >> ChunkShift;
/* If no chunks are specified then the nursery is permenantly disabled. */
if (numNurseryChunks_ == 0)
return true;
if (!hugeSlots.init())
return false;
void *heap = runtime()->gc.pageAllocator.mapAlignedPages(NurserySize, Alignment);
void *heap = runtime()->gc.pageAllocator.mapAlignedPages(nurserySize(), Alignment);
if (!heap)
return false;
heapStart_ = uintptr_t(heap);
heapEnd_ = heapStart_ + NurserySize;
heapEnd_ = heapStart_ + nurserySize();
currentStart_ = start();
numActiveChunks_ = 1;
JS_POISON(heap, JS_FRESH_NURSERY_PATTERN, NurserySize);
JS_POISON(heap, JS_FRESH_NURSERY_PATTERN, nurserySize());
setCurrentChunk(0);
updateDecommittedRegion();
@ -79,14 +86,14 @@ js::Nursery::init()
js::Nursery::~Nursery()
{
if (start())
runtime()->gc.pageAllocator.unmapPages((void *)start(), NurserySize);
runtime()->gc.pageAllocator.unmapPages((void *)start(), nurserySize());
}
void
js::Nursery::updateDecommittedRegion()
{
#ifndef JS_GC_ZEAL
if (numActiveChunks_ < NumNurseryChunks) {
if (numActiveChunks_ < numNurseryChunks_) {
// Bug 994054: madvise on MacOS is too slow to make this
// optimization worthwhile.
# ifndef XP_MACOSX
@ -140,7 +147,7 @@ js::Nursery::isEmpty() const
void
js::Nursery::enterZealMode() {
if (isEnabled())
numActiveChunks_ = NumNurseryChunks;
numActiveChunks_ = numNurseryChunks_;
}
void
@ -951,15 +958,15 @@ js::Nursery::sweep()
{
#ifdef JS_GC_ZEAL
/* Poison the nursery contents so touching a freed object will crash. */
JS_POISON((void *)start(), JS_SWEPT_NURSERY_PATTERN, NurserySize);
for (int i = 0; i < NumNurseryChunks; ++i)
JS_POISON((void *)start(), JS_SWEPT_NURSERY_PATTERN, nurserySize());
for (int i = 0; i < numNurseryChunks_; ++i)
initChunk(i);
if (runtime()->gcZeal() == ZealGenerationalGCValue) {
MOZ_ASSERT(numActiveChunks_ == NumNurseryChunks);
MOZ_ASSERT(numActiveChunks_ == numNurseryChunks_);
/* Only reset the alloc point when we are close to the end. */
if (currentChunk_ + 1 == NumNurseryChunks)
if (currentChunk_ + 1 == numNurseryChunks_)
setCurrentChunk(0);
} else
#endif
@ -981,9 +988,9 @@ js::Nursery::growAllocableSpace()
{
#ifdef JS_GC_ZEAL
MOZ_ASSERT_IF(runtime()->gcZeal() == ZealGenerationalGCValue,
numActiveChunks_ == NumNurseryChunks);
numActiveChunks_ == numNurseryChunks_);
#endif
numActiveChunks_ = Min(numActiveChunks_ * 2, NumNurseryChunks);
numActiveChunks_ = Min(numActiveChunks_ * 2, numNurseryChunks_);
}
void

View File

@ -86,25 +86,27 @@ class RelocationOverlay
class Nursery
{
public:
static const int NumNurseryChunks = 16;
static const int LastNurseryChunk = NumNurseryChunks - 1;
static const size_t Alignment = gc::ChunkSize;
static const size_t ChunkShift = gc::ChunkShift;
static const size_t NurserySize = gc::ChunkSize * NumNurseryChunks;
explicit Nursery(JSRuntime *rt)
: runtime_(rt),
position_(0),
heapStart_(0),
heapEnd_(0),
currentStart_(0),
currentEnd_(0),
heapStart_(0),
heapEnd_(0),
currentChunk_(0),
numActiveChunks_(0)
numActiveChunks_(0),
numNurseryChunks_(0)
{}
~Nursery();
bool init();
bool init(uint32_t numNurseryChunks);
bool exists() const { return numNurseryChunks_ != 0; }
size_t numChunks() const { return numNurseryChunks_; }
size_t nurserySize() const { return numNurseryChunks_ << ChunkShift; }
void enable();
void disable();
@ -170,7 +172,7 @@ class Nursery
return numActiveChunks_ * gc::ChunkSize;
}
size_t sizeOfHeapDecommitted() const {
return (NumNurseryChunks - numActiveChunks_) * gc::ChunkSize;
return (numNurseryChunks_ - numActiveChunks_) * gc::ChunkSize;
}
size_t sizeOfHugeSlots(mozilla::MallocSizeOf mallocSizeOf) const {
size_t total = 0;
@ -204,22 +206,25 @@ class Nursery
/* Pointer to the first unallocated byte in the nursery. */
uintptr_t position_;
/* Pointer to first and last address of the total nursery allocation. */
uintptr_t heapStart_;
uintptr_t heapEnd_;
/* Pointer to the logical start of the Nursery. */
uintptr_t currentStart_;
/* Pointer to the last byte of space in the current chunk. */
uintptr_t currentEnd_;
/* Pointer to first and last address of the total nursery allocation. */
uintptr_t heapStart_;
uintptr_t heapEnd_;
/* The index of the chunk that is currently being allocated from. */
int currentChunk_;
/* The index after the last chunk that we will allocate from. */
int numActiveChunks_;
/* Number of chunks allocated for the nursery. */
int numNurseryChunks_;
/*
* The set of externally malloced slots potentially kept live by objects
* stored in the nursery. Any external slots that do not belong to a
@ -243,7 +248,7 @@ class Nursery
static_assert(sizeof(NurseryChunkLayout) == gc::ChunkSize,
"Nursery chunk size must match gc::Chunk size.");
NurseryChunkLayout &chunk(int index) const {
JS_ASSERT(index < NumNurseryChunks);
JS_ASSERT(index < numNurseryChunks_);
JS_ASSERT(start());
return reinterpret_cast<NurseryChunkLayout *>(start())[index];
}
@ -256,7 +261,7 @@ class Nursery
}
MOZ_ALWAYS_INLINE void setCurrentChunk(int chunkno) {
JS_ASSERT(chunkno < NumNurseryChunks);
JS_ASSERT(chunkno < numNurseryChunks_);
JS_ASSERT(chunkno < numActiveChunks_);
currentChunk_ = chunkno;
position_ = chunk(chunkno).start();

View File

@ -5285,7 +5285,7 @@ ICSetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
masm.storeValue(tmpVal, element);
regs.add(key);
#ifdef JSGC_GENERATIONAL
{
if (cx->runtime()->gc.nursery.exists()) {
Register r = regs.takeAny();
GeneralRegisterSet saveRegs;
emitPostWriteBarrierSlot(masm, obj, tmpVal, r, saveRegs);
@ -5468,7 +5468,7 @@ ICSetElemDenseAddCompiler::generateStubCode(MacroAssembler &masm)
masm.storeValue(tmpVal, element);
regs.add(key);
#ifdef JSGC_GENERATIONAL
{
if (cx->runtime()->gc.nursery.exists()) {
Register r = regs.takeAny();
GeneralRegisterSet saveRegs;
emitPostWriteBarrierSlot(masm, obj, tmpVal, r, saveRegs);
@ -7691,7 +7691,7 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler &masm)
if (holderReg != objReg)
regs.add(holderReg);
#ifdef JSGC_GENERATIONAL
{
if (cx->runtime()->gc.nursery.exists()) {
Register scr = regs.takeAny();
GeneralRegisterSet saveRegs;
saveRegs.add(R1);
@ -7813,7 +7813,7 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
regs.add(holderReg);
#ifdef JSGC_GENERATIONAL
{
if (cx->runtime()->gc.nursery.exists()) {
Register scr = regs.takeAny();
GeneralRegisterSet saveRegs;
saveRegs.add(R1);

View File

@ -6543,6 +6543,10 @@ jit::TypeSetIncludes(types::TypeSet *types, MIRType input, types::TypeSet *input
bool
jit::NeedsPostBarrier(CompileInfo &info, MDefinition *value)
{
#ifdef JSGC_GENERATIONAL
if (!GetIonContext()->runtime->gcNursery().exists())
return false;
#endif
return info.executionMode() != ParallelExecution && value->mightBeType(MIRType_Object);
}

View File

@ -4573,7 +4573,7 @@ MacroAssemblerARMCompat::branchPtrInNurseryRange(Condition cond, Register ptr, R
ma_mov(Imm32(startChunk), secondScratchReg_);
as_rsb(secondScratchReg_, secondScratchReg_, lsr(ptr, Nursery::ChunkShift));
branch32(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
secondScratchReg_, Imm32(Nursery::NumNurseryChunks), label);
secondScratchReg_, Imm32(nursery.numChunks()), label);
}
void

View File

@ -3516,7 +3516,7 @@ MacroAssemblerMIPSCompat::branchPtrInNurseryRange(Condition cond, Register ptr,
movePtr(ImmWord(-ptrdiff_t(nursery.start())), SecondScratchReg);
addPtr(ptr, SecondScratchReg);
branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
SecondScratchReg, Imm32(Nursery::NurserySize), label);
SecondScratchReg, Imm32(nursery.nurserySize()), label);
}
void

View File

@ -419,7 +419,7 @@ MacroAssemblerX64::branchPtrInNurseryRange(Condition cond, Register ptr, Registe
movePtr(ImmWord(-ptrdiff_t(nursery.start())), ScratchReg);
addPtr(ptr, ScratchReg);
branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
ScratchReg, Imm32(Nursery::NurserySize), label);
ScratchReg, Imm32(nursery.nurserySize()), label);
}
void
@ -435,7 +435,7 @@ MacroAssemblerX64::branchValueIsNurseryObject(Condition cond, ValueOperand value
movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), ScratchReg);
addPtr(value.valueReg(), ScratchReg);
branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
ScratchReg, Imm32(Nursery::NurserySize), label);
ScratchReg, Imm32(nursery.nurserySize()), label);
}
#endif

View File

@ -430,7 +430,7 @@ MacroAssemblerX86::branchPtrInNurseryRange(Condition cond, Register ptr, Registe
movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
addPtr(ptr, temp);
branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
temp, Imm32(Nursery::NurserySize), label);
temp, Imm32(nursery.nurserySize()), label);
}
void

View File

@ -636,7 +636,7 @@ JS_FRIEND_API(bool) JS::isGCEnabled() { return true; }
#endif
JS_PUBLIC_API(JSRuntime *)
JS_NewRuntime(uint32_t maxbytes, JSRuntime *parentRuntime)
JS_NewRuntime(uint32_t maxbytes, uint32_t maxNurseryBytes, JSRuntime *parentRuntime)
{
MOZ_ASSERT(jsInitState == Running,
"must call JS_Init prior to creating any JSRuntimes");
@ -651,7 +651,7 @@ JS_NewRuntime(uint32_t maxbytes, JSRuntime *parentRuntime)
if (!rt)
return nullptr;
if (!rt->init(maxbytes)) {
if (!rt->init(maxbytes, maxNurseryBytes)) {
JS_DestroyRuntime(rt);
return nullptr;
}

View File

@ -1264,7 +1264,9 @@ extern JS_PUBLIC_API(void)
JS_ShutDown(void);
extern JS_PUBLIC_API(JSRuntime *)
JS_NewRuntime(uint32_t maxbytes, JSRuntime *parentRuntime = nullptr);
JS_NewRuntime(uint32_t maxbytes,
uint32_t maxNurseryBytes = JS::DefaultNurseryBytes,
JSRuntime *parentRuntime = nullptr);
extern JS_PUBLIC_API(void)
JS_DestroyRuntime(JSRuntime *rt);

View File

@ -1266,7 +1266,7 @@ GCRuntime::initZeal()
static const int64_t JIT_SCRIPT_RELEASE_TYPES_INTERVAL = 60 * 1000 * 1000;
bool
GCRuntime::init(uint32_t maxbytes)
GCRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
{
#ifdef JS_THREADSAFE
lock = PR_NewLock();
@ -1295,11 +1295,17 @@ GCRuntime::init(uint32_t maxbytes)
#endif
#ifdef JSGC_GENERATIONAL
if (!nursery.init())
if (!nursery.init(maxNurseryBytes))
return false;
if (!storeBuffer.enable())
return false;
if (!nursery.isEnabled()) {
JS_ASSERT(nursery.nurserySize() == 0);
++rt->gc.generationalDisabled;
} else {
JS_ASSERT(nursery.nurserySize() > 0);
if (!storeBuffer.enable())
return false;
}
#endif
#ifdef JS_GC_ZEAL

View File

@ -2893,7 +2893,7 @@ WorkerMain(void *arg)
{
WorkerInput *input = (WorkerInput *) arg;
JSRuntime *rt = JS_NewRuntime(8L * 1024L * 1024L, input->runtime);
JSRuntime *rt = JS_NewRuntime(8L * 1024L * 1024L, 2L * 1024L * 1024L, input->runtime);
if (!rt) {
js_delete(input);
return;
@ -6343,6 +6343,9 @@ main(int argc, char **argv, char **envp)
"simulator.")
|| !op.addIntOption('\0', "mips-sim-stop-at", "NUMBER", "Stop the MIPS simulator after the given "
"NUMBER of instructions.", -1)
#endif
#ifdef JSGC_GENERATIONAL
|| !op.addIntOption('\0', "nursery-size", "SIZE-MB", "Set the maximum nursery size in MB", 16)
#endif
)
{
@ -6409,8 +6412,13 @@ main(int argc, char **argv, char **envp)
if (!JS_Init())
return 1;
size_t nurseryBytes = JS::DefaultNurseryBytes;
#ifdef JSGC_GENERATIONAL
nurseryBytes = op.getIntOption("nursery-size") * 1024L * 1024L;
#endif
/* Use the same parameters as the browser in xpcjsruntime.cpp. */
rt = JS_NewRuntime(32L * 1024L * 1024L);
rt = JS_NewRuntime(32L * 1024L * 1024L, nurseryBytes);
if (!rt)
return 1;

View File

@ -257,7 +257,7 @@ JitSupportsFloatingPoint()
}
bool
JSRuntime::init(uint32_t maxbytes)
JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
{
#ifdef JS_THREADSAFE
ownerThread_ = PR_GetCurrentThread();
@ -279,7 +279,7 @@ JSRuntime::init(uint32_t maxbytes)
if (!threadPool.init())
return false;
if (!gc.init(maxbytes))
if (!gc.init(maxbytes, maxNurseryBytes))
return false;
const char *size = getenv("JSGC_MARK_STACK_LIMIT");

View File

@ -1283,7 +1283,7 @@ struct JSRuntime : public JS::shadow::Runtime,
JSRuntime(JSRuntime *parentRuntime);
~JSRuntime();
bool init(uint32_t maxbytes);
bool init(uint32_t maxbytes, uint32_t maxNurseryBytes);
JSRuntime *thisFromCtor() { return this; }

View File

@ -476,7 +476,7 @@ CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSRuntime* aParentRuntime,
{
mozilla::dom::InitScriptSettings();
mJSRuntime = JS_NewRuntime(aMaxbytes, aParentRuntime);
mJSRuntime = JS_NewRuntime(aMaxbytes, JS::DefaultNurseryBytes, aParentRuntime);
if (!mJSRuntime) {
MOZ_CRASH();
}