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
This commit is contained in:
bak@chromium.org 2009-06-18 14:06:36 +00:00
parent 531a6db569
commit 7dab62ee96
9 changed files with 120 additions and 76 deletions

View File

@ -34,7 +34,7 @@
namespace v8 {
namespace internal {
int Heap::MaxHeapObjectSize() {
int Heap::MaxObjectSizeInPagedSpace() {
return Page::kMaxHeapObjectSize;
}

View File

@ -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);
#ifdef DEBUG
VerifyNonPointerSpacePointersVisitor v;
(*p)->Iterate(&v);
#endif
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);
#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<Array*>(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);

View File

@ -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_;

View File

@ -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));

View File

@ -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);
}

View File

@ -1261,15 +1261,19 @@ RelativeAddress Serializer::Allocate(HeapObject* obj) {
found = Heap::InSpace(obj, s);
}
CHECK(found);
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;
}
int size = obj->Size();
if (s == NEW_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;
}
}
GCTreatment gc_treatment = DataObject;
if (obj->IsFixedArray()) gc_treatment = PointerObject;
else if (obj->IsCode()) gc_treatment = CodeObject;

View File

@ -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;

View File

@ -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';

View File

@ -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<FixedArray> array(FixedArray::cast(obj));