Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 970fc24550878072e45297bd6c0601a576165ba3..cde43f9f23e0a352702adb360de479b4143c3547 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -1604,6 +1604,7 @@ MaybeObject* JSObject::AddFastProperty(String* name, |
// 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 @@ MaybeObject* JSObject::AddConstantFunctionProperty( |
} |
} |
old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
+ Map::cast(new_map)->SetBackPointer(old_map); |
return function; |
} |
@@ -1824,6 +1826,7 @@ MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition( |
} |
} |
old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
+ map()->SetBackPointer(old_map); |
return result; |
} |
@@ -2408,6 +2411,7 @@ MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind, |
return maybe_new_descriptors; |
} |
set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
+ transitioned_map->SetBackPointer(this); |
return this; |
} |
@@ -4653,6 +4657,7 @@ static MaybeObject* CreateFreshAccessor(JSObject* obj, |
// 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 @@ static MaybeObject* NewCallbackTransition(JSObject* obj, |
// 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 @@ class IntrusiveMapTransitionIterator { |
// 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 @@ class IntrusivePrototypeTransitionIterator { |
private: |
bool HasTransitions() { |
- return proto_trans_->length() >= Map::kProtoTransitionHeaderSize; |
+ return proto_trans_->map()->IsSmi() || proto_trans_->IsFixedArray(); |
} |
Object** Header() { |
@@ -5170,12 +5176,16 @@ class IntrusivePrototypeTransitionIterator { |
} |
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 @@ class IntrusivePrototypeTransitionIterator { |
transitionNumber * Map::kProtoTransitionElementsPerEntry; |
} |
- FixedArray* proto_trans_; |
+ HeapObject* proto_trans_; |
}; |
@@ -7346,85 +7356,23 @@ void String::PrintOn(FILE* file) { |
} |
-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; |
+ } else { |
+ map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); |
+ return true; |
} |
- 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; |
} |
-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 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { |
// 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 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { |
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 { |