Commit 17573d77 authored by ager@chromium.org's avatar ager@chromium.org

Landing for Justin Schuh.

Add 128MB limit for executable pages.

BUG=http://code.google.com/p/v8/issues/detail?id=925
TEST=None.
TBR=jschuh@chromium.org
Review URL: http://codereview.chromium.org/4634003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5799 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 20d3aad5
...@@ -2348,12 +2348,15 @@ class V8EXPORT ResourceConstraints { ...@@ -2348,12 +2348,15 @@ class V8EXPORT ResourceConstraints {
void set_max_young_space_size(int value) { max_young_space_size_ = value; } void set_max_young_space_size(int value) { max_young_space_size_ = value; }
int max_old_space_size() const { return max_old_space_size_; } int max_old_space_size() const { return max_old_space_size_; }
void set_max_old_space_size(int value) { max_old_space_size_ = value; } void set_max_old_space_size(int value) { max_old_space_size_ = value; }
int max_executable_size() { return max_executable_size_; }
void set_max_executable_size(int value) { max_executable_size_ = value; }
uint32_t* stack_limit() const { return stack_limit_; } uint32_t* stack_limit() const { return stack_limit_; }
// Sets an address beyond which the VM's stack may not grow. // Sets an address beyond which the VM's stack may not grow.
void set_stack_limit(uint32_t* value) { stack_limit_ = value; } void set_stack_limit(uint32_t* value) { stack_limit_ = value; }
private: private:
int max_young_space_size_; int max_young_space_size_;
int max_old_space_size_; int max_old_space_size_;
int max_executable_size_;
uint32_t* stack_limit_; uint32_t* stack_limit_;
}; };
...@@ -2485,13 +2488,18 @@ class V8EXPORT HeapStatistics { ...@@ -2485,13 +2488,18 @@ class V8EXPORT HeapStatistics {
public: public:
HeapStatistics(); HeapStatistics();
size_t total_heap_size() { return total_heap_size_; } size_t total_heap_size() { return total_heap_size_; }
size_t total_heap_size_executable() { return total_heap_size_executable_; }
size_t used_heap_size() { return used_heap_size_; } size_t used_heap_size() { return used_heap_size_; }
private: private:
void set_total_heap_size(size_t size) { total_heap_size_ = size; } void set_total_heap_size(size_t size) { total_heap_size_ = size; }
void set_total_heap_size_executable(size_t size) {
total_heap_size_executable_ = size;
}
void set_used_heap_size(size_t size) { used_heap_size_ = size; } void set_used_heap_size(size_t size) { used_heap_size_ = size; }
size_t total_heap_size_; size_t total_heap_size_;
size_t total_heap_size_executable_;
size_t used_heap_size_; size_t used_heap_size_;
friend class V8; friend class V8;
......
...@@ -393,14 +393,18 @@ v8::Handle<Boolean> False() { ...@@ -393,14 +393,18 @@ v8::Handle<Boolean> False() {
ResourceConstraints::ResourceConstraints() ResourceConstraints::ResourceConstraints()
: max_young_space_size_(0), : max_young_space_size_(0),
max_old_space_size_(0), max_old_space_size_(0),
max_executable_size_(0),
stack_limit_(NULL) { } stack_limit_(NULL) { }
bool SetResourceConstraints(ResourceConstraints* constraints) { bool SetResourceConstraints(ResourceConstraints* constraints) {
int young_space_size = constraints->max_young_space_size(); int young_space_size = constraints->max_young_space_size();
int old_gen_size = constraints->max_old_space_size(); int old_gen_size = constraints->max_old_space_size();
if (young_space_size != 0 || old_gen_size != 0) { int max_executable_size = constraints->max_executable_size();
bool result = i::Heap::ConfigureHeap(young_space_size / 2, old_gen_size); if (young_space_size != 0 || old_gen_size != 0 || max_executable_size != 0) {
bool result = i::Heap::ConfigureHeap(young_space_size / 2,
old_gen_size,
max_executable_size);
if (!result) return false; if (!result) return false;
} }
if (constraints->stack_limit() != NULL) { if (constraints->stack_limit() != NULL) {
...@@ -3259,11 +3263,15 @@ bool v8::V8::Dispose() { ...@@ -3259,11 +3263,15 @@ bool v8::V8::Dispose() {
} }
HeapStatistics::HeapStatistics(): total_heap_size_(0), used_heap_size_(0) { } HeapStatistics::HeapStatistics(): total_heap_size_(0),
total_heap_size_executable_(0),
used_heap_size_(0) { }
void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) { void v8::V8::GetHeapStatistics(HeapStatistics* heap_statistics) {
heap_statistics->set_total_heap_size(i::Heap::CommittedMemory()); heap_statistics->set_total_heap_size(i::Heap::CommittedMemory());
heap_statistics->set_total_heap_size_executable(
i::Heap::CommittedMemoryExecutable());
heap_statistics->set_used_heap_size(i::Heap::SizeOfObjects()); heap_statistics->set_used_heap_size(i::Heap::SizeOfObjects());
} }
......
...@@ -186,6 +186,7 @@ DEFINE_bool(always_inline_smi_code, false, ...@@ -186,6 +186,7 @@ DEFINE_bool(always_inline_smi_code, false,
// heap.cc // heap.cc
DEFINE_int(max_new_space_size, 0, "max size of the new generation (in kBytes)") DEFINE_int(max_new_space_size, 0, "max size of the new generation (in kBytes)")
DEFINE_int(max_old_space_size, 0, "max size of the old generation (in Mbytes)") DEFINE_int(max_old_space_size, 0, "max size of the old generation (in Mbytes)")
DEFINE_int(max_executable_size, 0, "max size of executable memory (in Mbytes)")
DEFINE_bool(gc_global, false, "always perform global GCs") DEFINE_bool(gc_global, false, "always perform global GCs")
DEFINE_int(gc_interval, -1, "garbage collect after <n> allocations") DEFINE_int(gc_interval, -1, "garbage collect after <n> allocations")
DEFINE_bool(trace_gc, false, DEFINE_bool(trace_gc, false,
......
...@@ -83,16 +83,19 @@ int Heap::max_semispace_size_ = 2*MB; ...@@ -83,16 +83,19 @@ int Heap::max_semispace_size_ = 2*MB;
intptr_t Heap::max_old_generation_size_ = 192*MB; intptr_t Heap::max_old_generation_size_ = 192*MB;
int Heap::initial_semispace_size_ = 128*KB; int Heap::initial_semispace_size_ = 128*KB;
intptr_t Heap::code_range_size_ = 0; intptr_t Heap::code_range_size_ = 0;
intptr_t Heap::max_executable_size_ = max_old_generation_size_;
#elif defined(V8_TARGET_ARCH_X64) #elif defined(V8_TARGET_ARCH_X64)
int Heap::max_semispace_size_ = 16*MB; int Heap::max_semispace_size_ = 16*MB;
intptr_t Heap::max_old_generation_size_ = 1*GB; intptr_t Heap::max_old_generation_size_ = 1*GB;
int Heap::initial_semispace_size_ = 1*MB; int Heap::initial_semispace_size_ = 1*MB;
intptr_t Heap::code_range_size_ = 512*MB; intptr_t Heap::code_range_size_ = 512*MB;
intptr_t Heap::max_executable_size_ = 256*MB;
#else #else
int Heap::max_semispace_size_ = 8*MB; int Heap::max_semispace_size_ = 8*MB;
intptr_t Heap::max_old_generation_size_ = 512*MB; intptr_t Heap::max_old_generation_size_ = 512*MB;
int Heap::initial_semispace_size_ = 512*KB; int Heap::initial_semispace_size_ = 512*KB;
intptr_t Heap::code_range_size_ = 0; intptr_t Heap::code_range_size_ = 0;
intptr_t Heap::max_executable_size_ = 128*MB;
#endif #endif
// The snapshot semispace size will be the default semispace size if // The snapshot semispace size will be the default semispace size if
...@@ -172,6 +175,12 @@ intptr_t Heap::CommittedMemory() { ...@@ -172,6 +175,12 @@ intptr_t Heap::CommittedMemory() {
lo_space_->Size(); lo_space_->Size();
} }
intptr_t Heap::CommittedMemoryExecutable() {
if (!HasBeenSetup()) return 0;
return MemoryAllocator::SizeExecutable();
}
intptr_t Heap::Available() { intptr_t Heap::Available() {
if (!HasBeenSetup()) return 0; if (!HasBeenSetup()) return 0;
...@@ -4313,7 +4322,9 @@ static bool heap_configured = false; ...@@ -4313,7 +4322,9 @@ static bool heap_configured = false;
// TODO(1236194): Since the heap size is configurable on the command line // 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 // and through the API, we should gracefully handle the case that the heap
// size is not big enough to fit all the initial objects. // size is not big enough to fit all the initial objects.
bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) { bool Heap::ConfigureHeap(int max_semispace_size,
int max_old_gen_size,
int max_executable_size) {
if (HasBeenSetup()) return false; if (HasBeenSetup()) return false;
if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size; if (max_semispace_size > 0) max_semispace_size_ = max_semispace_size;
...@@ -4334,6 +4345,9 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) { ...@@ -4334,6 +4345,9 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
} }
if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size; if (max_old_gen_size > 0) max_old_generation_size_ = max_old_gen_size;
if (max_executable_size > 0) {
max_executable_size_ = RoundUp(max_executable_size_, Page::kPageSize);
}
// The new space size must be a power of two to support single-bit testing // The new space size must be a power of two to support single-bit testing
// for containment. // for containment.
...@@ -4351,8 +4365,9 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) { ...@@ -4351,8 +4365,9 @@ bool Heap::ConfigureHeap(int max_semispace_size, int max_old_gen_size) {
bool Heap::ConfigureHeapDefault() { bool Heap::ConfigureHeapDefault() {
return ConfigureHeap( return ConfigureHeap(FLAG_max_new_space_size / 2 * KB,
FLAG_max_new_space_size * (KB / 2), FLAG_max_old_space_size * MB); FLAG_max_old_space_size * MB,
FLAG_max_executable_size * MB);
} }
...@@ -4435,7 +4450,7 @@ bool Heap::Setup(bool create_heap_objects) { ...@@ -4435,7 +4450,7 @@ bool Heap::Setup(bool create_heap_objects) {
// space. The chunk is double the size of the requested reserved // 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 // new space size to ensure that we can find a pair of semispaces that
// are contiguous and aligned to their size. // are contiguous and aligned to their size.
if (!MemoryAllocator::Setup(MaxReserved())) return false; if (!MemoryAllocator::Setup(MaxReserved(), MaxExecutableSize())) return false;
void* chunk = void* chunk =
MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_); MemoryAllocator::ReserveInitialChunk(4 * reserved_semispace_size_);
if (chunk == NULL) return false; if (chunk == NULL) return false;
......
...@@ -222,7 +222,9 @@ class Heap : public AllStatic { ...@@ -222,7 +222,9 @@ class Heap : public AllStatic {
public: public:
// Configure heap size before setup. Return false if the heap has been // Configure heap size before setup. Return false if the heap has been
// setup already. // setup already.
static bool ConfigureHeap(int max_semispace_size, int max_old_gen_size); static bool ConfigureHeap(int max_semispace_size,
int max_old_gen_size,
int max_executable_size);
static bool ConfigureHeapDefault(); static bool ConfigureHeapDefault();
// Initializes the global object heap. If create_heap_objects is true, // Initializes the global object heap. If create_heap_objects is true,
...@@ -253,6 +255,7 @@ class Heap : public AllStatic { ...@@ -253,6 +255,7 @@ class Heap : public AllStatic {
static int ReservedSemiSpaceSize() { return reserved_semispace_size_; } static int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
static int InitialSemiSpaceSize() { return initial_semispace_size_; } static int InitialSemiSpaceSize() { return initial_semispace_size_; }
static intptr_t MaxOldGenerationSize() { return max_old_generation_size_; } static intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
static intptr_t MaxExecutableSize() { return max_executable_size_; }
// Returns the capacity of the heap in bytes w/o growing. Heap grows when // Returns the capacity of the heap in bytes w/o growing. Heap grows when
// more spaces are needed until it reaches the limit. // more spaces are needed until it reaches the limit.
...@@ -261,6 +264,9 @@ class Heap : public AllStatic { ...@@ -261,6 +264,9 @@ class Heap : public AllStatic {
// Returns the amount of memory currently committed for the heap. // Returns the amount of memory currently committed for the heap.
static intptr_t CommittedMemory(); static intptr_t CommittedMemory();
// Returns the amount of executable memory currently committed for the heap.
static intptr_t CommittedMemoryExecutable();
// Returns the available bytes in space w/o growing. // Returns the available bytes in space w/o growing.
// Heap doesn't guarantee that it can allocate an object that requires // Heap doesn't guarantee that it can allocate an object that requires
// all available bytes. Check MaxHeapObjectSize() instead. // all available bytes. Check MaxHeapObjectSize() instead.
...@@ -1096,6 +1102,7 @@ class Heap : public AllStatic { ...@@ -1096,6 +1102,7 @@ class Heap : public AllStatic {
static int max_semispace_size_; static int max_semispace_size_;
static int initial_semispace_size_; static int initial_semispace_size_;
static intptr_t max_old_generation_size_; static intptr_t max_old_generation_size_;
static intptr_t max_executable_size_;
static intptr_t code_range_size_; static intptr_t code_range_size_;
// For keeping track of how much data has survived // For keeping track of how much data has survived
......
...@@ -271,6 +271,7 @@ void CodeRange::TearDown() { ...@@ -271,6 +271,7 @@ void CodeRange::TearDown() {
// MemoryAllocator // MemoryAllocator
// //
intptr_t MemoryAllocator::capacity_ = 0; intptr_t MemoryAllocator::capacity_ = 0;
intptr_t MemoryAllocator::capacity_executable_ = 0;
intptr_t MemoryAllocator::size_ = 0; intptr_t MemoryAllocator::size_ = 0;
intptr_t MemoryAllocator::size_executable_ = 0; intptr_t MemoryAllocator::size_executable_ = 0;
...@@ -302,8 +303,10 @@ int MemoryAllocator::Pop() { ...@@ -302,8 +303,10 @@ int MemoryAllocator::Pop() {
} }
bool MemoryAllocator::Setup(intptr_t capacity) { bool MemoryAllocator::Setup(intptr_t capacity, intptr_t capacity_executable) {
capacity_ = RoundUp(capacity, Page::kPageSize); capacity_ = RoundUp(capacity, Page::kPageSize);
capacity_executable_ = RoundUp(capacity_executable, Page::kPageSize);
ASSERT_GE(capacity_, capacity_executable_);
// Over-estimate the size of chunks_ array. It assumes the expansion of old // Over-estimate the size of chunks_ array. It assumes the expansion of old
// space is always in the unit of a chunk (kChunkSize) except the last // space is always in the unit of a chunk (kChunkSize) except the last
...@@ -346,6 +349,7 @@ void MemoryAllocator::TearDown() { ...@@ -346,6 +349,7 @@ void MemoryAllocator::TearDown() {
ASSERT(top_ == max_nof_chunks_); // all chunks are free ASSERT(top_ == max_nof_chunks_); // all chunks are free
top_ = 0; top_ = 0;
capacity_ = 0; capacity_ = 0;
capacity_executable_ = 0;
size_ = 0; size_ = 0;
max_nof_chunks_ = 0; max_nof_chunks_ = 0;
} }
...@@ -357,16 +361,31 @@ void* MemoryAllocator::AllocateRawMemory(const size_t requested, ...@@ -357,16 +361,31 @@ void* MemoryAllocator::AllocateRawMemory(const size_t requested,
if (size_ + static_cast<size_t>(requested) > static_cast<size_t>(capacity_)) { if (size_ + static_cast<size_t>(requested) > static_cast<size_t>(capacity_)) {
return NULL; return NULL;
} }
void* mem; void* mem;
if (executable == EXECUTABLE && CodeRange::exists()) { if (executable == EXECUTABLE) {
// Check executable memory limit.
if (size_executable_ + requested >
static_cast<size_t>(capacity_executable_)) {
LOG(StringEvent("MemoryAllocator::AllocateRawMemory",
"V8 Executable Allocation capacity exceeded"));
return NULL;
}
// Allocate executable memory either from code range or from the
// OS.
if (CodeRange::exists()) {
mem = CodeRange::AllocateRawMemory(requested, allocated); mem = CodeRange::AllocateRawMemory(requested, allocated);
} else { } else {
mem = OS::Allocate(requested, allocated, (executable == EXECUTABLE)); mem = OS::Allocate(requested, allocated, true);
}
// Update executable memory size.
size_executable_ += static_cast<int>(*allocated);
} else {
mem = OS::Allocate(requested, allocated, false);
} }
int alloced = static_cast<int>(*allocated); int alloced = static_cast<int>(*allocated);
size_ += alloced; size_ += alloced;
if (executable == EXECUTABLE) size_executable_ += alloced;
#ifdef DEBUG #ifdef DEBUG
ZapBlock(reinterpret_cast<Address>(mem), alloced); ZapBlock(reinterpret_cast<Address>(mem), alloced);
#endif #endif
...@@ -391,6 +410,7 @@ void MemoryAllocator::FreeRawMemory(void* mem, ...@@ -391,6 +410,7 @@ void MemoryAllocator::FreeRawMemory(void* mem,
if (executable == EXECUTABLE) size_executable_ -= static_cast<int>(length); if (executable == EXECUTABLE) size_executable_ -= static_cast<int>(length);
ASSERT(size_ >= 0); ASSERT(size_ >= 0);
ASSERT(size_executable_ >= 0);
} }
......
...@@ -491,8 +491,8 @@ class CodeRange : public AllStatic { ...@@ -491,8 +491,8 @@ class CodeRange : public AllStatic {
class MemoryAllocator : public AllStatic { class MemoryAllocator : public AllStatic {
public: public:
// Initializes its internal bookkeeping structures. // Initializes its internal bookkeeping structures.
// Max capacity of the total space. // Max capacity of the total space and executable memory limit.
static bool Setup(intptr_t max_capacity); static bool Setup(int max_capacity, int capacity_executable);
// Deletes valid chunks. // Deletes valid chunks.
static void TearDown(); static void TearDown();
...@@ -590,6 +590,12 @@ class MemoryAllocator : public AllStatic { ...@@ -590,6 +590,12 @@ class MemoryAllocator : public AllStatic {
// Returns allocated spaces in bytes. // Returns allocated spaces in bytes.
static intptr_t Size() { return size_; } static intptr_t Size() { return size_; }
// Returns the maximum available executable bytes of heaps.
static int AvailableExecutable() {
if (capacity_executable_ < size_executable_) return 0;
return capacity_executable_ - size_executable_;
}
// Returns allocated executable spaces in bytes. // Returns allocated executable spaces in bytes.
static intptr_t SizeExecutable() { return size_executable_; } static intptr_t SizeExecutable() { return size_executable_; }
...@@ -653,6 +659,8 @@ class MemoryAllocator : public AllStatic { ...@@ -653,6 +659,8 @@ class MemoryAllocator : public AllStatic {
private: private:
// Maximum space size in bytes. // Maximum space size in bytes.
static intptr_t capacity_; static intptr_t capacity_;
// Maximum subset of capacity_ that can be executable
static intptr_t capacity_executable_;
// Allocated space size in bytes. // Allocated space size in bytes.
static intptr_t size_; static intptr_t size_;
......
...@@ -75,7 +75,7 @@ TEST(Promotion) { ...@@ -75,7 +75,7 @@ TEST(Promotion) {
// from new space. // from new space.
FLAG_gc_global = true; FLAG_gc_global = true;
FLAG_always_compact = true; FLAG_always_compact = true;
Heap::ConfigureHeap(2*256*KB, 4*MB); Heap::ConfigureHeap(2*256*KB, 4*MB, 0);
InitializeVM(); InitializeVM();
...@@ -101,7 +101,7 @@ TEST(Promotion) { ...@@ -101,7 +101,7 @@ TEST(Promotion) {
TEST(NoPromotion) { TEST(NoPromotion) {
Heap::ConfigureHeap(2*256*KB, 4*MB); Heap::ConfigureHeap(2*256*KB, 4*MB, 0);
// Test the situation that some objects in new space are promoted to // Test the situation that some objects in new space are promoted to
// the old space // the old space
......
...@@ -91,7 +91,7 @@ TEST(Page) { ...@@ -91,7 +91,7 @@ TEST(Page) {
TEST(MemoryAllocator) { TEST(MemoryAllocator) {
CHECK(Heap::ConfigureHeapDefault()); CHECK(Heap::ConfigureHeapDefault());
CHECK(MemoryAllocator::Setup(Heap::MaxReserved())); CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE); OldSpace faked_space(Heap::MaxReserved(), OLD_POINTER_SPACE, NOT_EXECUTABLE);
int total_pages = 0; int total_pages = 0;
...@@ -147,7 +147,7 @@ TEST(MemoryAllocator) { ...@@ -147,7 +147,7 @@ TEST(MemoryAllocator) {
TEST(NewSpace) { TEST(NewSpace) {
CHECK(Heap::ConfigureHeapDefault()); CHECK(Heap::ConfigureHeapDefault());
CHECK(MemoryAllocator::Setup(Heap::MaxReserved())); CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
NewSpace new_space; NewSpace new_space;
...@@ -172,7 +172,7 @@ TEST(NewSpace) { ...@@ -172,7 +172,7 @@ TEST(NewSpace) {
TEST(OldSpace) { TEST(OldSpace) {
CHECK(Heap::ConfigureHeapDefault()); CHECK(Heap::ConfigureHeapDefault());
CHECK(MemoryAllocator::Setup(Heap::MaxReserved())); CHECK(MemoryAllocator::Setup(Heap::MaxReserved(), Heap::MaxExecutableSize()));
OldSpace* s = new OldSpace(Heap::MaxOldGenerationSize(), OldSpace* s = new OldSpace(Heap::MaxOldGenerationSize(),
OLD_POINTER_SPACE, OLD_POINTER_SPACE,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment