- Optimized CopyFixedArray and CopyJSObject.
authorbak@chromium.org <bak@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 22 Oct 2008 08:21:18 +0000 (08:21 +0000)
committerbak@chromium.org <bak@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 22 Oct 2008 08:21:18 +0000 (08:21 +0000)
- Refactored block copying.

Review URL: http://codereview.chromium.org/7863

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@548 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

13 files changed:
src/codegen-arm.cc
src/codegen-ia32.cc
src/handles.cc
src/handles.h
src/heap-inl.h
src/heap.cc
src/heap.h
src/objects-inl.h
src/objects.cc
src/objects.h
src/runtime.cc
src/spaces-inl.h
test/cctest/test-heap.cc

index f89525d..8832b83 100644 (file)
@@ -3909,7 +3909,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
 
 #ifdef DEBUG
   if (FLAG_gc_greedy) {
-    Failure* failure = Failure::RetryAfterGC(0, NEW_SPACE);
+    Failure* failure = Failure::RetryAfterGC(0);
     __ mov(r0, Operand(reinterpret_cast<intptr_t>(failure)));
   }
   GenerateCore(masm,
index a55441b..a2f8d64 100644 (file)
@@ -4937,7 +4937,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
 
 #ifdef DEBUG
   if (FLAG_gc_greedy) {
-    Failure* failure = Failure::RetryAfterGC(0, NEW_SPACE);
+    Failure* failure = Failure::RetryAfterGC(0);
     __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(failure)));
   }
   GenerateCore(masm, &throw_normal_exception,
index a1f8400..222876d 100644 (file)
@@ -237,8 +237,8 @@ Handle<Object> SetElement(Handle<JSObject> object,
 }
 
 
-Handle<JSObject> Copy(Handle<JSObject> obj, PretenureFlag pretenure) {
-  CALL_HEAP_FUNCTION(obj->Copy(pretenure), JSObject);
+Handle<JSObject> Copy(Handle<JSObject> obj) {
+  CALL_HEAP_FUNCTION(Heap::CopyJSObject(*obj), JSObject);
 }
 
 
index 8b0a466..a9adf3d 100644 (file)
@@ -144,7 +144,7 @@ Handle<Object> DeleteProperty(Handle<JSObject> obj, Handle<String> prop);
 
 Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index);
 
-Handle<JSObject> Copy(Handle<JSObject> obj, PretenureFlag = NOT_TENURED);
+Handle<JSObject> Copy(Handle<JSObject> obj);
 
 // Get the JS object corresponding to the given script; create it
 // if none exists.
index 036ddb8..16870a7 100644 (file)
@@ -146,6 +146,25 @@ OldSpace* Heap::TargetSpace(HeapObject* object) {
 }
 
 
+void Heap::CopyBlock(Object** dst, Object** src, int byte_size) {
+  ASSERT(IsAligned(byte_size, kPointerSize));
+
+  // Use block copying memcpy if the segment we're copying is
+  // enough to justify the extra call/setup overhead.
+  static const int kBlockCopyLimit = 16 * kPointerSize;
+
+  if (byte_size >= kBlockCopyLimit) {
+    memcpy(dst, src, byte_size);
+  } else {
+    int remaining = byte_size / kPointerSize;
+    do {
+      remaining--;
+      *dst++ = *src++;
+    } while (remaining > 0);
+  }
+}
+
+
 #define GC_GREEDY_CHECK() \
   ASSERT(!FLAG_gc_greedy || v8::internal::Heap::GarbageCollectionGreedyCheck())
 
index 406b4cc..92958bd 100644 (file)
@@ -726,25 +726,14 @@ void Heap::RecordCopiedObject(HeapObject* obj) {
 #endif  // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
 
 
+
 HeapObject* Heap::MigrateObject(HeapObject* source,
                                 HeapObject* target,
                                 int size) {
-  void** src = reinterpret_cast<void**>(source->address());
-  void** dst = reinterpret_cast<void**>(target->address());
-
-  // Use block copying memcpy if the object we're migrating is big
-  // enough to justify the extra call/setup overhead.
-  static const int kBlockCopyLimit = 16 * kPointerSize;
-
-  if (size >= kBlockCopyLimit) {
-    memcpy(dst, src, size);
-  } else {
-    int remaining = size / kPointerSize;
-    do {
-      remaining--;
-      *dst++ = *src++;
-    } while (remaining > 0);
-  }
+  // Copy the content of source to target.
+  CopyBlock(reinterpret_cast<Object**>(target->address()),
+            reinterpret_cast<Object**>(source->address()),
+            size);
 
   // Set the forwarding address.
   source->set_map_word(MapWord::FromForwardingAddress(target));
@@ -1589,8 +1578,9 @@ Object* Heap::CopyCode(Code* code) {
   // Copy code object.
   Address old_addr = code->address();
   Address new_addr = reinterpret_cast<HeapObject*>(result)->address();
-  memcpy(new_addr, old_addr, obj_size);
-
+  CopyBlock(reinterpret_cast<Object**>(new_addr),
+            reinterpret_cast<Object**>(old_addr),
+            obj_size);
   // Relocate the copy.
   Code* new_code = Code::cast(result);
   new_code->Relocate(new_addr - old_addr);
@@ -1657,7 +1647,7 @@ Object* Heap::AllocateArgumentsObject(Object* callee, int length) {
 
   JSObject* boilerplate =
       Top::context()->global_context()->arguments_boilerplate();
-  Object* result = boilerplate->Copy();
+  Object* result = CopyJSObject(boilerplate);
   if (result->IsFailure()) return result;
 
   Object* obj = JSObject::cast(result)->properties();
@@ -1764,6 +1754,42 @@ Object* Heap::AllocateJSObject(JSFunction* constructor,
 }
 
 
+Object* Heap::CopyJSObject(JSObject* source) {
+  // Never used to copy functions.  If functions need to be copied we
+  // have to be careful to clear the literals array.
+  ASSERT(!source->IsJSFunction());
+
+  // Make the clone.
+  Map* map = source->map();
+  int object_size = map->instance_size();
+  Object* clone = new_space_.AllocateRaw(object_size);
+  if (clone->IsFailure()) return clone;
+  ASSERT(Heap::InNewSpace(clone));
+
+  // Copy the content.
+  CopyBlock(reinterpret_cast<Object**>(HeapObject::cast(clone)->address()),
+            reinterpret_cast<Object**>(source->address()),
+            object_size);
+
+  FixedArray* elements = FixedArray::cast(source->elements());
+  FixedArray* properties = FixedArray::cast(source->properties());
+  // Update elements if necessary.
+  if (elements->length()> 0) {
+    Object* elem = Heap::CopyFixedArray(elements);
+    if (elem->IsFailure()) return elem;
+    JSObject::cast(clone)->set_elements(FixedArray::cast(elem));
+  }
+  // Update properties if necessary.
+  if (properties->length() > 0) {
+    Object* prop = Heap::CopyFixedArray(properties);
+    if (prop->IsFailure()) return prop;
+    JSObject::cast(clone)->set_properties(FixedArray::cast(prop));
+  }
+  // Return the new clone.
+  return clone;
+}
+
+
 Object* Heap::ReinitializeJSGlobalProxy(JSFunction* constructor,
                                         JSGlobalProxy* object) {
   // Allocate initial map if absent.
@@ -2064,14 +2090,20 @@ Object* Heap::AllocateRawFixedArray(int length) {
 
 Object* Heap::CopyFixedArray(FixedArray* src) {
   int len = src->length();
-  Object* obj = Heap::AllocateRawFixedArray(len);
+  Object* obj = AllocateRawFixedArray(len);
   if (obj->IsFailure()) return obj;
+  if (Heap::InNewSpace(obj)) {
+    HeapObject* dst = HeapObject::cast(obj);
+    CopyBlock(reinterpret_cast<Object**>(dst->address()),
+              reinterpret_cast<Object**>(src->address()),
+              FixedArray::SizeFor(len));
+    return obj;
+  }
   HeapObject::cast(obj)->set_map(src->map());
   FixedArray* result = FixedArray::cast(obj);
   result->set_length(len);
-  FixedArray::WriteBarrierMode mode = result->GetWriteBarrierMode();
   // Copy the content
-  for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
+  for (int i = 0; i < len; i++) result->set(i, src->get(i));
   return result;
 }
 
index 7f6eab8..802d9c6 100644 (file)
@@ -274,6 +274,11 @@ class Heap : public AllStatic {
   static Object* AllocateJSObject(JSFunction* constructor,
                                   PretenureFlag pretenure = NOT_TENURED);
 
+  // Returns a deep copy of the JavaScript object.
+  // Properties and elements are copied too.
+  // Returns failure if allocation failed.
+  static Object* CopyJSObject(JSObject* source);
+
   // Allocates the function prototype.
   // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
   // failed.
@@ -885,6 +890,9 @@ class Heap : public AllStatic {
   // Slow part of scavenge object.
   static void ScavengeObjectSlow(HeapObject** p, HeapObject* object);
 
+  // Copy memory from src to dst.
+  inline static void CopyBlock(Object** dst, Object** src, int byte_size);
+
   static const int kInitialSymbolTableSize = 2048;
   static const int kInitialEvalCacheSize = 64;
 
index b6a0e0b..3f7dc5f 100644 (file)
@@ -595,6 +595,17 @@ int Failure::value() const {
 }
 
 
+Failure* Failure::RetryAfterGC(int requested_bytes) {
+  int requested = requested_bytes >> kObjectAlignmentBits;
+  int value = (requested << kSpaceTagSize) | NEW_SPACE;
+  ASSERT(value >> kSpaceTagSize == requested);
+  ASSERT(Smi::IsValid(value));
+  ASSERT(value == ((value << kFailureTypeTagSize) >> kFailureTypeTagSize));
+  ASSERT(Smi::IsValid(value << kFailureTypeTagSize));
+  return Construct(RETRY_AFTER_GC, value);
+}
+
+
 Failure* Failure::Construct(Type type, int value) {
   int info = (value << kFailureTypeTagSize) | type;
   ASSERT(Smi::IsValid(info));  // Same validation check as in Smi
@@ -791,21 +802,6 @@ void HeapObject::IteratePointer(ObjectVisitor* v, int offset) {
 }
 
 
-void HeapObject::CopyBody(JSObject* from) {
-  ASSERT(map() == from->map());
-  ASSERT(Size() == from->Size());
-  int object_size = Size();
-  for (int offset = kHeaderSize;
-       offset < object_size;
-       offset += kPointerSize) {
-    Object* value = READ_FIELD(from, offset);
-    // Note: WRITE_FIELD does not update the write barrier.
-    WRITE_FIELD(this, offset, value);
-    WRITE_BARRIER(this, offset);
-  }
-}
-
-
 bool HeapObject::IsMarked() {
   return map_word().IsMarked();
 }
@@ -963,15 +959,17 @@ inline Object* JSObject::FastPropertyAtPut(int index, Object* value) {
 
 
 void JSObject::InitializeBody(int object_size) {
+  Object* value = Heap::undefined_value();
   for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) {
-    WRITE_FIELD(this, offset, Heap::undefined_value());
+    WRITE_FIELD(this, offset, value);
   }
 }
 
 
 void Struct::InitializeBody(int object_size) {
+  Object* value = Heap::undefined_value();
   for (int offset = kHeaderSize; offset < object_size; offset += kPointerSize) {
-    WRITE_FIELD(this, offset, Heap::undefined_value());
+    WRITE_FIELD(this, offset, value);
   }
 }
 
index 72a5e2e..c8147e4 100644 (file)
@@ -910,33 +910,6 @@ void JSObject::JSObjectIterateBody(int object_size, ObjectVisitor* v) {
 }
 
 
-Object* JSObject::Copy(PretenureFlag pretenure) {
-  // Never used to copy functions.  If functions need to be copied we
-  // have to be careful to clear the literals array.
-  ASSERT(!IsJSFunction());
-
-  // Copy the elements and properties.
-  Object* elem = FixedArray::cast(elements())->Copy();
-  if (elem->IsFailure()) return elem;
-  Object* prop = properties()->Copy();
-  if (prop->IsFailure()) return prop;
-
-  // Make the clone.
-  Object* clone = (pretenure == NOT_TENURED) ?
-      Heap::Allocate(map(), NEW_SPACE) :
-      Heap::Allocate(map(), OLD_POINTER_SPACE);
-  if (clone->IsFailure()) return clone;
-  JSObject::cast(clone)->CopyBody(this);
-
-  // Set the new elements and properties.
-  JSObject::cast(clone)->set_elements(FixedArray::cast(elem));
-  JSObject::cast(clone)->set_properties(FixedArray::cast(prop));
-
-  // Return the new clone.
-  return clone;
-}
-
-
 Object* JSObject::AddFastPropertyUsingMap(Map* new_map,
                                           String* name,
                                           Object* value) {
index b59dfc0..0fc49e4 100644 (file)
@@ -812,6 +812,7 @@ class Failure: public Object {
   inline bool IsOutOfMemoryException() const;
 
   static Failure* RetryAfterGC(int requested_bytes, AllocationSpace space);
+  static inline Failure* RetryAfterGC(int requested_bytes);  // NEW_SPACE
   static inline Failure* Exception();
   static inline Failure* InternalError();
   static inline Failure* OutOfMemoryException();
@@ -996,10 +997,6 @@ class HeapObject: public Object {
   // of this struct.
   void IterateStructBody(int object_size, ObjectVisitor* v);
 
-  // Copy the body from the 'from' object to this.
-  // Please note the two object must have the same map prior to the call.
-  inline void CopyBody(JSObject* from);
-
   // Returns the heap object's size in bytes
   inline int Size();
 
@@ -1253,11 +1250,6 @@ class JSObject: public HeapObject {
   inline Object* GetInternalField(int index);
   inline void SetInternalField(int index, Object* value);
 
-  // Returns a deep copy of the JavaScript object.
-  // Properties and elements are copied too.
-  // Returns failure if allocation failed.
-  Object* Copy(PretenureFlag pretenure = NOT_TENURED);
-
   // Lookup a property.  If found, the result is valid and has
   // detailed information.
   void LocalLookup(String* name, LookupResult* result);
index 0d5ddd9..fd2480c 100644 (file)
@@ -94,7 +94,7 @@ static Object* IllegalOperation() {
 
 static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
   CONVERT_CHECKED(JSObject, boilerplate, args[0]);
-  return boilerplate->Copy();
+  return Heap::CopyJSObject(boilerplate);
 }
 
 
index 5f2a42f..7a81db3 100644 (file)
@@ -300,9 +300,7 @@ int LargeObjectSpace::ExtraRSetBytesFor(int object_size) {
 Object* NewSpace::AllocateRawInternal(int size_in_bytes,
                                       AllocationInfo* alloc_info) {
   Address new_top = alloc_info->top + size_in_bytes;
-  if (new_top > alloc_info->limit) {
-    return Failure::RetryAfterGC(size_in_bytes, identity());
-  }
+  if (new_top > alloc_info->limit) return Failure::RetryAfterGC(size_in_bytes);
 
   Object* obj = HeapObject::FromAddress(alloc_info->top);
   alloc_info->top = new_top;
index 9bb9f98..0d6bb3b 100644 (file)
@@ -664,7 +664,7 @@ TEST(JSObjectCopy) {
   obj->SetElement(1, second);
 
   // Make the clone.
-  JSObject* clone = JSObject::cast(obj->Copy());
+  JSObject* clone = JSObject::cast(Heap::CopyJSObject(obj));
   CHECK(clone != obj);
 
   CHECK_EQ(obj->GetElement(0), clone->GetElement(0));