Index: src/heap.cc |
diff --git a/src/heap.cc b/src/heap.cc |
index c4d0439e0d0b5dc940dca636b49635d7929757c7..dcc0cc6a9ba4a89389a5686d583f6a35bf18cd5d 100644 |
--- a/src/heap.cc |
+++ b/src/heap.cc |
@@ -37,6 +37,7 @@ |
#include "global-handles.h" |
#include "mark-compact.h" |
#include "natives.h" |
+#include "objects-visiting.h" |
#include "scanner.h" |
#include "scopeinfo.h" |
#include "snapshot.h" |
@@ -1032,6 +1033,17 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable( |
} |
+class NewSpaceScavenger : public StaticNewSpaceVisitor<NewSpaceScavenger> { |
+ public: |
+ static inline void VisitPointer(Object** p) { |
+ Object* object = *p; |
+ if (!Heap::InNewSpace(object)) return; |
+ Heap::ScavengeObject(reinterpret_cast<HeapObject**>(p), |
+ reinterpret_cast<HeapObject*>(object)); |
+ } |
+}; |
+ |
+ |
Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, |
Address new_space_front) { |
do { |
@@ -1042,10 +1054,7 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, |
// queue is empty. |
while (new_space_front < new_space_.top()) { |
HeapObject* object = HeapObject::FromAddress(new_space_front); |
- Map* map = object->map(); |
- int size = object->SizeFromMap(map); |
- object->IterateBody(map->instance_type(), size, scavenge_visitor); |
- new_space_front += size; |
+ new_space_front += NewSpaceScavenger::IterateBody(object->map(), object); |
} |
// Promote and process all the to-be-promoted objects. |
@@ -1072,315 +1081,231 @@ Address Heap::DoScavenge(ObjectVisitor* scavenge_visitor, |
} |
-#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
-static void RecordCopiedObject(HeapObject* obj) { |
- bool should_record = false; |
-#ifdef DEBUG |
- should_record = FLAG_heap_stats; |
-#endif |
-#ifdef ENABLE_LOGGING_AND_PROFILING |
- should_record = should_record || FLAG_log_gc; |
-#endif |
- if (should_record) { |
- if (Heap::new_space()->Contains(obj)) { |
- Heap::new_space()->RecordAllocation(obj); |
- } else { |
- Heap::new_space()->RecordPromotion(obj); |
- } |
- } |
-} |
-#endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
+class ScavengingVisitor : public StaticVisitorBase { |
+ public: |
+ static void Initialize() { |
+ table_.Register(kVisitSeqAsciiString, &EvacuateSeqAsciiString); |
+ table_.Register(kVisitSeqTwoByteString, &EvacuateSeqTwoByteString); |
+ table_.Register(kVisitShortcutCandidate, &EvacuateShortcutCandidate); |
+ table_.Register(kVisitByteArray, &EvacuateByteArray); |
+ table_.Register(kVisitFixedArray, &EvacuateFixedArray); |
+ typedef ObjectEvacuationStrategy<POINTER_OBJECT> PointerObject; |
-// Helper function used by CopyObject to copy a source object to an |
-// allocated target object and update the forwarding pointer in the source |
-// object. Returns the target object. |
-inline static HeapObject* MigrateObject(HeapObject* source, |
- HeapObject* target, |
- int size) { |
- // Copy the content of source to target. |
- Heap::CopyBlock(target->address(), source->address(), size); |
+ table_.Register(kVisitConsString, |
+ &ObjectEvacuationStrategy<POINTER_OBJECT>:: |
+ VisitSpecialized<ConsString::kSize>); |
- // Set the forwarding address. |
- source->set_map_word(MapWord::FromForwardingAddress(target)); |
+ table_.Register(kVisitSharedFunctionInfo, |
+ &ObjectEvacuationStrategy<POINTER_OBJECT>:: |
+ VisitSpecialized<SharedFunctionInfo::kSize>); |
-#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
- // Update NewSpace stats if necessary. |
- RecordCopiedObject(target); |
-#endif |
- HEAP_PROFILE(ObjectMoveEvent(source->address(), target->address())); |
+ table_.RegisterSpecializations<ObjectEvacuationStrategy<DATA_OBJECT>, |
+ kVisitDataObject, |
+ kVisitDataObjectGeneric>(); |
- return target; |
-} |
+ table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, |
+ kVisitJSObject, |
+ kVisitJSObjectGeneric>(); |
+ table_.RegisterSpecializations<ObjectEvacuationStrategy<POINTER_OBJECT>, |
+ kVisitStruct, |
+ kVisitStructGeneric>(); |
+ } |
-enum ObjectContents { DATA_OBJECT, POINTER_OBJECT }; |
-enum SizeRestriction { SMALL, UNKNOWN_SIZE }; |
+ static inline void Scavenge(Map* map, HeapObject** slot, HeapObject* obj) { |
+ table_.GetVisitor(map)(map, slot, obj); |
+ } |
-template<ObjectContents object_contents, SizeRestriction size_restriction> |
-static inline void EvacuateObject(Map* map, |
- HeapObject** slot, |
- HeapObject* object, |
- int object_size) { |
- ASSERT((size_restriction != SMALL) || |
- (object_size <= Page::kMaxHeapObjectSize)); |
- ASSERT(object->Size() == object_size); |
- if (Heap::ShouldBePromoted(object->address(), object_size)) { |
- Object* result; |
+ private: |
+ enum ObjectContents { DATA_OBJECT, POINTER_OBJECT }; |
+ enum SizeRestriction { SMALL, UNKNOWN_SIZE }; |
- if ((size_restriction != SMALL) && |
- (object_size > Page::kMaxHeapObjectSize)) { |
- result = Heap::lo_space()->AllocateRawFixedArray(object_size); |
- } else { |
- if (object_contents == DATA_OBJECT) { |
- result = Heap::old_data_space()->AllocateRaw(object_size); |
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
+ static void RecordCopiedObject(HeapObject* obj) { |
+ bool should_record = false; |
+#ifdef DEBUG |
+ should_record = FLAG_heap_stats; |
+#endif |
+#ifdef ENABLE_LOGGING_AND_PROFILING |
+ should_record = should_record || FLAG_log_gc; |
+#endif |
+ if (should_record) { |
+ if (Heap::new_space()->Contains(obj)) { |
+ Heap::new_space()->RecordAllocation(obj); |
} else { |
- result = Heap::old_pointer_space()->AllocateRaw(object_size); |
+ Heap::new_space()->RecordPromotion(obj); |
} |
} |
- |
- if (!result->IsFailure()) { |
- HeapObject* target = HeapObject::cast(result); |
- *slot = MigrateObject(object, target, object_size); |
- |
- if (object_contents == POINTER_OBJECT) { |
- promotion_queue.insert(target, object_size); |
- } |
- |
- Heap::tracer()->increment_promoted_objects_size(object_size); |
- return; |
- } |
} |
- Object* result = Heap::new_space()->AllocateRaw(object_size); |
- ASSERT(!result->IsFailure()); |
- *slot = MigrateObject(object, HeapObject::cast(result), object_size); |
- return; |
-} |
+#endif // defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
+ // Helper function used by CopyObject to copy a source object to an |
+ // allocated target object and update the forwarding pointer in the source |
+ // object. Returns the target object. |
+ INLINE(static HeapObject* MigrateObject(HeapObject* source, |
+ HeapObject* target, |
+ int size)) { |
+ // Copy the content of source to target. |
+ Heap::CopyBlock(target->address(), source->address(), size); |
-template<int object_size_in_words, ObjectContents object_contents> |
-static inline void EvacuateObjectOfFixedSize(Map* map, |
- HeapObject** slot, |
- HeapObject* object) { |
- const int object_size = object_size_in_words << kPointerSizeLog2; |
- EvacuateObject<object_contents, SMALL>(map, slot, object, object_size); |
-} |
+ // Set the forwarding address. |
+ source->set_map_word(MapWord::FromForwardingAddress(target)); |
+#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) |
+ // Update NewSpace stats if necessary. |
+ RecordCopiedObject(target); |
+#endif |
+ HEAP_PROFILE(ObjectMoveEvent(source->address(), target->address())); |
-template<ObjectContents object_contents> |
-static inline void EvacuateObjectOfFixedSize(Map* map, |
- HeapObject** slot, |
- HeapObject* object) { |
- int object_size = map->instance_size(); |
- EvacuateObject<object_contents, SMALL>(map, slot, object, object_size); |
-} |
+ return target; |
+ } |
-static inline void EvacuateFixedArray(Map* map, |
- HeapObject** slot, |
- HeapObject* object) { |
- int object_size = FixedArray::cast(object)->FixedArraySize(); |
- EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size); |
-} |
+ template<ObjectContents object_contents, SizeRestriction size_restriction> |
+ static inline void EvacuateObject(Map* map, |
+ HeapObject** slot, |
+ HeapObject* object, |
+ int object_size) { |
+ ASSERT((size_restriction != SMALL) || |
+ (object_size <= Page::kMaxHeapObjectSize)); |
+ ASSERT(object->Size() == object_size); |
+ if (Heap::ShouldBePromoted(object->address(), object_size)) { |
+ Object* result; |
-static inline void EvacuateByteArray(Map* map, |
- HeapObject** slot, |
- HeapObject* object) { |
- int object_size = ByteArray::cast(object)->ByteArraySize(); |
- EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size); |
-} |
+ if ((size_restriction != SMALL) && |
+ (object_size > Page::kMaxHeapObjectSize)) { |
+ result = Heap::lo_space()->AllocateRawFixedArray(object_size); |
+ } else { |
+ if (object_contents == DATA_OBJECT) { |
+ result = Heap::old_data_space()->AllocateRaw(object_size); |
+ } else { |
+ result = Heap::old_pointer_space()->AllocateRaw(object_size); |
+ } |
+ } |
+ if (!result->IsFailure()) { |
+ HeapObject* target = HeapObject::cast(result); |
+ *slot = MigrateObject(object, target, object_size); |
-static Scavenger GetScavengerForSize(int object_size, |
- ObjectContents object_contents) { |
- ASSERT(IsAligned(object_size, kPointerSize)); |
- ASSERT(object_size < Page::kMaxHeapObjectSize); |
+ if (object_contents == POINTER_OBJECT) { |
+ promotion_queue.insert(target, object_size); |
+ } |
- switch (object_size >> kPointerSizeLog2) { |
-#define CASE(n) \ |
- case n: \ |
- if (object_contents == DATA_OBJECT) { \ |
- return static_cast<Scavenger>( \ |
- &EvacuateObjectOfFixedSize<n, DATA_OBJECT>); \ |
- } else { \ |
- return static_cast<Scavenger>( \ |
- &EvacuateObjectOfFixedSize<n, POINTER_OBJECT>); \ |
+ Heap::tracer()->increment_promoted_objects_size(object_size); |
+ return; |
} |
+ } |
+ Object* result = Heap::new_space()->AllocateRaw(object_size); |
+ ASSERT(!result->IsFailure()); |
+ *slot = MigrateObject(object, HeapObject::cast(result), object_size); |
+ return; |
+ } |
- CASE(1); |
- CASE(2); |
- CASE(3); |
- CASE(4); |
- CASE(5); |
- CASE(6); |
- CASE(7); |
- CASE(8); |
- CASE(9); |
- CASE(10); |
- CASE(11); |
- CASE(12); |
- CASE(13); |
- CASE(14); |
- CASE(15); |
- CASE(16); |
- default: |
- if (object_contents == DATA_OBJECT) { |
- return static_cast<Scavenger>(&EvacuateObjectOfFixedSize<DATA_OBJECT>); |
- } else { |
- return static_cast<Scavenger>( |
- &EvacuateObjectOfFixedSize<POINTER_OBJECT>); |
- } |
-#undef CASE |
+ static inline void EvacuateFixedArray(Map* map, |
+ HeapObject** slot, |
+ HeapObject* object) { |
+ int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); |
+ EvacuateObject<POINTER_OBJECT, UNKNOWN_SIZE>(map, |
+ slot, |
+ object, |
+ object_size); |
} |
-} |
-static inline void EvacuateSeqAsciiString(Map* map, |
- HeapObject** slot, |
- HeapObject* object) { |
- int object_size = SeqAsciiString::cast(object)-> |
- SeqAsciiStringSize(map->instance_type()); |
- EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size); |
-} |
+ static inline void EvacuateByteArray(Map* map, |
+ HeapObject** slot, |
+ HeapObject* object) { |
+ int object_size = reinterpret_cast<ByteArray*>(object)->ByteArraySize(); |
+ EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size); |
+ } |
-static inline void EvacuateSeqTwoByteString(Map* map, |
+ static inline void EvacuateSeqAsciiString(Map* map, |
HeapObject** slot, |
HeapObject* object) { |
- int object_size = SeqTwoByteString::cast(object)-> |
- SeqTwoByteStringSize(map->instance_type()); |
- EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size); |
-} |
+ int object_size = SeqAsciiString::cast(object)-> |
+ SeqAsciiStringSize(map->instance_type()); |
+ EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size); |
+ } |
-static inline bool IsShortcutCandidate(int type) { |
- return ((type & kShortcutTypeMask) == kShortcutTypeTag); |
-} |
+ static inline void EvacuateSeqTwoByteString(Map* map, |
+ HeapObject** slot, |
+ HeapObject* object) { |
+ int object_size = SeqTwoByteString::cast(object)-> |
+ SeqTwoByteStringSize(map->instance_type()); |
+ EvacuateObject<DATA_OBJECT, UNKNOWN_SIZE>(map, slot, object, object_size); |
+ } |
-static inline void EvacuateShortcutCandidate(Map* map, |
- HeapObject** slot, |
- HeapObject* object) { |
- ASSERT(IsShortcutCandidate(map->instance_type())); |
+ static inline bool IsShortcutCandidate(int type) { |
+ return ((type & kShortcutTypeMask) == kShortcutTypeTag); |
+ } |
- if (ConsString::cast(object)->unchecked_second() == Heap::empty_string()) { |
- HeapObject* first = |
- HeapObject::cast(ConsString::cast(object)->unchecked_first()); |
+ static inline void EvacuateShortcutCandidate(Map* map, |
+ HeapObject** slot, |
+ HeapObject* object) { |
+ ASSERT(IsShortcutCandidate(map->instance_type())); |
- *slot = first; |
+ if (ConsString::cast(object)->unchecked_second() == Heap::empty_string()) { |
+ HeapObject* first = |
+ HeapObject::cast(ConsString::cast(object)->unchecked_first()); |
- if (!Heap::InNewSpace(first)) { |
- object->set_map_word(MapWord::FromForwardingAddress(first)); |
- return; |
- } |
+ *slot = first; |
- MapWord first_word = first->map_word(); |
- if (first_word.IsForwardingAddress()) { |
- HeapObject* target = first_word.ToForwardingAddress(); |
+ if (!Heap::InNewSpace(first)) { |
+ object->set_map_word(MapWord::FromForwardingAddress(first)); |
+ return; |
+ } |
- *slot = target; |
- object->set_map_word(MapWord::FromForwardingAddress(target)); |
+ MapWord first_word = first->map_word(); |
+ if (first_word.IsForwardingAddress()) { |
+ HeapObject* target = first_word.ToForwardingAddress(); |
+ |
+ *slot = target; |
+ object->set_map_word(MapWord::FromForwardingAddress(target)); |
+ return; |
+ } |
+ |
+ Scavenge(first->map(), slot, first); |
+ object->set_map_word(MapWord::FromForwardingAddress(*slot)); |
return; |
} |
- first->map()->Scavenge(slot, first); |
- object->set_map_word(MapWord::FromForwardingAddress(*slot)); |
- return; |
+ int object_size = ConsString::kSize; |
+ EvacuateObject<POINTER_OBJECT, SMALL>(map, slot, object, object_size); |
} |
- int object_size = ConsString::kSize; |
- EvacuateObject<POINTER_OBJECT, SMALL>(map, slot, object, object_size); |
-} |
- |
- |
-Scavenger Heap::GetScavenger(int instance_type, int instance_size) { |
- if (instance_type < FIRST_NONSTRING_TYPE) { |
- switch (instance_type & kStringRepresentationMask) { |
- case kSeqStringTag: |
- if ((instance_type & kStringEncodingMask) == kAsciiStringTag) { |
- return &EvacuateSeqAsciiString; |
- } else { |
- return &EvacuateSeqTwoByteString; |
- } |
- |
- case kConsStringTag: |
- if (IsShortcutCandidate(instance_type)) { |
- return &EvacuateShortcutCandidate; |
- } else { |
- ASSERT(instance_size == ConsString::kSize); |
- return GetScavengerForSize(ConsString::kSize, POINTER_OBJECT); |
- } |
- |
- case kExternalStringTag: |
- ASSERT(instance_size == ExternalString::kSize); |
- return GetScavengerForSize(ExternalString::kSize, DATA_OBJECT); |
+ template<ObjectContents object_contents> |
+ class ObjectEvacuationStrategy { |
+ public: |
+ template<int object_size> |
+ static inline void VisitSpecialized(Map* map, |
+ HeapObject** slot, |
+ HeapObject* object) { |
+ EvacuateObject<object_contents, SMALL>(map, slot, object, object_size); |
} |
- UNREACHABLE(); |
- } |
- |
- switch (instance_type) { |
- case BYTE_ARRAY_TYPE: |
- return reinterpret_cast<Scavenger>(&EvacuateByteArray); |
- case FIXED_ARRAY_TYPE: |
- return reinterpret_cast<Scavenger>(&EvacuateFixedArray); |
- |
- case JS_OBJECT_TYPE: |
- case JS_CONTEXT_EXTENSION_OBJECT_TYPE: |
- case JS_VALUE_TYPE: |
- case JS_ARRAY_TYPE: |
- case JS_REGEXP_TYPE: |
- case JS_FUNCTION_TYPE: |
- case JS_GLOBAL_PROXY_TYPE: |
- case JS_GLOBAL_OBJECT_TYPE: |
- case JS_BUILTINS_OBJECT_TYPE: |
- return GetScavengerForSize(instance_size, POINTER_OBJECT); |
- |
- case ODDBALL_TYPE: |
- return NULL; |
- |
- case PROXY_TYPE: |
- return GetScavengerForSize(Proxy::kSize, DATA_OBJECT); |
+ static inline void Visit(Map* map, |
+ HeapObject** slot, |
+ HeapObject* object) { |
+ int object_size = map->instance_size(); |
+ EvacuateObject<object_contents, SMALL>(map, slot, object, object_size); |
+ } |
+ }; |
- case MAP_TYPE: |
- return NULL; |
+ typedef void (*Callback)(Map* map, HeapObject** slot, HeapObject* object); |
- case CODE_TYPE: |
- return NULL; |
+ static VisitorDispatchTable<Callback> table_; |
+}; |
- case JS_GLOBAL_PROPERTY_CELL_TYPE: |
- return NULL; |
- case HEAP_NUMBER_TYPE: |
- case FILLER_TYPE: |
- case PIXEL_ARRAY_TYPE: |
- case EXTERNAL_BYTE_ARRAY_TYPE: |
- case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE: |
- case EXTERNAL_SHORT_ARRAY_TYPE: |
- case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE: |
- case EXTERNAL_INT_ARRAY_TYPE: |
- case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE: |
- case EXTERNAL_FLOAT_ARRAY_TYPE: |
- return GetScavengerForSize(instance_size, DATA_OBJECT); |
- |
- case SHARED_FUNCTION_INFO_TYPE: |
- return GetScavengerForSize(SharedFunctionInfo::kAlignedSize, |
- POINTER_OBJECT); |
- |
-#define MAKE_STRUCT_CASE(NAME, Name, name) \ |
- case NAME##_TYPE: |
- STRUCT_LIST(MAKE_STRUCT_CASE) |
-#undef MAKE_STRUCT_CASE |
- return GetScavengerForSize(instance_size, POINTER_OBJECT); |
- default: |
- UNREACHABLE(); |
- return NULL; |
- } |
-} |
+VisitorDispatchTable<ScavengingVisitor::Callback> ScavengingVisitor::table_; |
void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { |
@@ -1388,7 +1313,7 @@ void Heap::ScavengeObjectSlow(HeapObject** p, HeapObject* object) { |
MapWord first_word = object->map_word(); |
ASSERT(!first_word.IsForwardingAddress()); |
Map* map = first_word.ToMap(); |
- map->Scavenge(p, object); |
+ ScavengingVisitor::Scavenge(map, p, object); |
} |
@@ -1407,7 +1332,8 @@ Object* Heap::AllocatePartialMap(InstanceType instance_type, |
reinterpret_cast<Map*>(result)->set_instance_type(instance_type); |
reinterpret_cast<Map*>(result)->set_instance_size(instance_size); |
reinterpret_cast<Map*>(result)-> |
- set_scavenger(GetScavenger(instance_type, instance_size)); |
+ set_visitor_id( |
+ StaticVisitorBase::GetVisitorId(instance_type, instance_size)); |
reinterpret_cast<Map*>(result)->set_inobject_properties(0); |
reinterpret_cast<Map*>(result)->set_pre_allocated_property_fields(0); |
reinterpret_cast<Map*>(result)->set_unused_property_fields(0); |
@@ -1424,7 +1350,8 @@ Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) { |
Map* map = reinterpret_cast<Map*>(result); |
map->set_map(meta_map()); |
map->set_instance_type(instance_type); |
- map->set_scavenger(GetScavenger(instance_type, instance_size)); |
+ map->set_visitor_id( |
+ StaticVisitorBase::GetVisitorId(instance_type, instance_size)); |
map->set_prototype(null_value()); |
map->set_constructor(null_value()); |
map->set_instance_size(instance_size); |
@@ -4174,6 +4101,10 @@ bool Heap::Setup(bool create_heap_objects) { |
if (!ConfigureHeapDefault()) return false; |
} |
+ ScavengingVisitor::Initialize(); |
+ NewSpaceScavenger::Initialize(); |
+ MarkCompactCollector::Initialize(); |
+ |
// Setup memory allocator and reserve a chunk of memory for new |
// space. The chunk is double the size of the requested reserved |
// new space size to ensure that we can find a pair of semispaces that |
@@ -4858,6 +4789,7 @@ GCTracer::~GCTracer() { |
PrintF("external=%d ", static_cast<int>(scopes_[Scope::EXTERNAL])); |
PrintF("mark=%d ", static_cast<int>(scopes_[Scope::MC_MARK])); |
PrintF("sweep=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP])); |
+ PrintF("sweepns=%d ", static_cast<int>(scopes_[Scope::MC_SWEEP_NEWSPACE])); |
PrintF("compact=%d ", static_cast<int>(scopes_[Scope::MC_COMPACT])); |
PrintF("flushcode=%d ", static_cast<int>(scopes_[Scope::MC_FLUSH_CODE])); |