Revision: 11528
Author: [email protected]
Date: Wed May 9 00:29:18 2012
Log: Implement explicit back pointers in transition tree.
This makes back pointers in the map transition tree explicit by having
accurate back pointers throughout the lifetime of maps instead of
establishing and destroying back pointers before and after each marking
phase. This is a prerequisite for being able to clear map transitions
during incremental marking.
[email protected]
BUG=v8:1465
Review URL: https://chromiumcodereview.appspot.com/10381053
http://code.google.com/p/v8/source/detail?r=11528
Modified:
/branches/bleeding_edge/src/heap.cc
/branches/bleeding_edge/src/mark-compact.cc
/branches/bleeding_edge/src/mark-compact.h
/branches/bleeding_edge/src/objects-debug.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/profile-generator.cc
=======================================
--- /branches/bleeding_edge/src/heap.cc Fri May 4 02:36:46 2012
+++ /branches/bleeding_edge/src/heap.cc Wed May 9 00:29:18 2012
@@ -2020,7 +2020,7 @@
map->set_pre_allocated_property_fields(0);
map->init_instance_descriptors();
map->set_code_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
- map->set_prototype_transitions(empty_fixed_array(), SKIP_WRITE_BARRIER);
+ map->init_prototype_transitions(undefined_value());
map->set_unused_property_fields(0);
map->set_bit_field(0);
map->set_bit_field2(1 << Map::kIsExtensible);
@@ -2159,15 +2159,15 @@
// Fix the instance_descriptors for the existing maps.
meta_map()->init_instance_descriptors();
meta_map()->set_code_cache(empty_fixed_array());
- meta_map()->set_prototype_transitions(empty_fixed_array());
+ meta_map()->init_prototype_transitions(undefined_value());
fixed_array_map()->init_instance_descriptors();
fixed_array_map()->set_code_cache(empty_fixed_array());
- fixed_array_map()->set_prototype_transitions(empty_fixed_array());
+ fixed_array_map()->init_prototype_transitions(undefined_value());
oddball_map()->init_instance_descriptors();
oddball_map()->set_code_cache(empty_fixed_array());
- oddball_map()->set_prototype_transitions(empty_fixed_array());
+ oddball_map()->init_prototype_transitions(undefined_value());
// Fix prototype object for existing maps.
meta_map()->set_prototype(null_value());
=======================================
--- /branches/bleeding_edge/src/mark-compact.cc Fri May 4 02:36:46 2012
+++ /branches/bleeding_edge/src/mark-compact.cc Wed May 9 00:29:18 2012
@@ -680,7 +680,6 @@
ASSERT(!FLAG_never_compact || !FLAG_always_compact);
- if (collect_maps_) CreateBackPointers();
#ifdef ENABLE_GDB_JIT_INTERFACE
if (FLAG_gdbjit) {
// If GDBJIT interface is active disable compaction.
@@ -1816,13 +1815,19 @@
void MarkCompactCollector::MarkMapContents(Map* map) {
// Mark prototype transitions array but don't push it into marking stack.
// This will make references from it weak. We will clean dead prototype
- // transitions in ClearNonLiveTransitions.
- FixedArray* prototype_transitions = map->prototype_transitions();
- MarkBit mark = Marking::MarkBitFrom(prototype_transitions);
- if (!mark.Get()) {
- mark.Set();
- MemoryChunk::IncrementLiveBytesFromGC(prototype_transitions->address(),
- prototype_transitions->Size());
+ // transitions in ClearNonLiveTransitions. But make sure that back
pointers
+ // stored inside prototype transitions arrays are marked.
+ Object* raw_proto_transitions = map->unchecked_prototype_transitions();
+ if (raw_proto_transitions->IsFixedArray()) {
+ FixedArray* prototype_transitions =
FixedArray::cast(raw_proto_transitions);
+ MarkBit mark = Marking::MarkBitFrom(prototype_transitions);
+ if (!mark.Get()) {
+ mark.Set();
+
MemoryChunk::IncrementLiveBytesFromGC(prototype_transitions->address(),
+ prototype_transitions->Size());
+ MarkObjectAndPush(HeapObject::cast(
+
prototype_transitions->get(Map::kProtoTransitionBackPointerOffset)));
+ }
}
Object** raw_descriptor_array_slot =
@@ -1919,23 +1924,6 @@
// but the contents array is already marked.
marking_deque_.PushBlack(descriptors);
}
-
-
-void MarkCompactCollector::CreateBackPointers() {
- HeapObjectIterator iterator(heap()->map_space());
- for (HeapObject* next_object = iterator.Next();
- next_object != NULL; next_object = iterator.Next()) {
- if (next_object->IsMap()) { // Could also be FreeSpace object on free
list.
- Map* map = Map::cast(next_object);
- STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
- if (map->instance_type() >= FIRST_JS_RECEIVER_TYPE) {
- map->CreateBackPointers();
- } else {
- ASSERT(map->instance_descriptors() ==
heap()->empty_descriptor_array());
- }
- }
- }
-}
// Fill the marking stack with overflowed objects returned by the given
@@ -2461,15 +2449,8 @@
void MarkCompactCollector::ClearNonLiveTransitions() {
HeapObjectIterator map_iterator(heap()->map_space());
// Iterate over the map space, setting map transitions that go from
- // a marked map to an unmarked map to null transitions. At the same
time,
- // set all the prototype fields of maps back to their original value,
- // dropping the back pointers temporarily stored in the prototype field.
- // Setting the prototype field requires following the linked list of
- // back pointers, reversing them all at once. This allows us to find
- // those maps with map transitions that need to be nulled, and only
- // scan the descriptor arrays of those maps, not all maps.
- // All of these actions are carried out only on maps of JSObjects
- // and related subtypes.
+ // a marked map to an unmarked map to null transitions. This action
+ // is carried out only on maps of JSObjects and related subtypes.
for (HeapObject* obj = map_iterator.Next();
obj != NULL; obj = map_iterator.Next()) {
Map* map = reinterpret_cast<Map*>(obj);
@@ -2545,36 +2526,16 @@
void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map,
MarkBit map_mark) {
- // Follow the chain of back pointers to find the prototype.
- Object* real_prototype = map;
- while (real_prototype->IsMap()) {
- real_prototype = Map::cast(real_prototype)->prototype();
- ASSERT(real_prototype->IsHeapObject());
- }
-
- // Follow back pointers, setting them to prototype, clearing map
transitions
- // when necessary.
- Map* current = map;
+ Object* potential_parent = map->GetBackPointer();
+ if (!potential_parent->IsMap()) return;
+ Map* parent = Map::cast(potential_parent);
+
+ // Follow back pointer, check whether we are dealing with a map
transition
+ // from a live map to a dead path and in case clear transitions of
parent.
bool current_is_alive = map_mark.Get();
- bool on_dead_path = !current_is_alive;
- while (current->IsMap()) {
- Object* next = current->prototype();
- // There should never be a dead map above a live map.
- ASSERT(on_dead_path || current_is_alive);
-
- // A live map above a dead map indicates a dead transition. This test
will
- // always be false on the first iteration.
- if (on_dead_path && current_is_alive) {
- on_dead_path = false;
- current->ClearNonLiveTransitions(heap(), real_prototype);
- }
-
- Object** slot = HeapObject::RawField(current, Map::kPrototypeOffset);
- *slot = real_prototype;
- if (current_is_alive) RecordSlot(slot, slot, real_prototype);
-
- current = reinterpret_cast<Map*>(next);
- current_is_alive = Marking::MarkBitFrom(current).Get();
+ bool parent_is_alive = Marking::MarkBitFrom(parent).Get();
+ if (!current_is_alive && parent_is_alive) {
+ parent->ClearNonLiveTransitions(heap());
}
}
=======================================
--- /branches/bleeding_edge/src/mark-compact.h Tue Apr 17 03:37:41 2012
+++ /branches/bleeding_edge/src/mark-compact.h Wed May 9 00:29:18 2012
@@ -642,13 +642,6 @@
void ProcessNewlyMarkedObject(HeapObject* obj);
- // Creates back pointers for all map transitions, stores them in
- // the prototype field. The original prototype pointers are restored
- // in ClearNonLiveTransitions(). All JSObject maps
- // connected by map transitions have the same prototype object, which
- // is why we can use this field temporarily for back pointers.
- void CreateBackPointers();
-
// Mark a Map and its DescriptorArray together, skipping transitions.
void MarkMapContents(Map* map);
void MarkAccessorPairSlot(HeapObject* accessors, int offset);
=======================================
--- /branches/bleeding_edge/src/objects-debug.cc Mon Apr 16 07:43:27 2012
+++ /branches/bleeding_edge/src/objects-debug.cc Wed May 9 00:29:18 2012
@@ -303,6 +303,8 @@
instance_size() < HEAP->Capacity()));
VerifyHeapPointer(prototype());
VerifyHeapPointer(instance_descriptors());
+ SLOW_ASSERT(instance_descriptors()->IsSortedNoDuplicates());
+ SLOW_ASSERT(instance_descriptors()->IsConsistentWithBackPointers(this));
}
@@ -892,6 +894,61 @@
}
return true;
}
+
+
+static bool CheckOneBackPointer(Map* current_map, Object* target) {
+ return !target->IsMap() || Map::cast(target)->GetBackPointer() ==
current_map;
+}
+
+
+bool DescriptorArray::IsConsistentWithBackPointers(Map* current_map) {
+ for (int i = 0; i < number_of_descriptors(); ++i) {
+ switch (GetType(i)) {
+ case MAP_TRANSITION:
+ case CONSTANT_TRANSITION:
+ if (!CheckOneBackPointer(current_map, GetValue(i))) {
+ return false;
+ }
+ break;
+ case ELEMENTS_TRANSITION: {
+ Object* object = GetValue(i);
+ if (!CheckOneBackPointer(current_map, object)) {
+ return false;
+ }
+ if (object->IsFixedArray()) {
+ FixedArray* array = FixedArray::cast(object);
+ for (int i = 0; i < array->length(); ++i) {
+ if (!CheckOneBackPointer(current_map, array->get(i))) {
+ return false;
+ }
+ }
+ }
+ break;
+ }
+ case CALLBACKS: {
+ Object* object = GetValue(i);
+ if (object->IsAccessorPair()) {
+ AccessorPair* accessors = AccessorPair::cast(object);
+ if (!CheckOneBackPointer(current_map, accessors->getter())) {
+ return false;
+ }
+ if (!CheckOneBackPointer(current_map, accessors->setter())) {
+ return false;
+ }
+ }
+ break;
+ }
+ case NORMAL:
+ case FIELD:
+ case CONSTANT_FUNCTION:
+ case HANDLER:
+ case INTERCEPTOR:
+ case NULL_DESCRIPTOR:
+ break;
+ }
+ }
+ return true;
+}
void JSFunctionResultCache::JSFunctionResultCacheVerify() {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Tue May 8 05:30:36 2012
+++ /branches/bleeding_edge/src/objects-inl.h Wed May 9 00:29:18 2012
@@ -3407,14 +3407,66 @@
}
-FixedArray* Map::unchecked_prototype_transitions() {
- return reinterpret_cast<FixedArray*>(
- READ_FIELD(this, kPrototypeTransitionsOffset));
+Object* Map::GetBackPointer() {
+ Object* object = READ_FIELD(this,
kPrototypeTransitionsOrBackPointerOffset);
+ if (object->IsFixedArray()) {
+ return
FixedArray::cast(object)->get(kProtoTransitionBackPointerOffset);
+ } else {
+ return object;
+ }
+}
+
+
+void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
+ Heap* heap = GetHeap();
+ ASSERT(instance_type() >= FIRST_JS_RECEIVER_TYPE);
+ ASSERT((value->IsUndefined() && GetBackPointer()->IsMap()) ||
+ (value->IsMap() && GetBackPointer()->IsUndefined()));
+ Object* object = READ_FIELD(this,
kPrototypeTransitionsOrBackPointerOffset);
+ if (object->IsFixedArray()) {
+ FixedArray::cast(object)->set(
+ kProtoTransitionBackPointerOffset, value, mode);
+ } else {
+ WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, value);
+ CONDITIONAL_WRITE_BARRIER(
+ heap, this, kPrototypeTransitionsOrBackPointerOffset, value, mode);
+ }
+}
+
+
+FixedArray* Map::prototype_transitions() {
+ Object* object = READ_FIELD(this,
kPrototypeTransitionsOrBackPointerOffset);
+ if (object->IsFixedArray()) {
+ return FixedArray::cast(object);
+ } else {
+ return GetHeap()->empty_fixed_array();
+ }
+}
+
+
+void Map::set_prototype_transitions(FixedArray* value, WriteBarrierMode
mode) {
+ Heap* heap = GetHeap();
+ ASSERT(value != heap->empty_fixed_array());
+ value->set(kProtoTransitionBackPointerOffset, GetBackPointer());
+ WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, value);
+ CONDITIONAL_WRITE_BARRIER(
+ heap, this, kPrototypeTransitionsOrBackPointerOffset, value, mode);
+}
+
+
+void Map::init_prototype_transitions(Object* undefined) {
+ ASSERT(undefined->IsUndefined());
+ WRITE_FIELD(this, kPrototypeTransitionsOrBackPointerOffset, undefined);
+}
+
+
+HeapObject* Map::unchecked_prototype_transitions() {
+ Object* object = READ_FIELD(this,
kPrototypeTransitionsOrBackPointerOffset);
+ return reinterpret_cast<HeapObject*>(object);
}
ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)
-ACCESSORS(Map, prototype_transitions, FixedArray,
kPrototypeTransitionsOffset)
ACCESSORS(Map, constructor, Object, kConstructorOffset)
ACCESSORS(JSFunction, shared, SharedFunctionInfo,
kSharedFunctionInfoOffset)
=======================================
--- /branches/bleeding_edge/src/objects.cc Fri May 4 02:16:38 2012
+++ /branches/bleeding_edge/src/objects.cc Wed May 9 00:29:18 2012
@@ -1604,6 +1604,7 @@
// We have now allocated all the necessary objects.
// All the changes can be applied at once, so they are atomic.
map()->set_instance_descriptors(old_descriptors);
+ new_map->SetBackPointer(map());
new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
set_map(new_map);
return FastPropertyAtPut(index, value);
@@ -1664,6 +1665,7 @@
}
}
old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+ Map::cast(new_map)->SetBackPointer(old_map);
return function;
}
@@ -1824,6 +1826,7 @@
}
}
old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+ map()->SetBackPointer(old_map);
return result;
}
@@ -2408,6 +2411,7 @@
return maybe_new_descriptors;
}
set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+ transitioned_map->SetBackPointer(this);
return this;
}
@@ -4653,6 +4657,7 @@
// step 6: everything went well so far, so we make our changes visible
obj->set_map(map2);
map1->set_instance_descriptors(descriptors1);
+ map2->SetBackPointer(map1);
return obj;
}
@@ -4705,6 +4710,7 @@
// step 4: everything went well so far, so we make our changes visible
obj->set_map(map3);
accessors2->set(component, map3);
+ map3->SetBackPointer(map2);
return obj;
}
@@ -5137,7 +5143,7 @@
// underlying array while it is running.
class IntrusivePrototypeTransitionIterator {
public:
- explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
+ explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans)
: proto_trans_(proto_trans) { }
void Start() {
@@ -5162,7 +5168,7 @@
private:
bool HasTransitions() {
- return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
+ return proto_trans_->map()->IsSmi() || proto_trans_->IsFixedArray();
}
Object** Header() {
@@ -5170,12 +5176,16 @@
}
int NumberOfTransitions() {
- Object* num =
proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
+ ASSERT(HasTransitions());
+ FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
+ Object* num =
proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
return Smi::cast(num)->value();
}
Map* GetTransition(int transitionNumber) {
- return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
+ ASSERT(HasTransitions());
+ FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
+ return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
}
int IndexFor(int transitionNumber) {
@@ -5184,7 +5194,7 @@
transitionNumber * Map::kProtoTransitionElementsPerEntry;
}
- FixedArray* proto_trans_;
+ HeapObject* proto_trans_;
};
@@ -7346,85 +7356,23 @@
}
-void Map::CreateOneBackPointer(Object* transition_target) {
- if (!transition_target->IsMap()) return;
- Map* target = Map::cast(transition_target);
-#ifdef DEBUG
- // Verify target.
- Object* source_prototype = prototype();
- Object* target_prototype = target->prototype();
- ASSERT(source_prototype->IsJSReceiver() ||
- source_prototype->IsMap() ||
- source_prototype->IsNull());
- ASSERT(target_prototype->IsJSReceiver() ||
- target_prototype->IsNull());
- ASSERT(source_prototype->IsMap() ||
- source_prototype == target_prototype);
-#endif
- // Point target back to source. set_prototype() will not let us set
- // the prototype to a map, as we do here.
- *RawField(target, kPrototypeOffset) = this;
-}
-
-
-void Map::CreateBackPointers() {
- DescriptorArray* descriptors = instance_descriptors();
- for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
- switch (descriptors->GetType(i)) {
- case MAP_TRANSITION:
- case CONSTANT_TRANSITION:
- CreateOneBackPointer(descriptors->GetValue(i));
- break;
- case ELEMENTS_TRANSITION: {
- Object* object = descriptors->GetValue(i);
- if (object->IsMap()) {
- CreateOneBackPointer(object);
- } else {
- FixedArray* array = FixedArray::cast(object);
- for (int i = 0; i < array->length(); ++i) {
- CreateOneBackPointer(array->get(i));
- }
- }
- break;
- }
- case CALLBACKS: {
- Object* object = descriptors->GetValue(i);
- if (object->IsAccessorPair()) {
- AccessorPair* accessors = AccessorPair::cast(object);
- CreateOneBackPointer(accessors->getter());
- CreateOneBackPointer(accessors->setter());
- }
- break;
- }
- case NORMAL:
- case FIELD:
- case CONSTANT_FUNCTION:
- case HANDLER:
- case INTERCEPTOR:
- case NULL_DESCRIPTOR:
- break;
- }
- }
-}
-
-
-bool Map::RestoreOneBackPointer(Object* object,
- Object* real_prototype,
- bool* keep_entry) {
- if (!object->IsMap()) return false;
- Map* map = Map::cast(object);
+// Clear a possible back pointer in case the transition leads to a dead
map.
+// Return true in case a back pointer has been cleared and false otherwise.
+// Set *keep_entry to true when a live map transition has been found.
+static bool ClearBackPointer(Heap* heap, Object* target, bool* keep_entry)
{
+ if (!target->IsMap()) return false;
+ Map* map = Map::cast(target);
if (Marking::MarkBitFrom(map).Get()) {
*keep_entry = true;
return false;
- }
- ASSERT(map->prototype() == this || map->prototype() == real_prototype);
- // Getter prototype() is read-only, set_prototype() has side effects.
- *RawField(map, Map::kPrototypeOffset) = real_prototype;
- return true;
+ } else {
+ map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
+ return true;
+ }
}
-void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
+void Map::ClearNonLiveTransitions(Heap* heap) {
DescriptorArray* d = DescriptorArray::cast(
*RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
if (d->IsEmpty()) return;
@@ -7437,24 +7385,22 @@
// If the pair (value, details) is a map transition, check if the
target is
// live. If not, null the descriptor. Also drop the back pointer for
that
// map transition, so that this map is not reached again by following
a back
- // pointer from a non-live object.
+ // pointer from that non-live map.
bool keep_entry = false;
PropertyDetails details(Smi::cast(contents->get(i + 1)));
switch (details.type()) {
case MAP_TRANSITION:
case CONSTANT_TRANSITION:
- RestoreOneBackPointer(contents->get(i), real_prototype,
&keep_entry);
+ ClearBackPointer(heap, contents->get(i), &keep_entry);
break;
case ELEMENTS_TRANSITION: {
Object* object = contents->get(i);
if (object->IsMap()) {
- RestoreOneBackPointer(object, real_prototype, &keep_entry);
+ ClearBackPointer(heap, object, &keep_entry);
} else {
FixedArray* array = FixedArray::cast(object);
for (int j = 0; j < array->length(); ++j) {
- if (RestoreOneBackPointer(array->get(j),
- real_prototype,
- &keep_entry)) {
+ if (ClearBackPointer(heap, array->get(j), &keep_entry)) {
array->set_undefined(j);
}
}
@@ -7465,14 +7411,10 @@
Object* object = contents->get(i);
if (object->IsAccessorPair()) {
AccessorPair* accessors = AccessorPair::cast(object);
- if (RestoreOneBackPointer(accessors->getter(),
- real_prototype,
- &keep_entry)) {
+ if (ClearBackPointer(heap, accessors->getter(), &keep_entry)) {
accessors->set_getter(heap->the_hole_value());
}
- if (RestoreOneBackPointer(accessors->setter(),
- real_prototype,
- &keep_entry)) {
+ if (ClearBackPointer(heap, accessors->setter(), &keep_entry)) {
accessors->set_setter(heap->the_hole_value());
}
} else {
=======================================
--- /branches/bleeding_edge/src/objects.h Tue May 8 05:38:24 2012
+++ /branches/bleeding_edge/src/objects.h Wed May 9 00:29:18 2012
@@ -2609,6 +2609,9 @@
// Is the descriptor array sorted and without duplicates?
bool IsSortedNoDuplicates();
+ // Is the descriptor array consistent with the back pointers in targets?
+ bool IsConsistentWithBackPointers(Map* current_map);
+
// Are two DescriptorArrays equal?
bool IsEqualTo(DescriptorArray* other);
#endif
@@ -4719,19 +4722,30 @@
// [stub cache]: contains stubs compiled for this map.
DECL_ACCESSORS(code_cache, Object)
+ // [back pointer]: points back to the parent map from which a transition
+ // leads to this map. The field overlaps with prototype transitions and
the
+ // back pointer will be moved into the prototype transitions array if
+ // required.
+ inline Object* GetBackPointer();
+ inline void SetBackPointer(Object* value,
+ WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+
// [prototype transitions]: cache of prototype transitions.
// Prototype transition is a transition that happens
// when we change object's prototype to a new one.
// Cache format:
// 0: finger - index of the first free cell in the cache
- // 1 + 2 * i: prototype
- // 2 + 2 * i: target map
+ // 1: back pointer that overlaps with prototype transitions field.
+ // 2 + 2 * i: prototype
+ // 3 + 2 * i: target map
DECL_ACCESSORS(prototype_transitions, FixedArray)
- inline FixedArray* unchecked_prototype_transitions();
-
- static const int kProtoTransitionHeaderSize = 1;
+ inline void init_prototype_transitions(Object* undefined);
+ inline HeapObject* unchecked_prototype_transitions();
+
+ static const int kProtoTransitionHeaderSize = 2;
static const int kProtoTransitionNumberOfEntriesOffset = 0;
+ static const int kProtoTransitionBackPointerOffset = 1;
static const int kProtoTransitionElementsPerEntry = 2;
static const int kProtoTransitionPrototypeOffset = 0;
static const int kProtoTransitionMapOffset = 1;
@@ -4803,25 +4817,10 @@
// Removes a code object from the code cache at the given index.
void RemoveFromCodeCache(String* name, Code* code, int index);
- // For every transition in this map, makes the transition's
- // target's prototype pointer point back to this map.
- // This is undone in MarkCompactCollector::ClearNonLiveTransitions().
- void CreateBackPointers();
-
- void CreateOneBackPointer(Object* transition_target);
-
- // Set all map transitions from this map to dead maps to null.
- // Also, restore the original prototype on the targets of these
- // transitions, so that we do not process this map again while
- // following back pointers.
- void ClearNonLiveTransitions(Heap* heap, Object* real_prototype);
-
- // Restore a possible back pointer in the prototype field of object.
- // Return true in that case and false otherwise. Set *keep_entry to
- // true when a live map transition has been found.
- bool RestoreOneBackPointer(Object* object,
- Object* real_prototype,
- bool* keep_entry);
+ // Set all map transitions from this map to dead maps to null. Also
clear
+ // back pointers in transition targets so that we do not process this map
+ // again while following back pointers.
+ void ClearNonLiveTransitions(Heap* heap);
// Computes a hash value for this map, to be used in HashTables and such.
int Hash();
@@ -4903,16 +4902,17 @@
kConstructorOffset + kPointerSize;
static const int kCodeCacheOffset =
kInstanceDescriptorsOrBitField3Offset + kPointerSize;
- static const int kPrototypeTransitionsOffset =
+ static const int kPrototypeTransitionsOrBackPointerOffset =
kCodeCacheOffset + kPointerSize;
- static const int kPadStart = kPrototypeTransitionsOffset + kPointerSize;
+ static const int kPadStart =
+ kPrototypeTransitionsOrBackPointerOffset + kPointerSize;
static const int kSize = MAP_POINTER_ALIGN(kPadStart);
// Layout of pointer fields. Heap iteration code relies on them
// being continuously allocated.
static const int kPointerFieldsBeginOffset = Map::kPrototypeOffset;
static const int kPointerFieldsEndOffset =
- Map::kPrototypeTransitionsOffset + kPointerSize;
+ kPrototypeTransitionsOrBackPointerOffset + kPointerSize;
// Byte offsets within kInstanceSizesOffset.
static const int kInstanceSizeOffset = kInstanceSizesOffset + 0;
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Wed Apr 25 03:20:38
2012
+++ /branches/bleeding_edge/src/profile-generator.cc Wed May 9 00:29:18
2012
@@ -2146,10 +2146,16 @@
"descriptors", map->instance_descriptors(),
Map::kInstanceDescriptorsOrBitField3Offset);
}
- TagObject(map->prototype_transitions(), "(prototype transitions)");
- SetInternalReference(map, entry,
- "prototype_transitions",
map->prototype_transitions(),
- Map::kPrototypeTransitionsOffset);
+ if (map->unchecked_prototype_transitions()->IsFixedArray()) {
+ TagObject(map->prototype_transitions(), "(prototype transitions)");
+ SetInternalReference(map, entry,
+ "prototype_transitions",
map->prototype_transitions(),
+ Map::kPrototypeTransitionsOrBackPointerOffset);
+ } else {
+ SetInternalReference(map, entry,
+ "back_pointer", map->GetBackPointer(),
+ Map::kPrototypeTransitionsOrBackPointerOffset);
+ }
SetInternalReference(map, entry,
"code_cache", map->code_cache(),
Map::kCodeCacheOffset);
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev