Refactoring only: Extracted 2 methods from ClearNonLiveTransitions

This simple refactoring makes it very clear that clearing non-live transitions
actually consists of 2 quite separate things. Things would even be nicer if the
prototype transitions were represented by a separate data structure instead of
reusing FixedArray in an interesting way once again.

As an additional bonus, this CL makes it possible to read each of the methods in
question on a 30" screen without scrolling!

Review URL: https://chromiumcodereview.appspot.com/9169045

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10501 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
svenpanne@chromium.org 2012-01-25 14:22:59 +00:00
parent 4b913965a9
commit 7719981078
2 changed files with 83 additions and 77 deletions

View File

@ -2310,88 +2310,92 @@ void MarkCompactCollector::ClearNonLiveTransitions() {
map->unchecked_constructor()->unchecked_shared()->AttachInitialMap(map); map->unchecked_constructor()->unchecked_shared()->AttachInitialMap(map);
} }
// Clear dead prototype transitions. ClearNonLivePrototypeTransitions(map);
int number_of_transitions = map->NumberOfProtoTransitions(); ClearNonLiveMapTransitions(map, map_mark);
FixedArray* prototype_transitions = map->prototype_transitions(); }
}
int new_number_of_transitions = 0;
const int header = Map::kProtoTransitionHeaderSize; void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
const int proto_offset = int number_of_transitions = map->NumberOfProtoTransitions();
header + Map::kProtoTransitionPrototypeOffset; FixedArray* prototype_transitions = map->prototype_transitions();
const int map_offset = header + Map::kProtoTransitionMapOffset;
const int step = Map::kProtoTransitionElementsPerEntry; int new_number_of_transitions = 0;
for (int i = 0; i < number_of_transitions; i++) { const int header = Map::kProtoTransitionHeaderSize;
Object* prototype = prototype_transitions->get(proto_offset + i * step); const int proto_offset = header + Map::kProtoTransitionPrototypeOffset;
Object* cached_map = prototype_transitions->get(map_offset + i * step); const int map_offset = header + Map::kProtoTransitionMapOffset;
if (IsMarked(prototype) && IsMarked(cached_map)) { const int step = Map::kProtoTransitionElementsPerEntry;
int proto_index = proto_offset + new_number_of_transitions * step; for (int i = 0; i < number_of_transitions; i++) {
int map_index = map_offset + new_number_of_transitions * step; Object* prototype = prototype_transitions->get(proto_offset + i * step);
if (new_number_of_transitions != i) { Object* cached_map = prototype_transitions->get(map_offset + i * step);
prototype_transitions->set_unchecked( if (IsMarked(prototype) && IsMarked(cached_map)) {
heap_, int proto_index = proto_offset + new_number_of_transitions * step;
proto_index, int map_index = map_offset + new_number_of_transitions * step;
prototype, if (new_number_of_transitions != i) {
UPDATE_WRITE_BARRIER); prototype_transitions->set_unchecked(
prototype_transitions->set_unchecked( heap_,
heap_, proto_index,
map_index, prototype,
cached_map, UPDATE_WRITE_BARRIER);
SKIP_WRITE_BARRIER); prototype_transitions->set_unchecked(
} heap_,
Object** slot = map_index,
HeapObject::RawField(prototype_transitions, cached_map,
FixedArray::OffsetOfElementAt(proto_index)); SKIP_WRITE_BARRIER);
RecordSlot(slot, slot, prototype);
new_number_of_transitions++;
} }
Object** slot =
HeapObject::RawField(prototype_transitions,
FixedArray::OffsetOfElementAt(proto_index));
RecordSlot(slot, slot, prototype);
new_number_of_transitions++;
}
}
if (new_number_of_transitions != number_of_transitions) {
map->SetNumberOfProtoTransitions(new_number_of_transitions);
}
// Fill slots that became free with undefined value.
for (int i = new_number_of_transitions * step;
i < number_of_transitions * step;
i++) {
prototype_transitions->set_undefined(heap_, header + i);
}
}
void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map,
MarkBit map_mark) {
// Follow the chain of back pointers to find the prototype.
Map* real_prototype = map;
while (real_prototype->IsMap()) {
real_prototype = reinterpret_cast<Map*>(real_prototype->prototype());
ASSERT(real_prototype->IsHeapObject());
}
// Follow back pointers, setting them to prototype, clearing map transitions
// when necessary.
Map* current = map;
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);
} }
if (new_number_of_transitions != number_of_transitions) { Object** slot = HeapObject::RawField(current, Map::kPrototypeOffset);
map->SetNumberOfProtoTransitions(new_number_of_transitions); *slot = real_prototype;
} if (current_is_alive) RecordSlot(slot, slot, real_prototype);
// Fill slots that became free with undefined value. current = reinterpret_cast<Map*>(next);
for (int i = new_number_of_transitions * step; current_is_alive = Marking::MarkBitFrom(current).Get();
i < number_of_transitions * step;
i++) {
prototype_transitions->set_undefined(heap_, header + i);
}
// Follow the chain of back pointers to find the prototype.
Map* current = map;
while (current->IsMap()) {
current = reinterpret_cast<Map*>(current->prototype());
ASSERT(current->IsHeapObject());
}
Object* real_prototype = current;
// Follow back pointers, setting them to prototype,
// clearing map transitions when necessary.
current = map;
bool on_dead_path = !map_mark.Get();
Object* next;
while (current->IsMap()) {
next = current->prototype();
// There should never be a dead map above a live map.
MarkBit current_mark = Marking::MarkBitFrom(current);
bool is_alive = current_mark.Get();
ASSERT(on_dead_path || 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 && is_alive) {
on_dead_path = false;
current->ClearNonLiveTransitions(heap(), real_prototype);
}
*HeapObject::RawField(current, Map::kPrototypeOffset) =
real_prototype;
if (is_alive) {
Object** slot = HeapObject::RawField(current, Map::kPrototypeOffset);
RecordSlot(slot, slot, real_prototype);
}
current = reinterpret_cast<Map*>(next);
}
} }
} }

View File

@ -696,6 +696,8 @@ class MarkCompactCollector {
// Map transitions from a live map to a dead map must be killed. // Map transitions from a live map to a dead map must be killed.
// We replace them with a null descriptor, with the same key. // We replace them with a null descriptor, with the same key.
void ClearNonLiveTransitions(); void ClearNonLiveTransitions();
void ClearNonLivePrototypeTransitions(Map* map);
void ClearNonLiveMapTransitions(Map* map, MarkBit map_mark);
// Marking detaches initial maps from SharedFunctionInfo objects // Marking detaches initial maps from SharedFunctionInfo objects
// to make this reference weak. We need to reattach initial maps // to make this reference weak. We need to reattach initial maps