#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,
#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,
}
-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);
}
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.
}
+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())
#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));
// 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);
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();
}
+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.
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;
}
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.
// 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;
}
+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
}
-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();
}
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);
}
}
}
-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) {
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();
// 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();
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);
static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
CONVERT_CHECKED(JSObject, boilerplate, args[0]);
- return boilerplate->Copy();
+ return Heap::CopyJSObject(boilerplate);
}
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;
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));