diff --git a/src/objects.cc b/src/objects.cc index 0c61001936..94a122800b 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -3300,19 +3300,21 @@ static Handle AddMissingElementsTransitions(Handle map, Handle current_map = map; ElementsKind kind = map->elements_kind(); - if (!map->is_prototype_map()) { + TransitionFlag flag; + if (map->is_prototype_map()) { + flag = OMIT_TRANSITION; + } else { + flag = INSERT_TRANSITION; while (kind != to_kind && !IsTerminalElementsKind(kind)) { kind = GetNextTransitionElementsKind(kind); - current_map = - Map::CopyAsElementsKind(current_map, kind, INSERT_TRANSITION); + current_map = Map::CopyAsElementsKind(current_map, kind, flag); } } // In case we are exiting the fast elements kind system, just add the map in // the end. if (kind != to_kind) { - current_map = Map::CopyAsElementsKind( - current_map, to_kind, INSERT_TRANSITION); + current_map = Map::CopyAsElementsKind(current_map, to_kind, flag); } DCHECK(current_map->elements_kind() == to_kind); @@ -6805,31 +6807,18 @@ Handle Map::CopyAsElementsKind(Handle map, ElementsKind kind, map->CanHaveMoreTransitions() && !map->HasElementsTransition(); - if (insert_transition && map->owns_descriptors()) { - // In case the map owned its own descriptors, share the descriptors and - // transfer ownership to the new map. - Handle new_map = CopyDropDescriptors(map); + if (insert_transition) { + Handle new_map = CopyForTransition(map, "CopyAsElementsKind"); + new_map->set_elements_kind(kind); ConnectElementsTransition(map, new_map); - new_map->set_elements_kind(kind); - // The properties did not change, so reuse descriptors. - new_map->InitializeDescriptors(map->instance_descriptors(), - map->GetLayoutDescriptor()); return new_map; } - // In case the map did not own its own descriptors, a split is forced by - // copying the map; creating a new descriptor array cell. // Create a new free-floating map only if we are not allowed to store it. Handle new_map = Copy(map, "CopyAsElementsKind"); - new_map->set_elements_kind(kind); - - if (insert_transition) { - ConnectElementsTransition(map, new_map); - } - return new_map; } @@ -6839,27 +6828,55 @@ Handle Map::CopyForObserved(Handle map) { Isolate* isolate = map->GetIsolate(); - // In case the map owned its own descriptors, share the descriptors and - // transfer ownership to the new map. - Handle new_map; - if (map->owns_descriptors()) { - new_map = CopyDropDescriptors(map); - } else { - DCHECK(!map->is_prototype_map()); - new_map = Copy(map, "CopyForObserved"); + bool insert_transition = + map->CanHaveMoreTransitions() && !map->is_prototype_map(); + + if (insert_transition) { + Handle new_map = CopyForTransition(map, "CopyForObserved"); + new_map->set_is_observed(); + + Handle name = isolate->factory()->observed_symbol(); + ConnectTransition(map, new_map, name, SPECIAL_TRANSITION); + return new_map; } + // Create a new free-floating map only if we are not allowed to store it. + Handle new_map = Map::Copy(map, "CopyForObserved"); new_map->set_is_observed(); + return new_map; +} + + +Handle Map::CopyForTransition(Handle map, const char* reason) { + DCHECK(!map->is_prototype_map()); + Handle new_map = CopyDropDescriptors(map); + if (map->owns_descriptors()) { + // In case the map owned its own descriptors, share the descriptors and + // transfer ownership to the new map. // The properties did not change, so reuse descriptors. new_map->InitializeDescriptors(map->instance_descriptors(), map->GetLayoutDescriptor()); + } else { + // In case the map did not own its own descriptors, a split is forced by + // copying the map; creating a new descriptor array cell. + Handle descriptors(map->instance_descriptors()); + int number_of_own_descriptors = map->NumberOfOwnDescriptors(); + Handle new_descriptors = + DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors); + Handle new_layout_descriptor(map->GetLayoutDescriptor(), + map->GetIsolate()); + new_map->InitializeDescriptors(*new_descriptors, *new_layout_descriptor); } - if (map->CanHaveMoreTransitions()) { - Handle name = isolate->factory()->observed_symbol(); - ConnectTransition(map, new_map, name, SPECIAL_TRANSITION); +#if TRACE_MAPS + if (FLAG_trace_maps) { + PrintF("[TraceMaps: CopyForTransition from= %p to= %p reason= %s ]\n", + reinterpret_cast(*map), reinterpret_cast(*new_map), + reason); } +#endif + return new_map; } diff --git a/src/objects.h b/src/objects.h index 51755054cb..faab1730fb 100644 --- a/src/objects.h +++ b/src/objects.h @@ -6141,6 +6141,11 @@ class Map: public HeapObject { inline void AppendDescriptor(Descriptor* desc); + // Returns a copy of the map, prepared for inserting into the transition + // tree (if the |map| owns descriptors then the new one will share + // descriptors with |map|). + static Handle CopyForTransition(Handle map, const char* reason); + // Returns a copy of the map, with all transitions dropped from the // instance descriptors. static Handle Copy(Handle map, const char* reason); diff --git a/test/mjsunit/regress/regress-448711.js b/test/mjsunit/regress/regress-448711.js new file mode 100644 index 0000000000..b7628ab2eb --- /dev/null +++ b/test/mjsunit/regress/regress-448711.js @@ -0,0 +1,15 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Flags: --allow-natives-syntax + +function f() { + this.a = { text: "Hello!" }; +} +var v4 = new f(); +var v7 = new f(); +v7.b = {}; +Object.defineProperty(v4, '2', {}); +var v6 = new f(); +v6.a = {};