| 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 {
|
|
|