Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index b7ecee776430f70f1f2fd5072d0bb4328b625ab6..6999c6b24108c0e7339e82821cad27369e45b586 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -7222,7 +7222,9 @@ void String::PrintOn(FILE* file) { |
| } |
| -void Map::CreateOneBackPointer(Map* target) { |
| +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(); |
| @@ -7244,86 +7246,123 @@ void Map::CreateOneBackPointer(Map* target) { |
| void Map::CreateBackPointers() { |
| DescriptorArray* descriptors = instance_descriptors(); |
| for (int i = 0; i < descriptors->number_of_descriptors(); i++) { |
| - if (descriptors->IsTransition(i)) { |
| - Object* object = reinterpret_cast<Object*>(descriptors->GetValue(i)); |
| - if (object->IsMap()) { |
| - CreateOneBackPointer(reinterpret_cast<Map*>(object)); |
| - } else { |
| - ASSERT(object->IsFixedArray()); |
| - ASSERT(descriptors->GetType(i) == ELEMENTS_TRANSITION); |
| - FixedArray* array = reinterpret_cast<FixedArray*>(object); |
| - for (int i = 0; i < array->length(); ++i) { |
| - Map* target = reinterpret_cast<Map*>(array->get(i)); |
| - if (!target->IsUndefined()) { |
| - CreateOneBackPointer(target); |
| + 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; |
| } |
| } |
| } |
| +static bool RestoreProto(Object* object, |
|
Michael Starzinger
2012/01/30 12:57:56
I would prefer "RestorePrototype" as a name. Also
Sven Panne
2012/01/30 13:34:39
Done.
|
| + Object* real_prototype, |
| + bool* keep_entry) { |
| + if (!object->IsMap()) return false; |
| + Map* map = static_cast<Map*>(object); |
|
Michael Starzinger
2012/01/30 12:57:56
If object->IsMap() is usable at this point, then M
Sven Panne
2012/01/30 13:34:39
Done.
|
| + if (Marking::MarkBitFrom(map).Get()) { |
| + *keep_entry = true; |
| + return false; |
| + } |
| + // Getter prototype() is read-only, set_prototype() has side effects. |
| + *HeapObject::RawField(map, Map::kPrototypeOffset) = real_prototype; |
| + return true; |
| +} |
| + |
| + |
| void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { |
| - // Live DescriptorArray objects will be marked, so we must use |
| - // low-level accessors to get and modify their data. |
| - DescriptorArray* d = reinterpret_cast<DescriptorArray*>( |
| + // Live DescriptorArray objects will be marked, so we must use low-level |
|
Michael Starzinger
2012/01/30 12:57:56
The comment is no longer accurate.
Sven Panne
2012/01/30 13:34:39
Done.
|
| + // accessors to get and modify their data. |
| + DescriptorArray* d = static_cast<DescriptorArray*>( |
|
Michael Starzinger
2012/01/30 12:57:56
I think we can use our internal casts here. Could
Sven Panne
2012/01/30 13:34:39
Done.
|
| *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); |
| if (d->IsEmpty()) return; |
| Smi* NullDescriptorDetails = |
| PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); |
| - FixedArray* contents = reinterpret_cast<FixedArray*>( |
| + FixedArray* contents = static_cast<FixedArray*>( |
|
Michael Starzinger
2012/01/30 12:57:56
Likewise.
Sven Panne
2012/01/30 13:34:39
Done.
|
| d->get(DescriptorArray::kContentArrayIndex)); |
| ASSERT(contents->length() >= 2); |
| for (int i = 0; i < contents->length(); i += 2) { |
| - // 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. |
| + // 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. |
| + bool keep_entry = false; |
| PropertyDetails details(Smi::cast(contents->get(i + 1))); |
| - if (IsTransitionType(details.type())) { |
| - Object* object = reinterpret_cast<Object*>(contents->get(i)); |
| - if (object->IsMap()) { |
| - Map* target = reinterpret_cast<Map*>(object); |
| - ASSERT(target->IsHeapObject()); |
| - MarkBit map_mark = Marking::MarkBitFrom(target); |
| - if (!map_mark.Get()) { |
| - ASSERT(target->IsMap()); |
| - contents->set_unchecked(i + 1, NullDescriptorDetails); |
| - contents->set_null_unchecked(heap, i); |
| - ASSERT(target->prototype() == this || |
|
Michael Starzinger
2012/01/30 12:57:56
Can we keep this assertion around? If we turn Rest
Sven Panne
2012/01/30 13:34:39
Done.
|
| - target->prototype() == real_prototype); |
| - // Getter prototype() is read-only, set_prototype() has side effects. |
| - *RawField(target, Map::kPrototypeOffset) = real_prototype; |
| - } |
| - } else { |
| - ASSERT(object->IsFixedArray()); |
| - ASSERT(details.type() == ELEMENTS_TRANSITION); |
| - FixedArray* array = reinterpret_cast<FixedArray*>(object); |
| - bool reachable_map_found = false; |
| - for (int j = 0; j < array->length(); ++j) { |
| - Map* target = reinterpret_cast<Map*>(array->get(j)); |
| - ASSERT(target->IsHeapObject()); |
| - MarkBit map_mark = Marking::MarkBitFrom(target); |
| - if (!map_mark.Get()) { |
| - ASSERT(target->IsMap()); |
| - array->set_undefined(j); |
| - ASSERT(target->prototype() == this || |
|
Michael Starzinger
2012/01/30 12:57:56
Likewise.
Sven Panne
2012/01/30 13:34:39
Done.
|
| - target->prototype() == real_prototype); |
| - // Getter prototype() is read-only, set_prototype() has side |
| - // effects. |
| - *RawField(target, Map::kPrototypeOffset) = real_prototype; |
| - } else if (target->IsMap()) { |
| - reachable_map_found = true; |
| + switch (details.type()) { |
| + case MAP_TRANSITION: |
| + case CONSTANT_TRANSITION: |
| + RestoreProto(contents->get(i), real_prototype, &keep_entry); |
| + break; |
| + case ELEMENTS_TRANSITION: { |
| + Object* object = contents->get(i); |
| + if (object->IsMap()) { |
| + RestoreProto(object, real_prototype, &keep_entry); |
| + } else { |
| + FixedArray* array = FixedArray::cast(object); |
| + for (int j = 0; j < array->length(); ++j) { |
| + if (RestoreProto(array->get(j), real_prototype, &keep_entry)) { |
| + array->set_undefined(j); |
| + } |
| } |
| } |
| - // If no map was found, make sure the FixedArray also gets collected. |
|
Michael Starzinger
2012/01/30 12:57:56
Can we keep this comment (and place it above line
Sven Panne
2012/01/30 13:34:39
Done.
|
| - if (!reachable_map_found) { |
| - contents->set_unchecked(i + 1, NullDescriptorDetails); |
| - contents->set_null_unchecked(heap, i); |
| + break; |
| + } |
| + case CALLBACKS: { |
| + Object* object = contents->get(i); |
| + if (object->IsAccessorPair()) { |
| + AccessorPair* accessors = AccessorPair::cast(object); |
| + if (RestoreProto(accessors->getter(), real_prototype, &keep_entry)) { |
| + accessors->set_getter(heap->the_hole_value()); |
| + } |
| + if (RestoreProto(accessors->setter(), real_prototype, &keep_entry)) { |
| + accessors->set_setter(heap->the_hole_value()); |
| + } |
| + } else { |
| + keep_entry = true; |
| } |
| + break; |
| } |
| + case NORMAL: |
| + case FIELD: |
| + case CONSTANT_FUNCTION: |
| + case HANDLER: |
| + case INTERCEPTOR: |
| + case NULL_DESCRIPTOR: |
| + keep_entry = true; |
| + break; |
| + } |
| + if (!keep_entry) { |
| + contents->set_unchecked(i + 1, NullDescriptorDetails); |
| + contents->set_null_unchecked(heap, i); |
| } |
| } |
| } |