Allow resource constraints to specify the max committed new space size

when using snapshots.

The alignment of new space has to match the alignment in the snapshot,
but the max committed amount of memory does not.

For now, we assume that the default semispace size is always used in a
snapshot.
Review URL: http://codereview.chromium.org/300036

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3106 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
ager@chromium.org 2009-10-21 15:03:34 +00:00
parent 765e134b92
commit 9ee631338e
9 changed files with 84 additions and 62 deletions

View File

@ -342,10 +342,10 @@ ResourceConstraints::ResourceConstraints()
bool SetResourceConstraints(ResourceConstraints* constraints) {
int semispace_size = constraints->max_young_space_size();
int young_space_size = constraints->max_young_space_size();
int old_gen_size = constraints->max_old_space_size();
if (semispace_size != 0 || old_gen_size != 0) {
bool result = i::Heap::ConfigureHeap(semispace_size, old_gen_size);
if (young_space_size != 0 || old_gen_size != 0) {
bool result = i::Heap::ConfigureHeap(young_space_size / 2, old_gen_size);
if (!result) return false;
}
if (constraints->stack_limit() != NULL) {

View File

@ -163,8 +163,8 @@ DEFINE_int(max_stack_trace_source_length, 300,
"maximum length of function source code printed in a stack trace.")
// heap.cc
DEFINE_int(new_space_size, 0, "size of (each semispace in) the new generation")
DEFINE_int(old_space_size, 0, "size of the old generation")
DEFINE_int(max_new_space_size, 0, "max size of the new generation")
DEFINE_int(max_old_space_size, 0, "max size of the old generation")
DEFINE_bool(gc_global, false, "always perform global GCs")
DEFINE_int(gc_interval, -1, "garbage collect after <n> allocations")
DEFINE_bool(trace_gc, false,

View File

@ -39,6 +39,7 @@
#include "natives.h"
#include "scanner.h"
#include "scopeinfo.h"
#include "snapshot.h"
#include "v8threads.h"
#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
#include "regexp-macro-assembler.h"
@ -74,28 +75,35 @@ int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0;
// semispace_size_ should be a power of 2 and old_generation_size_ should be
// a multiple of Page::kPageSize.
#if defined(ANDROID)
int Heap::semispace_size_ = 512*KB;
int Heap::old_generation_size_ = 128*MB;
int Heap::max_semispace_size_ = 512*KB;
int Heap::max_old_generation_size_ = 128*MB;
int Heap::initial_semispace_size_ = 128*KB;
size_t Heap::code_range_size_ = 0;
#elif defined(V8_TARGET_ARCH_X64)
int Heap::semispace_size_ = 16*MB;
int Heap::old_generation_size_ = 1*GB;
int Heap::max_semispace_size_ = 16*MB;
int Heap::max_old_generation_size_ = 1*GB;
int Heap::initial_semispace_size_ = 1*MB;
size_t Heap::code_range_size_ = 512*MB;
#else
int Heap::semispace_size_ = 8*MB;
int Heap::old_generation_size_ = 512*MB;
int Heap::max_semispace_size_ = 8*MB;
int Heap::max_old_generation_size_ = 512*MB;
int Heap::initial_semispace_size_ = 512*KB;
size_t Heap::code_range_size_ = 0;
#endif
// The snapshot semispace size will be the default semispace size if
// snapshotting is used and will be the requested semispace size as
// set up by ConfigureHeap otherwise.
int Heap::reserved_semispace_size_ = Heap::max_semispace_size_;
GCCallback Heap::global_gc_prologue_callback_ = NULL;
GCCallback Heap::global_gc_epilogue_callback_ = NULL;
// Variables set based on semispace_size_ and old_generation_size_ in
// ConfigureHeap.
int Heap::young_generation_size_ = 0; // Will be 2 * semispace_size_.
// Will be 4 * reserved_semispace_size_ to ensure that young
// generation can be aligned to its size.
int Heap::survived_since_last_expansion_ = 0;
int Heap::external_allocation_limit_ = 0;
@ -3297,21 +3305,37 @@ static bool heap_configured = false;
// TODO(1236194): Since the heap size is configurable on the command line
// and through the API, we should gracefully handle the case that the heap
// size is not big enough to fit all the initial objects.
bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) {
bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
if (HasBeenSetup()) return false;
if (semispace_size > 0) semispace_size_ = semispace_size;
if (old_gen_size > 0) old_generation_size_ = old_gen_size;
if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size;
if (Snapshot::IsEnabled()) {
// If we are using a snapshot we always reserve the default amount
// of memory for each semispace because code in the snapshot has
// write-barrier code that relies on the size and alignment of new
// space. We therefore cannot use a larger max semispace size
// than the default reserved semispace size.
if (max_semispace_size_ > reserved_semispace_size_) {
max_semispace_size_ = reserved_semispace_size_;
}
} else {
// If we are not using snapshots we reserve space for the actual
// max semispace size.
reserved_semispace_size_ = max_semispace_size_;
}
if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
// The new space size must be a power of two to support single-bit testing
// for containment.
semispace_size_ = RoundUpToPowerOf2(semispace_size_);
initial_semispace_size_ = Min(initial_semispace_size_, semispace_size_);
young_generation_size_ = 2 * semispace_size_;
external_allocation_limit_ = 10 * semispace_size_;
max_semispace_size_ = RoundUpToPowerOf2(max_semispace_size_);
reserved_semispace_size_ = RoundUpToPowerOf2(reserved_semispace_size_);
initial_semispace_size_ = Min(initial_semispace_size_, max_semispace_size_);
external_allocation_limit_ = 10 * max_semispace_size_;
// The old generation is paged.
old_generation_size_ = RoundUp(old_generation_size_, Page::kPageSize);
max_old_generation_size_ = RoundUp(max_old_generation_size_, Page::kPageSize);
heap_configured = true;
return true;
@ -3319,7 +3343,7 @@ bool Heap::ConfigureHeap(int semispace_size, int old_gen_size) {
bool Heap::ConfigureHeapDefault() {
return ConfigureHeap(FLAG_new_space_size, FLAG_old_space_size);
return ConfigureHeap(FLAG_max_new_space_size / 2, FLAG_max_old_space_size);
}
@ -3355,30 +3379,29 @@ bool Heap::Setup(bool create_heap_objects) {
}
// Setup memory allocator and reserve a chunk of memory for new
// space. The chunk is double the size of the new space to ensure
// that we can find a pair of semispaces that are contiguous and
// aligned to their size.
if (!MemoryAllocator::Setup(MaxCapacity())) return false;
// space. The chunk is double the size of the requested reserved
// new space size to ensure that we can find a pair of semispaces that
// are contiguous and aligned to their size.
if (!MemoryAllocator::Setup(MaxReserved())) return false;
void* chunk =
MemoryAllocator::ReserveInitialChunk(2 * young_generation_size_);
MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_);
if (chunk == NULL) return false;
// Align the pair of semispaces to their size, which must be a power
// of 2.
ASSERT(IsPowerOf2(young_generation_size_));
Address new_space_start =
RoundUp(reinterpret_cast<byte*>(chunk), young_generation_size_);
if (!new_space_.Setup(new_space_start, young_generation_size_)) return false;
RoundUp(reinterpret_cast<byte*>(chunk), 2 * reserved_semispace_size_);
if (!new_space_.Setup(new_space_start, 2 * reserved_semispace_size_)) return false;
// Initialize old pointer space.
old_pointer_space_ =
new OldSpace(old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE);
new OldSpace(max_old_generation_size_, OLD_POINTER_SPACE, NOT_EXECUTABLE);
if (old_pointer_space_ == NULL) return false;
if (!old_pointer_space_->Setup(NULL, 0)) return false;
// Initialize old data space.
old_data_space_ =
new OldSpace(old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE);
new OldSpace(max_old_generation_size_, OLD_DATA_SPACE, NOT_EXECUTABLE);
if (old_data_space_ == NULL) return false;
if (!old_data_space_->Setup(NULL, 0)) return false;
@ -3393,7 +3416,7 @@ bool Heap::Setup(bool create_heap_objects) {
}
code_space_ =
new OldSpace(old_generation_size_, CODE_SPACE, EXECUTABLE);
new OldSpace(max_old_generation_size_, CODE_SPACE, EXECUTABLE);
if (code_space_ == NULL) return false;
if (!code_space_->Setup(NULL, 0)) return false;
@ -3403,7 +3426,7 @@ bool Heap::Setup(bool create_heap_objects) {
if (!map_space_->Setup(NULL, 0)) return false;
// Initialize global property cell space.
cell_space_ = new CellSpace(old_generation_size_, CELL_SPACE);
cell_space_ = new CellSpace(max_old_generation_size_, CELL_SPACE);
if (cell_space_ == NULL) return false;
if (!cell_space_->Setup(NULL, 0)) return false;

View File

@ -235,7 +235,7 @@ class Heap : public AllStatic {
public:
// Configure heap size before setup. Return false if the heap has been
// setup already.
static bool ConfigureHeap(int semispace_size, int old_gen_size);
static bool ConfigureHeap(int max_semispace_size, int max_old_gen_size);
static bool ConfigureHeapDefault();
// Initializes the global object heap. If create_heap_objects is true,
@ -254,14 +254,18 @@ class Heap : public AllStatic {
// Returns whether Setup has been called.
static bool HasBeenSetup();
// Returns the maximum heap capacity.
static int MaxCapacity() {
return young_generation_size_ + old_generation_size_;
// Returns the maximum amount of memory reserved for the heap. For
// the young generation, we reserve 4 times the amount needed for a
// semi space. The young generation consists of two semi spaces and
// we reserve twice the amount needed for those in order to ensure
// that new space can be aligned to its size.
static int MaxReserved() {
return 4 * reserved_semispace_size_ + max_old_generation_size_;
}
static int SemiSpaceSize() { return semispace_size_; }
static int MaxSemiSpaceSize() { return max_semispace_size_; }
static int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
static int InitialSemiSpaceSize() { return initial_semispace_size_; }
static int YoungGenerationSize() { return young_generation_size_; }
static int OldGenerationSize() { return old_generation_size_; }
static int MaxOldGenerationSize() { return max_old_generation_size_; }
// Returns the capacity of the heap in bytes w/o growing. Heap grows when
// more spaces are needed until it reaches the limit.
@ -905,10 +909,10 @@ class Heap : public AllStatic {
ExternalArrayType array_type);
private:
static int semispace_size_;
static int reserved_semispace_size_;
static int max_semispace_size_;
static int initial_semispace_size_;
static int young_generation_size_;
static int old_generation_size_;
static int max_old_generation_size_;
static size_t code_range_size_;
// For keeping track of how much data has survived

View File

@ -2117,7 +2117,7 @@ void Assembler::GrowBuffer() {
// Some internal data structures overflow for very large buffers,
// they must ensure that kMaximalBufferSize is not too large.
if ((desc.buffer_size > kMaximalBufferSize) ||
(desc.buffer_size > Heap::OldGenerationSize())) {
(desc.buffer_size > Heap::MaxOldGenerationSize())) {
V8::FatalProcessOutOfMemory("Assembler::GrowBuffer");
}

View File

@ -982,7 +982,7 @@ bool NewSpace::Setup(Address start, int size) {
// To support fast containment testing in the new space, the size of
// this chunk must be a power of two and it must be aligned to its size.
int initial_semispace_capacity = Heap::InitialSemiSpaceSize();
int maximum_semispace_capacity = Heap::SemiSpaceSize();
int maximum_semispace_capacity = Heap::MaxSemiSpaceSize();
ASSERT(initial_semispace_capacity <= maximum_semispace_capacity);
ASSERT(IsPowerOf2(maximum_semispace_capacity));
@ -998,7 +998,7 @@ bool NewSpace::Setup(Address start, int size) {
#undef SET_NAME
#endif
ASSERT(size == 2 * maximum_semispace_capacity);
ASSERT(size == 2 * Heap::ReservedSemiSpaceSize());
ASSERT(IsAddressAligned(start, size, 0));
if (!to_space_.Setup(start,

View File

@ -393,7 +393,7 @@ void Assembler::GrowBuffer() {
// Some internal data structures overflow for very large buffers,
// they must ensure that kMaximalBufferSize is not too large.
if ((desc.buffer_size > kMaximalBufferSize) ||
(desc.buffer_size > Heap::OldGenerationSize())) {
(desc.buffer_size > Heap::MaxOldGenerationSize())) {
V8::FatalProcessOutOfMemory("Assembler::GrowBuffer");
}

View File

@ -71,10 +71,6 @@ TEST(MarkingStack) {
TEST(Promotion) {
// Test the situation that some objects in new space are promoted to the
// old space
if (Snapshot::IsEnabled()) return;
// Ensure that we get a compacting collection so that objects are promoted
// from new space.
FLAG_gc_global = true;
@ -106,7 +102,6 @@ TEST(Promotion) {
TEST(NoPromotion) {
if (Snapshot::IsEnabled()) return;
Heap::ConfigureHeap(2*256*KB, 4*MB);
// Test the situation that some objects in new space are promoted to

View File

@ -99,9 +99,9 @@ TEST(Page) {
TEST(MemoryAllocator) {
CHECK(Heap::ConfigureHeapDefault());
CHECK(MemoryAllocator::Setup(Heap::MaxCapacity()));
CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
OldSpace faked_space(Heap::MaxCapacity(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
int total_pages = 0;
int requested = 2;
int allocated;
@ -155,16 +155,16 @@ TEST(MemoryAllocator) {
TEST(NewSpace) {
CHECK(Heap::ConfigureHeapDefault());
CHECK(MemoryAllocator::Setup(Heap::MaxCapacity()));
CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
NewSpace new_space;
void* chunk =
MemoryAllocator::ReserveInitialChunk(2 * Heap::YoungGenerationSize());
MemoryAllocator::ReserveInitialChunk(4 * Heap::ReservedSemiSpaceSize());
CHECK(chunk != NULL);
Address start = RoundUp(static_cast<Address>(chunk),
Heap::YoungGenerationSize());
CHECK(new_space.Setup(start, Heap::YoungGenerationSize()));
2 * Heap::ReservedSemiSpaceSize());
CHECK(new_space.Setup(start, 2 * Heap::ReservedSemiSpaceSize()));
CHECK(new_space.HasBeenSetup());
while (new_space.Available() >= Page::kMaxHeapObjectSize) {
@ -180,18 +180,18 @@ TEST(NewSpace) {
TEST(OldSpace) {
CHECK(Heap::ConfigureHeapDefault());
CHECK(MemoryAllocator::Setup(Heap::MaxCapacity()));
CHECK(MemoryAllocator::Setup(Heap::MaxReserved()));
OldSpace* s = new OldSpace(Heap::OldGenerationSize(),
OldSpace* s = new OldSpace(Heap::MaxOldGenerationSize(),
OLD_POINTER_SPACE,
NOT_EXECUTABLE);
CHECK(s != NULL);
void* chunk =
MemoryAllocator::ReserveInitialChunk(2 * Heap::YoungGenerationSize());
MemoryAllocator::ReserveInitialChunk(4 * Heap::ReservedSemiSpaceSize());
CHECK(chunk != NULL);
Address start = static_cast<Address>(chunk);
size_t size = RoundUp(start, Heap::YoungGenerationSize()) - start;
size_t size = RoundUp(start, 2 * Heap::ReservedSemiSpaceSize()) - start;
CHECK(s->Setup(start, size));