- 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
This commit is contained in:
parent
034b89cc05
commit
bf948c8313
@ -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())
|
||||
|
||||
|
76
src/heap.cc
76
src/heap.cc
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user