Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 970fc24550878072e45297bd6c0601a576165ba3..03d98c862f6a31302b563a18a71ad577ad49d276 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->set_back_pointer(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)->set_back_pointer(old_map); |
| return function; |
| } |
| @@ -1824,6 +1826,7 @@ MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition( |
| } |
| } |
| old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors)); |
| + map()->set_back_pointer(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->set_back_pointer(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->set_back_pointer(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->set_back_pointer(map2); |
| return obj; |
| } |
| @@ -5137,8 +5143,9 @@ class IntrusiveMapTransitionIterator { |
| // underlying array while it is running. |
| class IntrusivePrototypeTransitionIterator { |
| public: |
| - explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans) |
| - : proto_trans_(proto_trans) { } |
| + explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans) |
| + : heap_(proto_trans->GetHeap()), |
| + proto_trans_(reinterpret_cast<FixedArray*>(proto_trans)) { } |
| void Start() { |
| ASSERT(!IsIterating()); |
| @@ -5156,13 +5163,15 @@ class IntrusivePrototypeTransitionIterator { |
| *Header() = Smi::FromInt(transitionNumber + 1); |
| return GetTransition(transitionNumber); |
| } |
| - *Header() = proto_trans_->GetHeap()->fixed_array_map(); |
| + *Header() = heap_->fixed_array_map(); |
| return NULL; |
| } |
| private: |
| bool HasTransitions() { |
| - return proto_trans_->length() >= Map::kProtoTransitionHeaderSize; |
| + Object* header = *Header(); |
|
Vyacheslav Egorov (Chromium)
2012/05/08 14:29:19
is this change really required?
Michael Starzinger
2012/05/09 07:30:02
Yes it is, because this iterator overwrites the ma
|
| + return header->IsSmi() || (header == heap_->fixed_array_map() && |
| + proto_trans_->length() >= Map::kProtoTransitionHeaderSize); |
|
Vyacheslav Egorov (Chromium)
2012/05/08 14:29:19
should not this just be >?
Michael Starzinger
2012/05/09 07:30:02
Done. The length check is obsolete actually. The p
|
| } |
| Object** Header() { |
| @@ -5184,6 +5193,7 @@ class IntrusivePrototypeTransitionIterator { |
| transitionNumber * Map::kProtoTransitionElementsPerEntry; |
| } |
| + Heap* heap_; |
| FixedArray* 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->set_back_pointer(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 { |