Commit bf948c83 authored by bak@chromium.org's avatar bak@chromium.org

- Optimized CopyFixedArray and CopyJSObject.

- 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
parent 034b89cc
......@@ -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,
......
......@@ -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,
......
......@@ -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);
}
......
......@@ -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.
......
......@@ -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())
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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);
}
}
......
......@@ -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) {
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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));
......
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