From 7dab62ee964b18f14bb99a304584c1b134b95720 Mon Sep 17 00:00:00 2001 From: "bak@chromium.org" Date: Thu, 18 Jun 2009 14:06:36 +0000 Subject: [PATCH] Changed allocation to allow large objects to be allocated in new space. This avoids back-to-back mark-sweep collections. Review URL: http://codereview.chromium.org/136001 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2219 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/heap-inl.h | 2 +- src/heap.cc | 130 +++++++++++++++++++------------ src/heap.h | 7 +- src/ia32/builtins-ia32.cc | 4 +- src/mark-compact.cc | 17 ++-- src/serialize.cc | 18 +++-- src/spaces.h | 1 - test/cctest/test-heap.cc | 4 +- test/cctest/test-mark-compact.cc | 7 +- 9 files changed, 117 insertions(+), 73 deletions(-) diff --git a/src/heap-inl.h b/src/heap-inl.h index 016d64d61..810d3d42a 100644 --- a/src/heap-inl.h +++ b/src/heap-inl.h @@ -34,7 +34,7 @@ namespace v8 { namespace internal { -int Heap::MaxHeapObjectSize() { +int Heap::MaxObjectSizeInPagedSpace() { return Page::kMaxHeapObjectSize; } diff --git a/src/heap.cc b/src/heap.cc index 1f7df1f76..19434f8f9 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -943,17 +943,15 @@ void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { // If the object should be promoted, we try to copy it to old space. if (ShouldBePromoted(object->address(), object_size)) { - OldSpace* target_space = Heap::TargetSpace(object); - ASSERT(target_space == Heap::old_pointer_space_ || - target_space == Heap::old_data_space_); - Object* result = target_space->AllocateRaw(object_size); - if (!result->IsFailure()) { - HeapObject* target = HeapObject::cast(result); - if (target_space == Heap::old_pointer_space_) { + Object* result; + if (object_size > MaxObjectSizeInPagedSpace()) { + result = lo_space_->AllocateRawFixedArray(object_size); + if (!result->IsFailure()) { // Save the from-space object pointer and its map pointer at the // top of the to space to be swept and copied later. Write the // forwarding address over the map word of the from-space // object. + HeapObject* target = HeapObject::cast(result); promotion_queue.insert(object, first_word.ToMap()); object->set_map_word(MapWord::FromForwardingAddress(target)); @@ -964,21 +962,45 @@ void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { node->set_size(object_size); *p = target; - } else { - // Objects promoted to the data space can be copied immediately - // and not revisited---we will never sweep that space for - // pointers and the copied objects do not contain pointers to - // new space objects. - *p = MigrateObject(object, target, object_size); + return; + } + } else { + OldSpace* target_space = Heap::TargetSpace(object); + ASSERT(target_space == Heap::old_pointer_space_ || + target_space == Heap::old_data_space_); + result = target_space->AllocateRaw(object_size); + if (!result->IsFailure()) { + HeapObject* target = HeapObject::cast(result); + if (target_space == Heap::old_pointer_space_) { + // Save the from-space object pointer and its map pointer at the + // top of the to space to be swept and copied later. Write the + // forwarding address over the map word of the from-space + // object. + promotion_queue.insert(object, first_word.ToMap()); + object->set_map_word(MapWord::FromForwardingAddress(target)); + + // Give the space allocated for the result a proper map by + // treating it as a free list node (not linked into the free + // list). + FreeListNode* node = FreeListNode::FromAddress(target->address()); + node->set_size(object_size); + + *p = target; + } else { + // Objects promoted to the data space can be copied immediately + // and not revisited---we will never sweep that space for + // pointers and the copied objects do not contain pointers to + // new space objects. + *p = MigrateObject(object, target, object_size); #ifdef DEBUG - VerifyNonPointerSpacePointersVisitor v; - (*p)->Iterate(&v); + VerifyNonPointerSpacePointersVisitor v; + (*p)->Iterate(&v); #endif + } + return; } - return; } } - // The object should remain in new space or the old space allocation failed. Object* result = new_space_.AllocateRaw(object_size); // Failed allocation at this point is utterly unexpected. @@ -1698,7 +1720,7 @@ Object* Heap::AllocateByteArray(int length, PretenureFlag pretenure) { } int size = ByteArray::SizeFor(length); AllocationSpace space = - size > MaxHeapObjectSize() ? LO_SPACE : OLD_DATA_SPACE; + size > MaxObjectSizeInPagedSpace() ? LO_SPACE : OLD_DATA_SPACE; Object* result = AllocateRaw(size, space, OLD_DATA_SPACE); @@ -1713,7 +1735,7 @@ Object* Heap::AllocateByteArray(int length, PretenureFlag pretenure) { Object* Heap::AllocateByteArray(int length) { int size = ByteArray::SizeFor(length); AllocationSpace space = - size > MaxHeapObjectSize() ? LO_SPACE : NEW_SPACE; + size > MaxObjectSizeInPagedSpace() ? LO_SPACE : NEW_SPACE; Object* result = AllocateRaw(size, space, OLD_DATA_SPACE); @@ -1748,7 +1770,7 @@ Object* Heap::CreateCode(const CodeDesc& desc, int obj_size = Code::SizeFor(body_size, sinfo_size); ASSERT(IsAligned(obj_size, Code::kCodeAlignment)); Object* result; - if (obj_size > MaxHeapObjectSize()) { + if (obj_size > MaxObjectSizeInPagedSpace()) { result = lo_space_->AllocateRawCode(obj_size); } else { result = code_space_->AllocateRaw(obj_size); @@ -1788,7 +1810,7 @@ Object* Heap::CopyCode(Code* code) { // Allocate an object the same size as the code object. int obj_size = code->Size(); Object* result; - if (obj_size > MaxHeapObjectSize()) { + if (obj_size > MaxObjectSizeInPagedSpace()) { result = lo_space_->AllocateRawCode(obj_size); } else { result = code_space_->AllocateRaw(obj_size); @@ -1963,7 +1985,7 @@ Object* Heap::AllocateJSObjectFromMap(Map* map, PretenureFlag pretenure) { // Allocate the JSObject. AllocationSpace space = (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE; - if (map->instance_size() > MaxHeapObjectSize()) space = LO_SPACE; + if (map->instance_size() > MaxObjectSizeInPagedSpace()) space = LO_SPACE; Object* obj = Allocate(map, space); if (obj->IsFailure()) return obj; @@ -2250,7 +2272,7 @@ Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, // Allocate string. AllocationSpace space = - (size > MaxHeapObjectSize()) ? LO_SPACE : OLD_DATA_SPACE; + (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_DATA_SPACE; Object* result = AllocateRaw(size, space, OLD_DATA_SPACE); if (result->IsFailure()) return result; @@ -2272,13 +2294,16 @@ Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer, Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) { AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; int size = SeqAsciiString::SizeFor(length); - if (size > MaxHeapObjectSize()) { - space = LO_SPACE; - } - // Use AllocateRaw rather than Allocate because the object's size cannot be - // determined from the map. - Object* result = AllocateRaw(size, space, OLD_DATA_SPACE); + Object* result = Failure::OutOfMemoryException(); + if (space == NEW_SPACE) { + result = size <= kMaxObjectSizeInNewSpace + ? new_space_.AllocateRaw(size) + : lo_space_->AllocateRawFixedArray(size); + } else { + if (size > MaxObjectSizeInPagedSpace()) space = LO_SPACE; + result = AllocateRaw(size, space, OLD_DATA_SPACE); + } if (result->IsFailure()) return result; // Determine the map based on the string's length. @@ -2302,13 +2327,16 @@ Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) { Object* Heap::AllocateRawTwoByteString(int length, PretenureFlag pretenure) { AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE; int size = SeqTwoByteString::SizeFor(length); - if (size > MaxHeapObjectSize()) { - space = LO_SPACE; - } - // Use AllocateRaw rather than Allocate because the object's size cannot be - // determined from the map. - Object* result = AllocateRaw(size, space, OLD_DATA_SPACE); + Object* result = Failure::OutOfMemoryException(); + if (space == NEW_SPACE) { + result = size <= kMaxObjectSizeInNewSpace + ? new_space_.AllocateRaw(size) + : lo_space_->AllocateRawFixedArray(size); + } else { + if (size > MaxObjectSizeInPagedSpace()) space = LO_SPACE; + result = AllocateRaw(size, space, OLD_DATA_SPACE); + } if (result->IsFailure()) return result; // Determine the map based on the string's length. @@ -2345,9 +2373,9 @@ Object* Heap::AllocateRawFixedArray(int length) { if (always_allocate()) return AllocateFixedArray(length, NOT_TENURED); // Allocate the raw data for a fixed array. int size = FixedArray::SizeFor(length); - return (size > MaxHeapObjectSize()) - ? lo_space_->AllocateRawFixedArray(size) - : new_space_.AllocateRaw(size); + return size <= kMaxObjectSizeInNewSpace + ? new_space_.AllocateRaw(size) + : lo_space_->AllocateRawFixedArray(size); } @@ -2395,16 +2423,22 @@ Object* Heap::AllocateFixedArray(int length, PretenureFlag pretenure) { if (length == 0) return empty_fixed_array(); int size = FixedArray::SizeFor(length); - Object* result; - if (size > MaxHeapObjectSize()) { - result = lo_space_->AllocateRawFixedArray(size); - } else { - AllocationSpace space = - (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE; - result = AllocateRaw(size, space, OLD_POINTER_SPACE); + Object* result = Failure::OutOfMemoryException(); + if (pretenure != TENURED) { + result = size <= kMaxObjectSizeInNewSpace + ? new_space_.AllocateRaw(size) + : lo_space_->AllocateRawFixedArray(size); + } + if (result->IsFailure()) { + if (size > MaxObjectSizeInPagedSpace()) { + result = lo_space_->AllocateRawFixedArray(size); + } else { + AllocationSpace space = + (pretenure == TENURED) ? OLD_POINTER_SPACE : NEW_SPACE; + result = AllocateRaw(size, space, OLD_POINTER_SPACE); + } + if (result->IsFailure()) return result; } - if (result->IsFailure()) return result; - // Initialize the object. reinterpret_cast(result)->set_map(fixed_array_map()); FixedArray* array = FixedArray::cast(result); @@ -2504,7 +2538,7 @@ STRUCT_LIST(MAKE_CASE) } int size = map->instance_size(); AllocationSpace space = - (size > MaxHeapObjectSize()) ? LO_SPACE : OLD_POINTER_SPACE; + (size > MaxObjectSizeInPagedSpace()) ? LO_SPACE : OLD_POINTER_SPACE; Object* result = Heap::Allocate(map, space); if (result->IsFailure()) return result; Struct::cast(result)->InitializeBody(size); diff --git a/src/heap.h b/src/heap.h index e3289fcaa..9be369776 100644 --- a/src/heap.h +++ b/src/heap.h @@ -242,9 +242,8 @@ class Heap : public AllStatic { // all available bytes. Check MaxHeapObjectSize() instead. static int Available(); - // Returns the maximum object size that heap supports. Objects larger than - // the maximum heap object size are allocated in a large object space. - static inline int MaxHeapObjectSize(); + // Returns the maximum object size in paged space. + static inline int MaxObjectSizeInPagedSpace(); // Returns of size of all objects residing in the heap. static int SizeOfObjects(); @@ -830,6 +829,8 @@ class Heap : public AllStatic { static const int kMaxMapSpaceSize = 8*MB; + static const int kMaxObjectSizeInNewSpace = 256*KB; + static NewSpace new_space_; static OldSpace* old_pointer_space_; static OldSpace* old_data_space_; diff --git a/src/ia32/builtins-ia32.cc b/src/ia32/builtins-ia32.cc index f65074bd4..6230f2c95 100644 --- a/src/ia32/builtins-ia32.cc +++ b/src/ia32/builtins-ia32.cc @@ -113,7 +113,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // Make sure that the maximum heap object size will never cause us // problem here, because it is always greater than the maximum // instance size that can be represented in a byte. - ASSERT(Heap::MaxHeapObjectSize() >= (1 << kBitsPerByte)); + ASSERT(Heap::MaxObjectSizeInPagedSpace() >= (1 << kBitsPerByte)); ExternalReference new_space_allocation_top = ExternalReference::new_space_allocation_top_address(); __ mov(ebx, Operand::StaticVariable(new_space_allocation_top)); @@ -175,7 +175,7 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { // ebx: JSObject // edi: start of next object (will be start of FixedArray) // edx: number of elements in properties array - ASSERT(Heap::MaxHeapObjectSize() > + ASSERT(Heap::MaxObjectSizeInPagedSpace() > (FixedArray::kHeaderSize + 255*kPointerSize)); __ lea(ecx, Operand(edi, edx, times_4, FixedArray::kHeaderSize)); __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit)); diff --git a/src/mark-compact.cc b/src/mark-compact.cc index 56e4ea6ca..89d97e925 100644 --- a/src/mark-compact.cc +++ b/src/mark-compact.cc @@ -947,13 +947,18 @@ void EncodeFreeRegion(Address free_start, int free_size) { // Try to promote all objects in new space. Heap numbers and sequential -// strings are promoted to the code space, all others to the old space. +// strings are promoted to the code space, large objects to large object space, +// and all others to the old space. inline Object* MCAllocateFromNewSpace(HeapObject* object, int object_size) { - OldSpace* target_space = Heap::TargetSpace(object); - ASSERT(target_space == Heap::old_pointer_space() || - target_space == Heap::old_data_space()); - Object* forwarded = target_space->MCAllocateRaw(object_size); - + Object* forwarded; + if (object_size > Heap::MaxObjectSizeInPagedSpace()) { + forwarded = Failure::Exception(); + } else { + OldSpace* target_space = Heap::TargetSpace(object); + ASSERT(target_space == Heap::old_pointer_space() || + target_space == Heap::old_data_space()); + forwarded = target_space->MCAllocateRaw(object_size); + } if (forwarded->IsFailure()) { forwarded = Heap::new_space()->MCAllocateRaw(object_size); } diff --git a/src/serialize.cc b/src/serialize.cc index eb497fb2e..f45d65d30 100644 --- a/src/serialize.cc +++ b/src/serialize.cc @@ -1261,15 +1261,19 @@ RelativeAddress Serializer::Allocate(HeapObject* obj) { found = Heap::InSpace(obj, s); } CHECK(found); + int size = obj->Size(); if (s == NEW_SPACE) { - Space* space = Heap::TargetSpace(obj); - ASSERT(space == Heap::old_pointer_space() || - space == Heap::old_data_space()); - s = (space == Heap::old_pointer_space()) ? - OLD_POINTER_SPACE : - OLD_DATA_SPACE; + if (size > Heap::MaxObjectSizeInPagedSpace()) { + s = LO_SPACE; + } else { + OldSpace* space = Heap::TargetSpace(obj); + ASSERT(space == Heap::old_pointer_space() || + space == Heap::old_data_space()); + s = (space == Heap::old_pointer_space()) ? + OLD_POINTER_SPACE : + OLD_DATA_SPACE; + } } - int size = obj->Size(); GCTreatment gc_treatment = DataObject; if (obj->IsFixedArray()) gc_treatment = PointerObject; else if (obj->IsCode()) gc_treatment = CodeObject; diff --git a/src/spaces.h b/src/spaces.h index a62b0a8d3..0538c5f36 100644 --- a/src/spaces.h +++ b/src/spaces.h @@ -1041,7 +1041,6 @@ class SemiSpaceIterator : public ObjectIterator { HeapObject* object = HeapObject::FromAddress(current_); int size = (size_func_ == NULL) ? object->Size() : size_func_(object); - ASSERT_OBJECT_SIZE(size); current_ += size; return object; diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 515657f71..396bcc50b 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -208,7 +208,7 @@ TEST(GarbageCollection) { v8::HandleScope sc; // check GC when heap is empty - int free_bytes = Heap::MaxHeapObjectSize(); + int free_bytes = Heap::MaxObjectSizeInPagedSpace(); CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE)); // allocate a function and keep it in global object's property @@ -782,7 +782,7 @@ TEST(Iteration) { Factory::NewStringFromAscii(CStrVector("abcdefghij"), TENURED); // Allocate a large string (for large object space). - int large_size = Heap::MaxHeapObjectSize() + 1; + int large_size = Heap::MaxObjectSizeInPagedSpace() + 1; char* str = new char[large_size]; for (int i = 0; i < large_size - 1; ++i) str[i] = 'a'; str[large_size - 1] = '\0'; diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc index 53cff688a..8db7339b5 100644 --- a/test/cctest/test-mark-compact.cc +++ b/test/cctest/test-mark-compact.cc @@ -86,8 +86,8 @@ TEST(Promotion) { v8::HandleScope sc; // Allocate a fixed array in the new space. - int array_size = - (Heap::MaxHeapObjectSize() - Array::kHeaderSize) / (kPointerSize * 4); + int array_size = (Heap::MaxObjectSizeInPagedSpace() - Array::kHeaderSize) / + (kPointerSize * 4); Object* obj = Heap::AllocateFixedArray(array_size); CHECK(!obj->IsFailure()); @@ -118,7 +118,8 @@ TEST(NoPromotion) { CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE)); // Allocate a big Fixed array in the new space. - int size = (Heap::MaxHeapObjectSize() - Array::kHeaderSize) / kPointerSize; + int size = (Heap::MaxObjectSizeInPagedSpace() - Array::kHeaderSize) / + kPointerSize; Object* obj = Heap::AllocateFixedArray(size); Handle array(FixedArray::cast(obj)); -- 2.34.1