Changed allocation to allow large objects to be allocated in new space.
authorbak@chromium.org <bak@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 18 Jun 2009 14:06:36 +0000 (14:06 +0000)
committerbak@chromium.org <bak@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 18 Jun 2009 14:06:36 +0000 (14:06 +0000)
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
src/heap.cc
src/heap.h
src/ia32/builtins-ia32.cc
src/mark-compact.cc
src/serialize.cc
src/spaces.h
test/cctest/test-heap.cc
test/cctest/test-mark-compact.cc

index 016d64d..810d3d4 100644 (file)
@@ -34,7 +34,7 @@
 namespace v8 {
 namespace internal {
 
-int Heap::MaxHeapObjectSize() {
+int Heap::MaxObjectSizeInPagedSpace() {
   return Page::kMaxHeapObjectSize;
 }
 
index 1f7df1f..19434f8 100644 (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);
+        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<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);
index e3289fc..9be3697 100644 (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_;
index f65074b..6230f2c 100644 (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));
index 56e4ea6..89d97e9 100644 (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);
   }
index eb497fb..f45d65d 100644 (file)
@@ -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;
index a62b0a8..0538c5f 100644 (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;
index 515657f..396bcc5 100644 (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';
index 53cff68..8db7339 100644 (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));