| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index ecd31f7f5b531a6cc05d041d247704a0429dcf22..da65e86189d38a511005ff79ee6963b151c2880c 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -2704,20 +2704,21 @@ bool Map::DeprecateTarget(PropertyKind kind, Name* key,
|
| transition_target_deprecated = true;
|
| }
|
|
|
| - // Don't overwrite the empty descriptor array.
|
| - if (NumberOfOwnDescriptors() == 0) return transition_target_deprecated;
|
| + // Don't overwrite the empty descriptor array or initial map's descriptors.
|
| + if (NumberOfOwnDescriptors() == 0 || GetBackPointer()->IsUndefined()) {
|
| + return transition_target_deprecated;
|
| + }
|
|
|
| DescriptorArray* to_replace = instance_descriptors();
|
| - Map* current = this;
|
| GetHeap()->incremental_marking()->RecordWrites(to_replace);
|
| + Map* current = this;
|
| while (current->instance_descriptors() == to_replace) {
|
| + Object* next = current->GetBackPointer();
|
| + if (next->IsUndefined()) break; // Stop overwriting at initial map.
|
| current->SetEnumLength(kInvalidEnumCacheSentinel);
|
| current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
|
| - Object* next = current->GetBackPointer();
|
| - if (next->IsUndefined()) break;
|
| current = Map::cast(next);
|
| }
|
| -
|
| set_owns_descriptors(false);
|
| return transition_target_deprecated;
|
| }
|
| @@ -2727,7 +2728,14 @@ Map* Map::FindRootMap() {
|
| Map* result = this;
|
| while (true) {
|
| Object* back = result->GetBackPointer();
|
| - if (back->IsUndefined()) return result;
|
| + if (back->IsUndefined()) {
|
| + // Initial map always owns descriptors and doesn't have unused entries
|
| + // in the descriptor array.
|
| + DCHECK(result->owns_descriptors());
|
| + DCHECK_EQ(result->NumberOfOwnDescriptors(),
|
| + result->instance_descriptors()->number_of_descriptors());
|
| + return result;
|
| + }
|
| result = Map::cast(back);
|
| }
|
| }
|
| @@ -4089,15 +4097,13 @@ void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
|
| // Replace descriptors by new_descriptors in all maps that share it.
|
| map->GetHeap()->incremental_marking()->RecordWrites(*descriptors);
|
|
|
| - Map* walk_map;
|
| - for (Object* current = map->GetBackPointer();
|
| - !current->IsUndefined();
|
| - current = walk_map->GetBackPointer()) {
|
| - walk_map = Map::cast(current);
|
| - if (walk_map->instance_descriptors() != *descriptors) break;
|
| - walk_map->UpdateDescriptors(*new_descriptors, layout_descriptor);
|
| + Map* current = *map;
|
| + while (current->instance_descriptors() == *descriptors) {
|
| + Object* next = current->GetBackPointer();
|
| + if (next->IsUndefined()) break; // Stop overwriting at initial map.
|
| + current->UpdateDescriptors(*new_descriptors, layout_descriptor);
|
| + current = Map::cast(next);
|
| }
|
| -
|
| map->UpdateDescriptors(*new_descriptors, layout_descriptor);
|
| }
|
|
|
| @@ -8215,6 +8221,12 @@ Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
|
| DCHECK(constructor->IsJSFunction());
|
| DCHECK_EQ(*map, JSFunction::cast(constructor)->initial_map());
|
| #endif
|
| + // Initial maps must always own their descriptors and it's descriptor array
|
| + // does not contain descriptors that do not belong to the map.
|
| + DCHECK(map->owns_descriptors());
|
| + DCHECK_EQ(map->NumberOfOwnDescriptors(),
|
| + map->instance_descriptors()->number_of_descriptors());
|
| +
|
| Handle<Map> result = RawCopy(map, instance_size);
|
|
|
| // Please note instance_type and instance_size are set when allocated.
|
| @@ -8223,11 +8235,9 @@ Handle<Map> Map::CopyInitialMap(Handle<Map> map, int instance_size,
|
|
|
| int number_of_own_descriptors = map->NumberOfOwnDescriptors();
|
| if (number_of_own_descriptors > 0) {
|
| - DCHECK(map->owns_descriptors());
|
| - // The copy will use the same descriptors array, but it's not the owner.
|
| + // The copy will use the same descriptors array.
|
| result->UpdateDescriptors(map->instance_descriptors(),
|
| map->layout_descriptor());
|
| - result->set_owns_descriptors(false);
|
| result->SetNumberOfOwnDescriptors(number_of_own_descriptors);
|
|
|
| DCHECK_EQ(result->NumberOfFields(),
|
| @@ -8257,8 +8267,8 @@ Handle<Map> Map::ShareDescriptor(Handle<Map> map,
|
| // Sanity check. This path is only to be taken if the map owns its descriptor
|
| // array, implying that its NumberOfOwnDescriptors equals the number of
|
| // descriptors in the descriptor array.
|
| - DCHECK(map->NumberOfOwnDescriptors() ==
|
| - map->instance_descriptors()->number_of_descriptors());
|
| + DCHECK_EQ(map->NumberOfOwnDescriptors(),
|
| + map->instance_descriptors()->number_of_descriptors());
|
|
|
| Handle<Map> result = CopyDropDescriptors(map);
|
| Handle<Name> name = descriptor->GetKey();
|
| @@ -8323,7 +8333,15 @@ void Map::TraceAllTransitions(Map* map) {
|
|
|
| void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
|
| Handle<Name> name, SimpleTransitionFlag flag) {
|
| - parent->set_owns_descriptors(false);
|
| + if (!parent->GetBackPointer()->IsUndefined()) {
|
| + parent->set_owns_descriptors(false);
|
| + } else {
|
| + // |parent| is initial map and it must keep the ownership, there must be no
|
| + // descriptors in the descriptors array that do not belong to the map.
|
| + DCHECK(parent->owns_descriptors());
|
| + DCHECK_EQ(parent->NumberOfOwnDescriptors(),
|
| + parent->instance_descriptors()->number_of_descriptors());
|
| + }
|
| if (parent->is_prototype_map()) {
|
| DCHECK(child->is_prototype_map());
|
| #if TRACE_MAPS
|
| @@ -8821,7 +8839,9 @@ Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
|
| // Ensure the key is unique.
|
| descriptor->KeyToUniqueName();
|
|
|
| + // Share descriptors only if map owns descriptors and it not an initial map.
|
| if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
|
| + !map->GetBackPointer()->IsUndefined() &&
|
| TransitionArray::CanHaveMoreTransitions(map)) {
|
| return ShareDescriptor(map, descriptors, descriptor);
|
| }
|
|
|