Commit 8072cd29 authored by hpayer@chromium.org's avatar hpayer@chromium.org

Don't overwrite transition array map while iterating over the transition tree.

Instread of using the transition array map to store the iteration index, we are using the constructor field of the map. Moreover, I removed the unchecked transition array accessors.

BUG=
R=mstarzinger@chromium.org, verwaest@chromium.org

Review URL: https://codereview.chromium.org/223533002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20503 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0d1c01cb
......@@ -5002,23 +5002,6 @@ void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
}
// Can either be Smi (no transitions), normal transition array, or a transition
// array with the header overwritten as a Smi (thus iterating).
TransitionArray* Map::unchecked_transition_array() {
Object* object = *HeapObject::RawField(this,
Map::kTransitionsOrBackPointerOffset);
TransitionArray* transition_array = static_cast<TransitionArray*>(object);
return transition_array;
}
HeapObject* Map::UncheckedPrototypeTransitions() {
ASSERT(HasTransitionArray());
ASSERT(unchecked_transition_array()->HasPrototypeTransitions());
return unchecked_transition_array()->UncheckedPrototypeTransitions();
}
ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)
ACCESSORS(Map, dependent_code, DependentCode, kDependentCodeOffset)
ACCESSORS(Map, constructor, Object, kConstructorOffset)
......
......@@ -615,12 +615,9 @@ void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(
// array to prevent visiting it later. Skip recording the transition
// array slot, since it will be implicitly recorded when the pointer
// fields of this map are visited.
TransitionArray* transitions = map->unchecked_transition_array();
if (transitions->IsTransitionArray()) {
if (map->HasTransitionArray()) {
TransitionArray* transitions = map->transitions();
MarkTransitionArray(heap, transitions);
} else {
// Already marked by marking map->GetBackPointer() above.
ASSERT(transitions->IsMap() || transitions->IsUndefined());
}
// Since descriptor arrays are potentially shared, ensure that only the
......
......@@ -7232,74 +7232,92 @@ void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
}
// An iterator over all map transitions in an descriptor array, reusing the map
// field of the contens array while it is running.
// An iterator over all map transitions in an descriptor array, reusing the
// constructor field of the map while it is running. Negative values in
// the constructor field indicate an active map transition iteration. The
// original constructor is restored after iterating over all entries.
class IntrusiveMapTransitionIterator {
public:
explicit IntrusiveMapTransitionIterator(TransitionArray* transition_array)
: transition_array_(transition_array) { }
IntrusiveMapTransitionIterator(
Map* map, TransitionArray* transition_array, Object* constructor)
: map_(map),
transition_array_(transition_array),
constructor_(constructor) { }
void Start() {
ASSERT(!IsIterating());
*TransitionArrayHeader() = Smi::FromInt(0);
void StartIfNotStarted() {
ASSERT(!(*IteratorField())->IsSmi() || IsIterating());
if (!(*IteratorField())->IsSmi()) {
ASSERT(*IteratorField() == constructor_);
*IteratorField() = Smi::FromInt(-1);
}
}
bool IsIterating() {
return (*TransitionArrayHeader())->IsSmi();
return (*IteratorField())->IsSmi() &&
Smi::cast(*IteratorField())->value() < 0;
}
Map* Next() {
ASSERT(IsIterating());
int index = Smi::cast(*TransitionArrayHeader())->value();
int value = Smi::cast(*IteratorField())->value();
int index = -value - 1;
int number_of_transitions = transition_array_->number_of_transitions();
while (index < number_of_transitions) {
*TransitionArrayHeader() = Smi::FromInt(index + 1);
*IteratorField() = Smi::FromInt(value - 1);
return transition_array_->GetTarget(index);
}
*TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map();
*IteratorField() = constructor_;
return NULL;
}
private:
Object** TransitionArrayHeader() {
return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset);
Object** IteratorField() {
return HeapObject::RawField(map_, Map::kConstructorOffset);
}
Map* map_;
TransitionArray* transition_array_;
Object* constructor_;
};
// An iterator over all prototype transitions, reusing the map field of the
// underlying array while it is running.
// An iterator over all prototype transitions, reusing the constructor field
// of the map while it is running. Positive values in the constructor field
// indicate an active prototype transition iteration. The original constructor
// is restored after iterating over all entries.
class IntrusivePrototypeTransitionIterator {
public:
explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans)
: proto_trans_(proto_trans) { }
IntrusivePrototypeTransitionIterator(
Map* map, HeapObject* proto_trans, Object* constructor)
: map_(map), proto_trans_(proto_trans), constructor_(constructor) { }
void Start() {
ASSERT(!IsIterating());
*Header() = Smi::FromInt(0);
void StartIfNotStarted() {
if (!(*IteratorField())->IsSmi()) {
ASSERT(*IteratorField() == constructor_);
*IteratorField() = Smi::FromInt(0);
}
}
bool IsIterating() {
return (*Header())->IsSmi();
return (*IteratorField())->IsSmi() &&
Smi::cast(*IteratorField())->value() >= 0;
}
Map* Next() {
ASSERT(IsIterating());
int transitionNumber = Smi::cast(*Header())->value();
int transitionNumber = Smi::cast(*IteratorField())->value();
if (transitionNumber < NumberOfTransitions()) {
*Header() = Smi::FromInt(transitionNumber + 1);
*IteratorField() = Smi::FromInt(transitionNumber + 1);
return GetTransition(transitionNumber);
}
*Header() = proto_trans_->GetHeap()->fixed_array_map();
*IteratorField() = constructor_;
return NULL;
}
private:
Object** Header() {
return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
Object** IteratorField() {
return HeapObject::RawField(map_, Map::kConstructorOffset);
}
int NumberOfTransitions() {
......@@ -7319,29 +7337,33 @@ class IntrusivePrototypeTransitionIterator {
transitionNumber * Map::kProtoTransitionElementsPerEntry;
}
Map* map_;
HeapObject* proto_trans_;
Object* constructor_;
};
// To traverse the transition tree iteratively, we have to store two kinds of
// information in a map: The parent map in the traversal and which children of a
// node have already been visited. To do this without additional memory, we
// temporarily reuse two maps with known values:
// temporarily reuse two fields with known values:
//
// (1) The map of the map temporarily holds the parent, and is restored to the
// meta map afterwards.
//
// (2) The info which children have already been visited depends on which part
// of the map we currently iterate:
// of the map we currently iterate. We use the constructor field of the
// map to store the current index. We can do that because the constructor
// is the same for all involved maps.
//
// (a) If we currently follow normal map transitions, we temporarily store
// the current index in the map of the FixedArray of the desciptor
// array's contents, and restore it to the fixed array map afterwards.
// Note that a single descriptor can have 0, 1, or 2 transitions.
// the current index in the constructor field, and restore it to the
// original constructor afterwards. Note that a single descriptor can
// have 0, 1, or 2 transitions.
//
// (b) If we currently follow prototype transitions, we temporarily store
// the current index in the map of the FixedArray holding the prototype
// transitions, and restore it to the fixed array map afterwards.
// the current index in the constructor field, and restore it to the
// original constructor afterwards.
//
// Note that the child iterator is just a concatenation of two iterators: One
// iterating over map transitions and one iterating over prototype transisitons.
......@@ -7358,38 +7380,29 @@ class TraversableMap : public Map {
return old_parent;
}
// Start iterating over this map's children, possibly destroying a FixedArray
// map (see explanation above).
void ChildIteratorStart() {
if (HasTransitionArray()) {
if (HasPrototypeTransitions()) {
IntrusivePrototypeTransitionIterator(GetPrototypeTransitions()).Start();
}
IntrusiveMapTransitionIterator(transitions()).Start();
}
}
// If we have an unvisited child map, return that one and advance. If we have
// none, return NULL and reset any destroyed FixedArray maps.
TraversableMap* ChildIteratorNext() {
TransitionArray* transition_array = unchecked_transition_array();
if (!transition_array->map()->IsSmi() &&
!transition_array->IsTransitionArray()) {
return NULL;
}
// none, return NULL and restore the overwritten constructor field.
TraversableMap* ChildIteratorNext(Object* constructor) {
if (!HasTransitionArray()) return NULL;
TransitionArray* transition_array = transitions();
if (transition_array->HasPrototypeTransitions()) {
HeapObject* proto_transitions =
transition_array->UncheckedPrototypeTransitions();
IntrusivePrototypeTransitionIterator proto_iterator(proto_transitions);
transition_array->GetPrototypeTransitions();
IntrusivePrototypeTransitionIterator proto_iterator(this,
proto_transitions,
constructor);
proto_iterator.StartIfNotStarted();
if (proto_iterator.IsIterating()) {
Map* next = proto_iterator.Next();
if (next != NULL) return static_cast<TraversableMap*>(next);
}
}
IntrusiveMapTransitionIterator transition_iterator(transition_array);
IntrusiveMapTransitionIterator transition_iterator(this,
transition_array,
constructor);
transition_iterator.StartIfNotStarted();
if (transition_iterator.IsIterating()) {
Map* next = transition_iterator.Next();
if (next != NULL) return static_cast<TraversableMap*>(next);
......@@ -7403,12 +7416,16 @@ class TraversableMap : public Map {
// Traverse the transition tree in postorder without using the C++ stack by
// doing pointer reversal.
void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
// Make sure that we do not allocate in the callback.
DisallowHeapAllocation no_allocation;
TraversableMap* current = static_cast<TraversableMap*>(this);
current->ChildIteratorStart();
// Get the root constructor here to restore it later when finished iterating
// over maps.
Object* root_constructor = constructor();
while (true) {
TraversableMap* child = current->ChildIteratorNext();
TraversableMap* child = current->ChildIteratorNext(root_constructor);
if (child != NULL) {
child->ChildIteratorStart();
child->SetParent(current);
current = child;
} else {
......
......@@ -6123,9 +6123,6 @@ class Map: public HeapObject {
FixedArray* prototype_transitions);
inline bool HasPrototypeTransitions();
inline HeapObject* UncheckedPrototypeTransitions();
inline TransitionArray* unchecked_transition_array();
static const int kProtoTransitionHeaderSize = 1;
static const int kProtoTransitionNumberOfEntriesOffset = 0;
static const int kProtoTransitionElementsPerEntry = 2;
......
......@@ -88,12 +88,6 @@ FixedArray* TransitionArray::GetPrototypeTransitions() {
}
HeapObject* TransitionArray::UncheckedPrototypeTransitions() {
ASSERT(HasPrototypeTransitions());
return reinterpret_cast<HeapObject*>(get(kPrototypeTransitionsIndex));
}
void TransitionArray::SetPrototypeTransitions(FixedArray* transitions,
WriteBarrierMode mode) {
ASSERT(IsFullTransitionArray());
......
......@@ -85,7 +85,6 @@ class TransitionArray: public FixedArray {
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline Object** GetPrototypeTransitionsSlot();
inline bool HasPrototypeTransitions();
inline HeapObject* UncheckedPrototypeTransitions();
// Returns the number of transitions in the array.
int number_of_transitions() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment