Revert of Simplify and compact transitions storage (patchset #4 id:80001 of https...
authorjkummerow <jkummerow@chromium.org>
Thu, 5 Mar 2015 20:41:47 +0000 (12:41 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 5 Mar 2015 20:42:03 +0000 (20:42 +0000)
Reason for revert:
x64 test failures

Original issue's description:
> Simplify and compact transitions storage
>
> Simple transitions are now stored in a map's "transitions" field (as a WeakCell wrapping the target map); full TransitionArrays are used when that's not sufficient.
> To encapsulate these storage format implementation details, functions for manipulating and querying transitions have been refactored to be static functions on the TransitionArray class, and take maps as inputs.
>
> Committed: https://crrev.com/45fbef7f2252fce10634931cb103ccc1fc95ae6a
> Cr-Commit-Position: refs/heads/master@{#27029}

TBR=verwaest@chromium.org,ulan@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true

Review URL: https://codereview.chromium.org/982143002

Cr-Commit-Position: refs/heads/master@{#27030}

18 files changed:
src/heap-snapshot-generator.cc
src/heap/heap.cc
src/heap/mark-compact.cc
src/heap/mark-compact.h
src/heap/objects-visiting-inl.h
src/hydrogen.h
src/json-parser.h
src/objects-debug.cc
src/objects-inl.h
src/objects-printer.cc
src/objects.cc
src/objects.h
src/transitions-inl.h
src/transitions.cc
src/transitions.h
test/cctest/test-heap.cc
test/cctest/test-migrations.cc
test/cctest/test-transitions.cc

index 2809072c9c9521aa21a96666d17da24cfd94ed3c..6fb68702fdc2a28ca2e02a783c1b2b6f3a19b58c 100644 (file)
@@ -1286,31 +1286,28 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
 
 
 void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
-  Object* raw_transitions = map->raw_transitions();
-  if (TransitionArray::IsFullTransitionArray(raw_transitions)) {
-    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
+  if (map->HasTransitionArray()) {
+    TransitionArray* transitions = map->transitions();
     int transitions_entry = GetEntry(transitions)->index();
 
     if (FLAG_collect_maps && map->CanTransition()) {
-      if (transitions->HasPrototypeTransitions()) {
-        FixedArray* prototype_transitions =
-            transitions->GetPrototypeTransitions();
-        MarkAsWeakContainer(prototype_transitions);
-        TagObject(prototype_transitions, "(prototype transitions");
-        SetInternalReference(transitions, transitions_entry,
-                             "prototype_transitions", prototype_transitions);
+      if (!transitions->IsSimpleTransition()) {
+        if (transitions->HasPrototypeTransitions()) {
+          FixedArray* prototype_transitions =
+              transitions->GetPrototypeTransitions();
+          MarkAsWeakContainer(prototype_transitions);
+          TagObject(prototype_transitions, "(prototype transitions");
+          SetInternalReference(transitions, transitions_entry,
+                               "prototype_transitions", prototype_transitions);
+        }
+        // TODO(alph): transitions keys are strong links.
+        MarkAsWeakContainer(transitions);
       }
-      // TODO(alph): transitions keys are strong links.
-      MarkAsWeakContainer(transitions);
     }
 
     TagObject(transitions, "(transition array)");
     SetInternalReference(map, entry, "transitions", transitions,
                          Map::kTransitionsOffset);
-  } else if (TransitionArray::IsSimpleTransition(raw_transitions)) {
-    TagObject(raw_transitions, "(transition)");
-    SetInternalReference(map, entry, "transition", raw_transitions,
-                         Map::kTransitionsOffset);
   }
   DescriptorArray* descriptors = map->instance_descriptors();
   TagObject(descriptors, "(map descriptors)");
index 9b7141e09a1d4475dc2252365001134993a35a92..7c9130d41a9c92286da176f8eebbeea2e5120ad6 100644 (file)
@@ -2476,7 +2476,7 @@ AllocationResult Heap::AllocateMap(InstanceType instance_type,
   map->set_dependent_code(DependentCode::cast(empty_fixed_array()),
                           SKIP_WRITE_BARRIER);
   map->set_weak_cell_cache(Smi::FromInt(0));
-  map->set_raw_transitions(Smi::FromInt(0));
+  map->init_transitions(undefined_value());
   map->set_unused_property_fields(0);
   map->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
@@ -2610,7 +2610,7 @@ bool Heap::CreateInitialMaps() {
   // Fix the instance_descriptors for the existing maps.
   meta_map()->set_code_cache(empty_fixed_array());
   meta_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
-  meta_map()->set_raw_transitions(Smi::FromInt(0));
+  meta_map()->init_transitions(undefined_value());
   meta_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     meta_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
@@ -2619,7 +2619,7 @@ bool Heap::CreateInitialMaps() {
   fixed_array_map()->set_code_cache(empty_fixed_array());
   fixed_array_map()->set_dependent_code(
       DependentCode::cast(empty_fixed_array()));
-  fixed_array_map()->set_raw_transitions(Smi::FromInt(0));
+  fixed_array_map()->init_transitions(undefined_value());
   fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     fixed_array_map()->set_layout_descriptor(
@@ -2628,7 +2628,7 @@ bool Heap::CreateInitialMaps() {
 
   undefined_map()->set_code_cache(empty_fixed_array());
   undefined_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
-  undefined_map()->set_raw_transitions(Smi::FromInt(0));
+  undefined_map()->init_transitions(undefined_value());
   undefined_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     undefined_map()->set_layout_descriptor(
@@ -2637,7 +2637,7 @@ bool Heap::CreateInitialMaps() {
 
   null_map()->set_code_cache(empty_fixed_array());
   null_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
-  null_map()->set_raw_transitions(Smi::FromInt(0));
+  null_map()->init_transitions(undefined_value());
   null_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     null_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
@@ -2646,7 +2646,7 @@ bool Heap::CreateInitialMaps() {
   constant_pool_array_map()->set_code_cache(empty_fixed_array());
   constant_pool_array_map()->set_dependent_code(
       DependentCode::cast(empty_fixed_array()));
-  constant_pool_array_map()->set_raw_transitions(Smi::FromInt(0));
+  constant_pool_array_map()->init_transitions(undefined_value());
   constant_pool_array_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     constant_pool_array_map()->set_layout_descriptor(
index abaf965abedf373f981032f99f261c7a9eaa6718..1c5299fb6021b67fbcfd16e41bf81c6010660faa 100644 (file)
@@ -1470,9 +1470,8 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker<
       heap->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE,
                                          fixed_array_size);
     }
-    if (TransitionArray::IsFullTransitionArray(map_obj->raw_transitions())) {
-      int fixed_array_size =
-          TransitionArray::cast(map_obj->raw_transitions())->Size();
+    if (map_obj->HasTransitionArray()) {
+      int fixed_array_size = map_obj->transitions()->Size();
       heap->RecordFixedArraySubTypeStats(TRANSITION_ARRAY_SUB_TYPE,
                                          fixed_array_size);
     }
@@ -2347,12 +2346,10 @@ void MarkCompactCollector::ClearNonLiveReferences() {
 
 
 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
-  FixedArray* prototype_transitions =
-      TransitionArray::GetPrototypeTransitions(map);
-  int number_of_transitions =
-      TransitionArray::NumberOfPrototypeTransitions(prototype_transitions);
+  int number_of_transitions = map->NumberOfProtoTransitions();
+  FixedArray* prototype_transitions = map->GetPrototypeTransitions();
 
-  const int header = TransitionArray::kProtoTransitionHeaderSize;
+  const int header = Map::kProtoTransitionHeaderSize;
   int new_number_of_transitions = 0;
   for (int i = 0; i < number_of_transitions; i++) {
     Object* cached_map = prototype_transitions->get(header + i);
@@ -2366,8 +2363,7 @@ void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
   }
 
   if (new_number_of_transitions != number_of_transitions) {
-    TransitionArray::SetNumberOfPrototypeTransitions(prototype_transitions,
-                                                     new_number_of_transitions);
+    map->SetNumberOfProtoTransitions(new_number_of_transitions);
   }
 
   // Fill slots that became free with undefined value.
@@ -2388,7 +2384,7 @@ void MarkCompactCollector::ClearNonLiveMapTransitions(Map* map,
   bool current_is_alive = map_mark.Get();
   bool parent_is_alive = Marking::MarkBitFrom(parent).Get();
   if (!current_is_alive && parent_is_alive) {
-    ClearMapTransitions(parent, map);
+    ClearMapTransitions(parent);
   }
 }
 
@@ -2402,43 +2398,28 @@ bool MarkCompactCollector::ClearMapBackPointer(Map* target) {
 }
 
 
-void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) {
-  Object* transitions = map->raw_transitions();
-  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
+void MarkCompactCollector::ClearMapTransitions(Map* map) {
+  // If there are no transitions to be cleared, return.
+  // TODO(verwaest) Should be an assert, otherwise back pointers are not
+  // properly cleared.
+  if (!map->HasTransitionArray()) return;
 
-  int number_of_own_descriptors = map->NumberOfOwnDescriptors();
-  DescriptorArray* descriptors = map->instance_descriptors();
-
-  // A previously existing simple transition (stored in a WeakCell) may have
-  // been cleared. Clear the useless cell pointer, and take ownership
-  // of the descriptor array.
-  if (transitions->IsWeakCell() && WeakCell::cast(transitions)->cleared()) {
-    map->set_raw_transitions(Smi::FromInt(0));
-  }
-  if (num_transitions == 0 &&
-      descriptors == dead_transition->instance_descriptors() &&
-      number_of_own_descriptors > 0) {
-    TrimDescriptorArray(map, descriptors, number_of_own_descriptors);
-    DCHECK(descriptors->number_of_descriptors() == number_of_own_descriptors);
-    map->set_owns_descriptors(true);
-    return;
-  }
+  TransitionArray* t = map->transitions();
 
   int transition_index = 0;
 
+  DescriptorArray* descriptors = map->instance_descriptors();
   bool descriptors_owner_died = false;
 
   // Compact all live descriptors to the left.
-  for (int i = 0; i < num_transitions; ++i) {
-    Map* target = TransitionArray::GetTarget(transitions, i);
+  for (int i = 0; i < t->number_of_transitions(); ++i) {
+    Map* target = t->GetTarget(i);
     if (ClearMapBackPointer(target)) {
       if (target->instance_descriptors() == descriptors) {
         descriptors_owner_died = true;
       }
     } else {
       if (i != transition_index) {
-        DCHECK(TransitionArray::IsFullTransitionArray(transitions));
-        TransitionArray* t = TransitionArray::cast(transitions);
         Name* key = t->GetKey(i);
         t->SetKey(transition_index, key);
         Object** key_slot = t->GetKeySlot(transition_index);
@@ -2453,7 +2434,9 @@ void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) {
   // If there are no transitions to be cleared, return.
   // TODO(verwaest) Should be an assert, otherwise back pointers are not
   // properly cleared.
-  if (transition_index == num_transitions) return;
+  if (transition_index == t->number_of_transitions()) return;
+
+  int number_of_own_descriptors = map->NumberOfOwnDescriptors();
 
   if (descriptors_owner_died) {
     if (number_of_own_descriptors > 0) {
@@ -2469,17 +2452,14 @@ void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) {
   // such that number_of_transitions() == 0. If this assumption changes,
   // TransitionArray::Insert() will need to deal with the case that a transition
   // array disappeared during GC.
-  int trim = TransitionArray::Capacity(transitions) - transition_index;
+  int trim = t->number_of_transitions_storage() - transition_index;
   if (trim > 0) {
-    // Non-full-TransitionArray cases can never reach this point.
-    DCHECK(TransitionArray::IsFullTransitionArray(transitions));
-    TransitionArray* t = TransitionArray::cast(transitions);
     heap_->RightTrimFixedArray<Heap::FROM_GC>(
-        t, trim * TransitionArray::kTransitionSize);
+        t, t->IsSimpleTransition() ? trim
+                                   : trim * TransitionArray::kTransitionSize);
     t->SetNumberOfTransitions(transition_index);
-    // The map still has a full transition array.
-    DCHECK(TransitionArray::IsFullTransitionArray(map->raw_transitions()));
   }
+  DCHECK(map->HasTransitionArray());
 }
 
 
@@ -4191,7 +4171,7 @@ void MarkCompactCollector::SweepSpaces() {
 
   EvacuateNewSpaceAndCandidates();
 
-  // ClearNonLiveReferences depends on precise sweeping of map space to
+  // ClearNonLiveTransitions depends on precise sweeping of map space to
   // detect whether unmarked map became dead in this collection or in one
   // of the previous ones.
   {
index 4fee16edc36439f8e258f6158bbaffd0395f93d3..589bebf63f8a0e57de8079d8aab7bdf9ffc768ca 100644 (file)
@@ -808,7 +808,7 @@ class MarkCompactCollector {
   void ClearNonLiveReferences();
   void ClearNonLivePrototypeTransitions(Map* map);
   void ClearNonLiveMapTransitions(Map* map, MarkBit map_mark);
-  void ClearMapTransitions(Map* map, Map* dead_transition);
+  void ClearMapTransitions(Map* map);
   bool ClearMapBackPointer(Map* map);
   void TrimDescriptorArray(Map* map, DescriptorArray* descriptors,
                            int number_of_own_descriptors);
index b4240d2a491e44be26f4e8fbb6bda132953e8bc1..58afeae0167dd7aedbdbbc70ff6b3b6d9fb579f8 100644 (file)
@@ -584,13 +584,18 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSDataView(Map* map,
 template <typename StaticVisitor>
 void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(Heap* heap,
                                                           Map* map) {
-  Object* raw_transitions = map->raw_transitions();
-  if (TransitionArray::IsSimpleTransition(raw_transitions)) {
-    StaticVisitor::VisitPointer(
-        heap, HeapObject::RawField(map, Map::kTransitionsOffset));
-  }
-  if (TransitionArray::IsFullTransitionArray(raw_transitions)) {
-    MarkTransitionArray(heap, TransitionArray::cast(raw_transitions));
+  // Make sure that the back pointer stored either in the map itself or
+  // inside its transitions array is marked. Skip recording the back
+  // pointer slot since map space is not compacted.
+  StaticVisitor::MarkObject(heap, HeapObject::cast(map->GetBackPointer()));
+
+  // Treat pointers in the transitions array as weak and also mark that
+  // array to prevent visiting it later. Skip recording the transition
+  // array slot, since it will be implicitly recorded when the pointer
+  // fields of this map are visited.
+  if (map->HasTransitionArray()) {
+    TransitionArray* transitions = map->transitions();
+    MarkTransitionArray(heap, transitions);
   }
 
   // Since descriptor arrays are potentially shared, ensure that only the
@@ -626,18 +631,20 @@ void StaticMarkingVisitor<StaticVisitor>::MarkTransitionArray(
     Heap* heap, TransitionArray* transitions) {
   if (!StaticVisitor::MarkObjectWithoutPush(heap, transitions)) return;
 
+  // Simple transitions do not have keys nor prototype transitions.
+  if (transitions->IsSimpleTransition()) return;
+
   if (transitions->HasPrototypeTransitions()) {
     // Mark prototype transitions array but do not push it onto marking
     // stack, this will make references from it weak. We will clean dead
-    // prototype transitions in ClearNonLiveReferences.
+    // prototype transitions in ClearNonLiveTransitions.
     Object** slot = transitions->GetPrototypeTransitionsSlot();
     HeapObject* obj = HeapObject::cast(*slot);
     heap->mark_compact_collector()->RecordSlot(slot, slot, obj);
     StaticVisitor::MarkObjectWithoutPush(heap, obj);
   }
 
-  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
-  for (int i = 0; i < num_transitions; ++i) {
+  for (int i = 0; i < transitions->number_of_transitions(); ++i) {
     StaticVisitor::VisitPointer(heap, transitions->GetKeySlot(i));
   }
 }
index ca679e7253ec9db75fbbc04529785ab89038fd98..831ed20cb11d26ea064eddbbfa94ccd3773302c0 100644 (file)
@@ -2553,11 +2553,10 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
       number_ = number;
     }
     void LookupTransition(Map* map, Name* name, PropertyAttributes attributes) {
-      Map* target =
-          TransitionArray::SearchTransition(map, kData, name, attributes);
-      if (target == NULL) return NotFound();
+      int transition_index = map->SearchTransition(kData, name, attributes);
+      if (transition_index == TransitionArray::kNotFound) return NotFound();
       lookup_type_ = TRANSITION_TYPE;
-      transition_ = handle(target);
+      transition_ = handle(map->GetTransition(transition_index));
       number_ = transition_->LastAdded();
       details_ = transition_->instance_descriptors()->GetDetails(number_);
     }
index da26670f8e822041921b1bb7bc9f398c99bdaf65..4cf52574b54655a9000651db6391f38bd9cf9450 100644 (file)
@@ -359,19 +359,19 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
         bool follow_expected = false;
         Handle<Map> target;
         if (seq_one_byte) {
-          key = TransitionArray::ExpectedTransitionKey(map);
+          key = Map::ExpectedTransitionKey(map);
           follow_expected = !key.is_null() && ParseJsonString(key);
         }
         // If the expected transition hits, follow it.
         if (follow_expected) {
-          target = TransitionArray::ExpectedTransitionTarget(map);
+          target = Map::ExpectedTransitionTarget(map);
         } else {
           // If the expected transition failed, parse an internalized string and
           // try to find a matching transition.
           key = ParseJsonInternalizedString();
           if (key.is_null()) return ReportUnexpectedCharacter();
 
-          target = TransitionArray::FindTransitionToField(map, key);
+          target = Map::FindTransitionToField(map, key);
           // If a transition was found, follow it and continue.
           transitioning = !target.is_null();
         }
index b6353314b22c8695cbfa1d63350f27d11d4c1558..78a07c737e41a2553c1052c2e55a38ee002f073f 100644 (file)
@@ -320,8 +320,10 @@ void Map::MapVerify() {
   VerifyHeapPointer(prototype());
   VerifyHeapPointer(instance_descriptors());
   SLOW_DCHECK(instance_descriptors()->IsSortedNoDuplicates());
-  SLOW_DCHECK(TransitionArray::IsSortedNoDuplicates(this));
-  SLOW_DCHECK(TransitionArray::IsConsistentWithBackPointers(this));
+  if (HasTransitionArray()) {
+    SLOW_DCHECK(transitions()->IsSortedNoDuplicates());
+    SLOW_DCHECK(transitions()->IsConsistentWithBackPointers(this));
+  }
   // TODO(ishell): turn it back to SLOW_DCHECK.
   CHECK(!FLAG_unbox_double_fields ||
         layout_descriptor()->IsConsistentWithMap(this));
@@ -342,6 +344,7 @@ void Map::VerifyOmittedMapChecks() {
   if (!FLAG_omit_map_checks_for_leaf_maps) return;
   if (!is_stable() ||
       is_deprecated() ||
+      HasTransitionArray() ||
       is_dictionary_map()) {
     CHECK_EQ(0, dependent_code()->number_of_entries(
         DependentCode::kPrototypeCheckGroup));
@@ -1205,28 +1208,14 @@ bool TransitionArray::IsSortedNoDuplicates(int valid_entries) {
 }
 
 
-// static
-bool TransitionArray::IsSortedNoDuplicates(Map* map) {
-  Object* raw_transitions = map->raw_transitions();
-  if (IsFullTransitionArray(raw_transitions)) {
-    return TransitionArray::cast(raw_transitions)->IsSortedNoDuplicates();
-  }
-  // Simple and non-existent transitions are always sorted.
-  return true;
-}
-
-
 static bool CheckOneBackPointer(Map* current_map, Object* target) {
   return !target->IsMap() || Map::cast(target)->GetBackPointer() == current_map;
 }
 
 
-// static
-bool TransitionArray::IsConsistentWithBackPointers(Map* map) {
-  Object* transitions = map->raw_transitions();
-  for (int i = 0; i < TransitionArray::NumberOfTransitions(transitions); ++i) {
-    Map* target = TransitionArray::GetTarget(transitions, i);
-    if (!CheckOneBackPointer(map, target)) return false;
+bool TransitionArray::IsConsistentWithBackPointers(Map* current_map) {
+  for (int i = 0; i < number_of_transitions(); ++i) {
+    if (!CheckOneBackPointer(current_map, GetTarget(i))) return false;
   }
   return true;
 }
index 41bf13e265cc22f3d39b99983bf85b405f5efa53..a5b2b352d79174ac87f08b4f6bc2d6e5f349f3a9 100644 (file)
@@ -1877,6 +1877,41 @@ void JSObject::initialize_elements() {
 }
 
 
+Handle<String> Map::ExpectedTransitionKey(Handle<Map> map) {
+  DisallowHeapAllocation no_gc;
+  if (!map->HasTransitionArray()) return Handle<String>::null();
+  TransitionArray* transitions = map->transitions();
+  if (!transitions->IsSimpleTransition()) return Handle<String>::null();
+  int transition = TransitionArray::kSimpleTransitionIndex;
+  PropertyDetails details = transitions->GetTargetDetails(transition);
+  Name* name = transitions->GetKey(transition);
+  if (details.type() != DATA) return Handle<String>::null();
+  if (details.attributes() != NONE) return Handle<String>::null();
+  if (!name->IsString()) return Handle<String>::null();
+  return Handle<String>(String::cast(name));
+}
+
+
+Handle<Map> Map::ExpectedTransitionTarget(Handle<Map> map) {
+  DCHECK(!ExpectedTransitionKey(map).is_null());
+  return Handle<Map>(map->transitions()->GetTarget(
+      TransitionArray::kSimpleTransitionIndex));
+}
+
+
+Handle<Map> Map::FindTransitionToField(Handle<Map> map, Handle<Name> key) {
+  DisallowHeapAllocation no_allocation;
+  if (!map->HasTransitionArray()) return Handle<Map>::null();
+  TransitionArray* transitions = map->transitions();
+  int transition = transitions->Search(kData, *key, NONE);
+  if (transition == TransitionArray::kNotFound) return Handle<Map>::null();
+  PropertyDetails details = transitions->GetTargetDetails(transition);
+  if (details.type() != DATA) return Handle<Map>::null();
+  DCHECK_EQ(NONE, details.attributes());
+  return Handle<Map>(transitions->GetTarget(transition));
+}
+
+
 ACCESSORS(Oddball, to_string, String, kToStringOffset)
 ACCESSORS(Oddball, to_number, Object, kToNumberOffset)
 
@@ -3002,7 +3037,7 @@ FixedArrayBase* Map::GetInitialElements() {
     return empty_array;
   } else if (has_fixed_typed_array_elements()) {
     FixedTypedArrayBase* empty_array =
-        GetHeap()->EmptyFixedTypedArrayForMap(this);
+      GetHeap()->EmptyFixedTypedArrayForMap(this);
     DCHECK(!GetHeap()->InNewSpace(empty_array));
     return empty_array;
   } else {
@@ -5220,6 +5255,22 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) {
 }
 
 
+// If the descriptor is using the empty transition array, install a new empty
+// transition array that will have place for an element transition.
+static void EnsureHasTransitionArray(Handle<Map> map) {
+  Handle<TransitionArray> transitions;
+  if (!map->HasTransitionArray()) {
+    transitions = TransitionArray::Allocate(map->GetIsolate(), 0);
+    transitions->set_back_pointer_storage(map->GetBackPointer());
+  } else if (!map->transitions()->IsFullTransitionArray()) {
+    transitions = TransitionArray::ExtendToFullTransitionArray(map);
+  } else {
+    return;
+  }
+  map->set_transitions(*transitions);
+}
+
+
 LayoutDescriptor* Map::layout_descriptor_gc_safe() {
   Object* layout_desc = READ_FIELD(this, kLayoutDecriptorOffset);
   return LayoutDescriptor::cast_gc_safe(layout_desc);
@@ -5322,13 +5373,127 @@ Object* Map::GetBackPointer() {
 }
 
 
-Map* Map::ElementsTransitionMap() {
-  return TransitionArray::SearchSpecial(
-      this, GetHeap()->elements_transition_symbol());
+bool Map::HasElementsTransition() {
+  return HasTransitionArray() && transitions()->HasElementsTransition();
+}
+
+
+bool Map::HasTransitionArray() const {
+  Object* object = READ_FIELD(this, kTransitionsOffset);
+  return object->IsTransitionArray();
+}
+
+
+Map* Map::elements_transition_map() {
+  int index =
+      transitions()->SearchSpecial(GetHeap()->elements_transition_symbol());
+  return transitions()->GetTarget(index);
 }
 
 
-ACCESSORS(Map, raw_transitions, Object, kTransitionsOffset)
+bool Map::CanHaveMoreTransitions() {
+  if (!HasTransitionArray()) return true;
+  return transitions()->number_of_transitions() <
+         TransitionArray::kMaxNumberOfTransitions;
+}
+
+
+Map* Map::GetTransition(int transition_index) {
+  return transitions()->GetTarget(transition_index);
+}
+
+
+int Map::SearchSpecialTransition(Symbol* name) {
+  if (HasTransitionArray()) {
+    return transitions()->SearchSpecial(name);
+  }
+  return TransitionArray::kNotFound;
+}
+
+
+int Map::SearchTransition(PropertyKind kind, Name* name,
+                          PropertyAttributes attributes) {
+  if (HasTransitionArray()) {
+    return transitions()->Search(kind, name, attributes);
+  }
+  return TransitionArray::kNotFound;
+}
+
+
+FixedArray* Map::GetPrototypeTransitions() {
+  if (!HasTransitionArray()) return GetHeap()->empty_fixed_array();
+  if (!transitions()->HasPrototypeTransitions()) {
+    return GetHeap()->empty_fixed_array();
+  }
+  return transitions()->GetPrototypeTransitions();
+}
+
+
+void Map::SetPrototypeTransitions(
+    Handle<Map> map, Handle<FixedArray> proto_transitions) {
+  EnsureHasTransitionArray(map);
+  int old_number_of_transitions = map->NumberOfProtoTransitions();
+  if (Heap::ShouldZapGarbage() && map->HasPrototypeTransitions()) {
+    DCHECK(map->GetPrototypeTransitions() != *proto_transitions);
+    map->ZapPrototypeTransitions();
+  }
+  map->transitions()->SetPrototypeTransitions(*proto_transitions);
+  map->SetNumberOfProtoTransitions(old_number_of_transitions);
+}
+
+
+bool Map::HasPrototypeTransitions() {
+  return HasTransitionArray() && transitions()->HasPrototypeTransitions();
+}
+
+
+TransitionArray* Map::transitions() const {
+  DCHECK(HasTransitionArray());
+  Object* object = READ_FIELD(this, kTransitionsOffset);
+  return TransitionArray::cast(object);
+}
+
+
+void Map::set_transitions(TransitionArray* transition_array,
+                          WriteBarrierMode mode) {
+  // Transition arrays are not shared. When one is replaced, it should not
+  // keep referenced objects alive, so we zap it.
+  // When there is another reference to the array somewhere (e.g. a handle),
+  // not zapping turns from a waste of memory into a source of crashes.
+  if (HasTransitionArray()) {
+#ifdef DEBUG
+    for (int i = 0; i < transitions()->number_of_transitions(); i++) {
+      Map* target = transitions()->GetTarget(i);
+      if (target->instance_descriptors() == instance_descriptors()) {
+        Name* key = transitions()->GetKey(i);
+        int new_target_index;
+        if (TransitionArray::IsSpecialTransition(key)) {
+          new_target_index = transition_array->SearchSpecial(Symbol::cast(key));
+        } else {
+          PropertyDetails details =
+              TransitionArray::GetTargetDetails(key, target);
+          new_target_index = transition_array->Search(details.kind(), key,
+                                                      details.attributes());
+        }
+        DCHECK_NE(TransitionArray::kNotFound, new_target_index);
+        DCHECK_EQ(target, transition_array->GetTarget(new_target_index));
+      }
+    }
+#endif
+    DCHECK(transitions() != transition_array);
+    ZapTransitions();
+  }
+
+  WRITE_FIELD(this, kTransitionsOffset, transition_array);
+  CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kTransitionsOffset,
+                            transition_array, mode);
+}
+
+
+void Map::init_transitions(Object* undefined) {
+  DCHECK(undefined->IsUndefined());
+  WRITE_FIELD(this, kTransitionsOffset, undefined);
+}
 
 
 void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
@@ -5347,7 +5512,6 @@ ACCESSORS(Map, weak_cell_cache, Object, kWeakCellCacheOffset)
 ACCESSORS(Map, constructor_or_backpointer, Object,
           kConstructorOrBackPointerOffset)
 
-
 Object* Map::GetConstructor() const {
   Object* maybe_constructor = constructor_or_backpointer();
   // Follow any back pointers.
@@ -5357,15 +5521,12 @@ Object* Map::GetConstructor() const {
   }
   return maybe_constructor;
 }
-
-
 void Map::SetConstructor(Object* constructor, WriteBarrierMode mode) {
   // Never overwrite a back pointer with a constructor.
   DCHECK(!constructor_or_backpointer()->IsMap());
   set_constructor_or_backpointer(constructor, mode);
 }
 
-
 ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
 ACCESSORS(JSFunction, literals_or_bindings, FixedArray, kLiteralsOffset)
 ACCESSORS(JSFunction, next_function_link, Object, kNextFunctionLinkOffset)
index 1b31c1bfffe7a4408889e3527a0797e516c9ea63..3fd1579ba5212161202ffa803d4d6c3a9a72ba1a 100644 (file)
@@ -432,9 +432,8 @@ void Map::MapPrint(std::ostream& os) {  // NOLINT
   if (FLAG_unbox_double_fields) {
     os << "\n - layout descriptor: " << Brief(layout_descriptor());
   }
-  if (TransitionArray::NumberOfTransitions(raw_transitions()) > 0) {
-    os << "\n - transitions: ";
-    TransitionArray::PrintTransitions(os, raw_transitions());
+  if (HasTransitionArray()) {
+    os << "\n - transitions: " << Brief(transitions());
   }
   os << "\n - prototype: " << Brief(prototype());
   os << "\n - constructor: " << Brief(GetConstructor());
@@ -1139,20 +1138,19 @@ void DescriptorArray::PrintDescriptors(std::ostream& os) {  // NOLINT
 
 void TransitionArray::Print() {
   OFStream os(stdout);
-  TransitionArray::PrintTransitions(os, this);
+  this->PrintTransitions(os);
   os << std::flush;
 }
 
 
-void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions,
+void TransitionArray::PrintTransitions(std::ostream& os,
                                        bool print_header) {  // NOLINT
-  int num_transitions = NumberOfTransitions(transitions);
   if (print_header) {
-    os << "Transition array " << num_transitions << "\n";
+    os << "Transition array " << number_of_transitions() << "\n";
   }
-  for (int i = 0; i < num_transitions; i++) {
-    Name* key = GetKey(transitions, i);
-    Map* target = GetTarget(transitions, i);
+  for (int i = 0; i < number_of_transitions(); i++) {
+    Name* key = GetKey(i);
+    Map* target = GetTarget(i);
     os << "   ";
 #ifdef OBJECT_PRINT
     key->NamePrint(os);
@@ -1160,17 +1158,16 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions,
     key->ShortPrint(os);
 #endif
     os << ": ";
-    Heap* heap = key->GetHeap();
-    if (key == heap->nonextensible_symbol()) {
+    if (key == GetHeap()->nonextensible_symbol()) {
       os << " (transition to non-extensible)";
-    } else if (key == heap->sealed_symbol()) {
+    } else if (key == GetHeap()->sealed_symbol()) {
       os << " (transition to sealed)";
-    } else if (key == heap->frozen_symbol()) {
+    } else if (key == GetHeap()->frozen_symbol()) {
       os << " (transition to frozen)";
-    } else if (key == heap->elements_transition_symbol()) {
+    } else if (key == GetHeap()->elements_transition_symbol()) {
       os << " (transition to " << ElementsKindToString(target->elements_kind())
          << ")";
-    } else if (key == heap->observed_symbol()) {
+    } else if (key == GetHeap()->observed_symbol()) {
       os << " (transition to Object.observe)";
     } else {
       PropertyDetails details = GetTargetDetails(key, target);
@@ -1180,9 +1177,7 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions,
       }
       os << (details.kind() == kData ? "data" : "accessor");
       if (details.location() == kDescriptor) {
-        Object* value =
-            target->instance_descriptors()->GetValue(target->LastAdded());
-        os << " " << Brief(value);
+        os << " " << Brief(GetTargetValue(i));
       }
       os << "), attrs: " << details.attributes();
     }
@@ -1192,7 +1187,8 @@ void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions,
 
 
 void JSObject::PrintTransitions(std::ostream& os) {  // NOLINT
-  TransitionArray::PrintTransitions(os, map()->raw_transitions());
+  if (!map()->HasTransitionArray()) return;
+  map()->transitions()->PrintTransitions(os, false);
 }
 #endif  // defined(DEBUG) || defined(OBJECT_PRINT)
 } }  // namespace v8::internal
index ac7778f63c4c84af52f6240de7cb25bf6905b297..717a16a9cbe280125557d42d2191e967d18d5c5d 100644 (file)
@@ -1900,8 +1900,7 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
             old_map->GetHeap()->empty_descriptor_array(),
             LayoutDescriptor::FastPointerLayout());
         // Ensure that no transition was inserted for prototype migrations.
-        DCHECK_EQ(0, TransitionArray::NumberOfTransitions(
-                         old_map->raw_transitions()));
+        DCHECK(!old_map->HasTransitionArray());
         DCHECK(new_map->GetBackPointer()->IsUndefined());
       }
     } else {
@@ -2187,10 +2186,11 @@ Handle<Map> Map::CopyGeneralizeAllRepresentations(
 
 void Map::DeprecateTransitionTree() {
   if (is_deprecated()) return;
-  Object* transitions = raw_transitions();
-  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
-  for (int i = 0; i < num_transitions; ++i) {
-    TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
+  if (HasTransitionArray()) {
+    TransitionArray* transitions = this->transitions();
+    for (int i = 0; i < transitions->number_of_transitions(); i++) {
+      transitions->GetTarget(i)->DeprecateTransitionTree();
+    }
   }
   deprecate();
   dependent_code()->DeoptimizeDependentCodeGroup(
@@ -2215,11 +2215,13 @@ bool Map::DeprecateTarget(PropertyKind kind, Name* key,
                           DescriptorArray* new_descriptors,
                           LayoutDescriptor* new_layout_descriptor) {
   bool transition_target_deprecated = false;
-  Map* maybe_transition =
-      TransitionArray::SearchTransition(this, kind, key, attributes);
-  if (maybe_transition != NULL) {
-    maybe_transition->DeprecateTransitionTree();
-    transition_target_deprecated = true;
+  if (HasTransitionArray()) {
+    TransitionArray* transitions = this->transitions();
+    int transition = transitions->Search(kind, key, attributes);
+    if (transition != TransitionArray::kNotFound) {
+      transitions->GetTarget(transition)->DeprecateTransitionTree();
+      transition_target_deprecated = true;
+    }
   }
 
   // Don't overwrite the empty descriptor array.
@@ -2262,11 +2264,15 @@ Map* Map::FindLastMatchMap(int verbatim,
   Map* current = this;
 
   for (int i = verbatim; i < length; i++) {
+    if (!current->HasTransitionArray()) break;
     Name* name = descriptors->GetKey(i);
     PropertyDetails details = descriptors->GetDetails(i);
-    Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
-                                                  details.attributes());
-    if (next == NULL) break;
+    TransitionArray* transitions = current->transitions();
+    int transition =
+        transitions->Search(details.kind(), name, details.attributes());
+    if (transition == TransitionArray::kNotFound) break;
+
+    Map* next = transitions->GetTarget(transition);
     DescriptorArray* next_descriptors = next->instance_descriptors();
 
     PropertyDetails next_details = next_descriptors->GetDetails(i);
@@ -2314,12 +2320,12 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
   DisallowHeapAllocation no_allocation;
   PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
   if (details.type() != DATA) return;
-  Object* transitions = raw_transitions();
-  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
-  for (int i = 0; i < num_transitions; ++i) {
-    Map* target = TransitionArray::GetTarget(transitions, i);
-    target->UpdateFieldType(descriptor, name, new_representation,
-                            new_wrapped_type);
+  if (HasTransitionArray()) {
+    TransitionArray* transitions = this->transitions();
+    for (int i = 0; i < transitions->number_of_transitions(); ++i) {
+      transitions->GetTarget(i)->UpdateFieldType(
+          descriptor, name, new_representation, new_wrapped_type);
+    }
   }
   // It is allowed to change representation here only from None to something.
   DCHECK(details.representation().Equals(new_representation) ||
@@ -2559,11 +2565,10 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
       next_attributes = old_details.attributes();
       next_representation = old_details.representation();
     }
-    Map* transition = TransitionArray::SearchTransition(
-        *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
-    if (transition == NULL) break;
-    Handle<Map> tmp_map(transition, isolate);
-
+    int j = target_map->SearchTransition(next_kind, old_descriptors->GetKey(i),
+                                         next_attributes);
+    if (j == TransitionArray::kNotFound) break;
+    Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
     Handle<DescriptorArray> tmp_descriptors = handle(
         tmp_map->instance_descriptors(), isolate);
 
@@ -2648,10 +2653,10 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
       next_kind = old_details.kind();
       next_attributes = old_details.attributes();
     }
-    Map* transition = TransitionArray::SearchTransition(
-        *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
-    if (transition == NULL) break;
-    Handle<Map> tmp_map(transition, isolate);
+    int j = target_map->SearchTransition(next_kind, old_descriptors->GetKey(i),
+                                         next_attributes);
+    if (j == TransitionArray::kNotFound) break;
+    Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
     Handle<DescriptorArray> tmp_descriptors(
         tmp_map->instance_descriptors(), isolate);
 
@@ -2889,8 +2894,7 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
   // If |transition_target_deprecated| is true then the transition array
   // already contains entry for given descriptor. This means that the transition
   // could be inserted regardless of whether transitions array is full or not.
-  if (!transition_target_deprecated &&
-      !TransitionArray::CanHaveMoreTransitions(split_map)) {
+  if (!transition_target_deprecated && !split_map->CanHaveMoreTransitions()) {
     return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
                                             new_kind, new_attributes,
                                             "GenAll_CantHaveMoreTransitions");
@@ -2963,11 +2967,11 @@ MaybeHandle<Map> Map::TryUpdate(Handle<Map> old_map) {
   Map* new_map = root_map;
   for (int i = root_nof; i < old_nof; ++i) {
     PropertyDetails old_details = old_descriptors->GetDetails(i);
-    Map* transition = TransitionArray::SearchTransition(
-        new_map, old_details.kind(), old_descriptors->GetKey(i),
-        old_details.attributes());
-    if (transition == NULL) return MaybeHandle<Map>();
-    new_map = transition;
+    int j = new_map->SearchTransition(old_details.kind(),
+                                      old_descriptors->GetKey(i),
+                                      old_details.attributes());
+    if (j == TransitionArray::kNotFound) return MaybeHandle<Map>();
+    new_map = new_map->GetTransition(j);
     DescriptorArray* new_descriptors = new_map->instance_descriptors();
 
     PropertyDetails new_details = new_descriptors->GetDetails(i);
@@ -3609,9 +3613,9 @@ static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
   // have the cached transition.
   if (IsExternalArrayElementsKind(to_kind) &&
       !IsFixedTypedArrayElementsKind(map->elements_kind())) {
-    Map* next_map = map->ElementsTransitionMap();
-    if (next_map != NULL && next_map->elements_kind() == to_kind) {
-      return next_map;
+    if (map->HasElementsTransition()) {
+        Map* next_map = map->elements_transition_map();
+        if (next_map->elements_kind() == to_kind) return next_map;
     }
     return map;
   }
@@ -3619,14 +3623,13 @@ static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
   ElementsKind kind = map->elements_kind();
   while (kind != target_kind) {
     kind = GetNextTransitionElementsKind(kind);
-    Map* next_map = current_map->ElementsTransitionMap();
-    if (next_map == NULL) return current_map;
-    current_map = next_map;
+    if (!current_map->HasElementsTransition()) return current_map;
+    current_map = current_map->elements_transition_map();
   }
 
-  Map* next_map = current_map->ElementsTransitionMap();
-  if (to_kind != kind && next_map != NULL) {
+  if (to_kind != kind && current_map->HasElementsTransition()) {
     DCHECK(to_kind == DICTIONARY_ELEMENTS);
+    Map* next_map = current_map->elements_transition_map();
     if (next_map->elements_kind() == to_kind) return next_map;
   }
 
@@ -5726,15 +5729,13 @@ MaybeHandle<Object> JSObject::PreventExtensionsWithTransition(
   }
 
   Handle<Map> old_map(object->map(), isolate);
-  Map* transition =
-      TransitionArray::SearchSpecial(*old_map, *transition_marker);
-  if (transition != NULL) {
-    Handle<Map> transition_map(transition, isolate);
+  int transition_index = old_map->SearchSpecialTransition(*transition_marker);
+  if (transition_index != TransitionArray::kNotFound) {
+    Handle<Map> transition_map(old_map->GetTransition(transition_index));
     DCHECK(transition_map->has_dictionary_elements());
     DCHECK(!transition_map->is_extensible());
     JSObject::MigrateToMap(object, transition_map);
-  } else if (object->HasFastProperties() &&
-             TransitionArray::CanHaveMoreTransitions(old_map)) {
+  } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
     // Create a new descriptor array with the appropriate property attributes
     Handle<Map> new_map = Map::CopyForPreventExtensions(
         old_map, attrs, transition_marker, "CopyForPreventExtensions");
@@ -5793,13 +5794,12 @@ void JSObject::SetObserved(Handle<JSObject> object) {
   Handle<Map> new_map;
   Handle<Map> old_map(object->map(), isolate);
   DCHECK(!old_map->is_observed());
-  Map* transition = TransitionArray::SearchSpecial(
-      *old_map, isolate->heap()->observed_symbol());
-  if (transition != NULL) {
-    new_map = handle(transition, isolate);
+  int transition_index =
+      old_map->SearchSpecialTransition(isolate->heap()->observed_symbol());
+  if (transition_index != TransitionArray::kNotFound) {
+    new_map = handle(old_map->GetTransition(transition_index), isolate);
     DCHECK(new_map->is_observed());
-  } else if (object->HasFastProperties() &&
-             TransitionArray::CanHaveMoreTransitions(old_map)) {
+  } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
     new_map = Map::CopyForObserved(old_map);
   } else {
     new_map = Map::Copy(old_map, "SlowObserved");
@@ -7018,12 +7018,11 @@ void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
 
 // static
 void Map::TraceAllTransitions(Map* map) {
-  Object* transitions = map->raw_transitions();
-  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
-  for (int i = -0; i < num_transitions; ++i) {
-    Map* target = TransitionArray::GetTarget(transitions, i);
-    Name* key = TransitionArray::GetKey(transitions, i);
-    Map::TraceTransition("Transition", map, target, key);
+  if (!map->HasTransitionArray()) return;
+  TransitionArray* transitions = map->transitions();
+  for (int i = 0; i < transitions->number_of_transitions(); ++i) {
+    Map* target = transitions->GetTarget(i);
+    Map::TraceTransition("Transition", map, target, transitions->GetKey(i));
     Map::TraceAllTransitions(target);
   }
 }
@@ -7040,7 +7039,13 @@ void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
     Map::TraceTransition("NoTransition", *parent, *child, *name);
 #endif
   } else {
-    TransitionArray::Insert(parent, name, child, flag);
+    Handle<TransitionArray> transitions =
+        TransitionArray::Insert(parent, name, child, flag);
+    if (!parent->HasTransitionArray() ||
+        *transitions != parent->transitions()) {
+      parent->set_transitions(*transitions);
+    }
+    child->SetBackPointer(*parent);
     if (child->prototype()->IsJSObject()) {
       Handle<JSObject> proto(JSObject::cast(child->prototype()));
       if (!child->ShouldRegisterAsPrototypeUser(proto)) {
@@ -7064,8 +7069,7 @@ Handle<Map> Map::CopyReplaceDescriptors(
   Handle<Map> result = CopyDropDescriptors(map);
 
   if (!map->is_prototype_map()) {
-    if (flag == INSERT_TRANSITION &&
-        TransitionArray::CanHaveMoreTransitions(map)) {
+    if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) {
       result->InitializeDescriptors(*descriptors, *layout_descriptor);
 
       Handle<Name> name;
@@ -7089,8 +7093,7 @@ Handle<Map> Map::CopyReplaceDescriptors(
   if (FLAG_trace_maps &&
       // Mirror conditions above that did not call ConnectTransition().
       (map->is_prototype_map() ||
-       !(flag == INSERT_TRANSITION &&
-         TransitionArray::CanHaveMoreTransitions(map)))) {
+       !(flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()))) {
     PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
            reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
            reason);
@@ -7148,24 +7151,22 @@ Handle<Map> Map::CopyInstallDescriptors(
 
 Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
                                     TransitionFlag flag) {
-  Map* maybe_elements_transition_map = NULL;
   if (flag == INSERT_TRANSITION) {
-    maybe_elements_transition_map = map->ElementsTransitionMap();
-    DCHECK(
-        maybe_elements_transition_map == NULL ||
-        ((maybe_elements_transition_map->elements_kind() ==
-              DICTIONARY_ELEMENTS ||
+    DCHECK(!map->HasElementsTransition() ||
+        ((map->elements_transition_map()->elements_kind() ==
+          DICTIONARY_ELEMENTS ||
           IsExternalArrayElementsKind(
-              maybe_elements_transition_map->elements_kind())) &&
-         (kind == DICTIONARY_ELEMENTS || IsExternalArrayElementsKind(kind))));
+              map->elements_transition_map()->elements_kind())) &&
+         (kind == DICTIONARY_ELEMENTS ||
+          IsExternalArrayElementsKind(kind))));
     DCHECK(!IsFastElementsKind(kind) ||
            IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
     DCHECK(kind != map->elements_kind());
   }
 
   bool insert_transition = flag == INSERT_TRANSITION &&
-                           TransitionArray::CanHaveMoreTransitions(map) &&
-                           maybe_elements_transition_map == NULL;
+                           map->CanHaveMoreTransitions() &&
+                           !map->HasElementsTransition();
 
   if (insert_transition) {
     Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
@@ -7189,7 +7190,7 @@ Handle<Map> Map::CopyForObserved(Handle<Map> map) {
   Isolate* isolate = map->GetIsolate();
 
   bool insert_transition =
-      TransitionArray::CanHaveMoreTransitions(map) && !map->is_prototype_map();
+      map->CanHaveMoreTransitions() && !map->is_prototype_map();
 
   if (insert_transition) {
     Handle<Map> new_map = CopyForTransition(map, "CopyForObserved");
@@ -7355,10 +7356,9 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
   // Migrate to the newest map before storing the property.
   map = Update(map);
 
-  Map* maybe_transition =
-      TransitionArray::SearchTransition(*map, kData, *name, attributes);
-  if (maybe_transition != NULL) {
-    Handle<Map> transition(maybe_transition);
+  int index = map->SearchTransition(kData, *name, attributes);
+  if (index != TransitionArray::kNotFound) {
+    Handle<Map> transition(map->GetTransition(index));
     int descriptor = transition->LastAdded();
 
     DCHECK_EQ(attributes, transition->instance_descriptors()
@@ -7447,10 +7447,9 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
                                        ? KEEP_INOBJECT_PROPERTIES
                                        : CLEAR_INOBJECT_PROPERTIES;
 
-  Map* maybe_transition =
-      TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
-  if (maybe_transition != NULL) {
-    Handle<Map> transition(maybe_transition, isolate);
+  int index = map->SearchTransition(kAccessor, *name, attributes);
+  if (index != TransitionArray::kNotFound) {
+    Handle<Map> transition(map->GetTransition(index));
     DescriptorArray* descriptors = transition->instance_descriptors();
     int descriptor = transition->LastAdded();
     DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
@@ -7522,8 +7521,9 @@ Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
   // Ensure the key is unique.
   descriptor->KeyToUniqueName();
 
-  if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
-      TransitionArray::CanHaveMoreTransitions(map)) {
+  if (flag == INSERT_TRANSITION &&
+      map->owns_descriptors() &&
+      map->CanHaveMoreTransitions()) {
     return ShareDescriptor(map, descriptors, descriptor);
   }
 
@@ -7687,6 +7687,38 @@ void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
 }
 
 
+static void TraverseTransitionTreeInternal(Map* map,
+                                           Map::TraverseCallback callback,
+                                           void* data) {
+  if (map->HasTransitionArray()) {
+    TransitionArray* transitions = map->transitions();
+    if (transitions->HasPrototypeTransitions()) {
+      FixedArray* proto_trans = transitions->GetPrototypeTransitions();
+      Object* num_obj =
+          proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
+      int num = Smi::cast(num_obj)->value();
+      for (int i = 0; i < num; ++i) {
+        int index = Map::kProtoTransitionHeaderSize + i;
+        TraverseTransitionTreeInternal(Map::cast(proto_trans->get(index)),
+                                       callback, data);
+      }
+    }
+    for (int i = 0; i < transitions->number_of_transitions(); ++i) {
+      TraverseTransitionTreeInternal(transitions->GetTarget(i), callback, data);
+    }
+  }
+  callback(map, data);
+}
+
+
+// Traverse the transition tree in postorder.
+void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
+  // Make sure that we do not allocate in the callback.
+  DisallowHeapAllocation no_allocation;
+  TraverseTransitionTreeInternal(this, callback, data);
+}
+
+
 void CodeCache::Update(
     Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
   // The number of monomorphic stubs for normal load/store/call IC's can grow to
@@ -9860,10 +9892,10 @@ void JSFunction::CompleteInobjectSlackTracking() {
   map->set_counter(Map::kRetainingCounterStart);
 
   int slack = map->unused_property_fields();
-  TransitionArray::TraverseTransitionTree(map, &GetMinInobjectSlack, &slack);
+  map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
   if (slack != 0) {
     // Resize the initial map and all maps in its transition tree.
-    TransitionArray::TraverseTransitionTree(map, &ShrinkInstanceSize, &slack);
+    map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
   }
 }
 
@@ -10016,9 +10048,8 @@ Handle<Object> CacheInitialJSArrayMaps(
        i < kFastElementsKindCount; ++i) {
     Handle<Map> new_map;
     ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
-    Map* maybe_elements_transition = current_map->ElementsTransitionMap();
-    if (maybe_elements_transition != NULL) {
-      new_map = handle(maybe_elements_transition);
+    if (current_map->HasElementsTransition()) {
+      new_map = handle(current_map->elements_transition_map());
       DCHECK(new_map->elements_kind() == next_kind);
     } else {
       new_map = Map::CopyAsElementsKind(
@@ -11939,6 +11970,77 @@ MaybeHandle<Object> JSArray::SetElementsLength(
 }
 
 
+Handle<Map> Map::GetPrototypeTransition(Handle<Map> map,
+                                        Handle<Object> prototype) {
+  DisallowHeapAllocation no_gc;
+  FixedArray* cache = map->GetPrototypeTransitions();
+  int number_of_transitions = map->NumberOfProtoTransitions();
+  for (int i = 0; i < number_of_transitions; i++) {
+    Map* map = Map::cast(cache->get(kProtoTransitionHeaderSize + i));
+    if (map->prototype() == *prototype) return handle(map);
+  }
+  return Handle<Map>();
+}
+
+
+Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
+                                        Handle<Object> prototype,
+                                        Handle<Map> target_map) {
+  DCHECK(target_map->IsMap());
+  DCHECK(HeapObject::cast(*prototype)->map()->IsMap());
+  // Don't cache prototype transition if this map is either shared, or a map of
+  // a prototype.
+  if (map->is_prototype_map()) return map;
+  if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map;
+
+  const int header = kProtoTransitionHeaderSize;
+
+  Handle<FixedArray> cache(map->GetPrototypeTransitions());
+  int capacity = cache->length() - header;
+  int transitions = map->NumberOfProtoTransitions() + 1;
+
+  if (transitions > capacity) {
+    // Grow array by factor 2 up to MaxCachedPrototypeTransitions.
+    int new_capacity = Min(kMaxCachedPrototypeTransitions, transitions * 2);
+    if (new_capacity == capacity) return map;
+
+    cache = FixedArray::CopySize(cache, header + new_capacity);
+
+    SetPrototypeTransitions(map, cache);
+  }
+
+  // Reload number of transitions as GC might shrink them.
+  int last = map->NumberOfProtoTransitions();
+  int entry = header + last;
+
+  cache->set(entry, *target_map);
+  map->SetNumberOfProtoTransitions(last + 1);
+
+  return map;
+}
+
+
+void Map::ZapTransitions() {
+  TransitionArray* transition_array = transitions();
+  // TODO(mstarzinger): Temporarily use a slower version instead of the faster
+  // MemsetPointer to investigate a crasher. Switch back to MemsetPointer.
+  Object** data = transition_array->data_start();
+  Object* the_hole = GetHeap()->the_hole_value();
+  int length = transition_array->length();
+  for (int i = 0; i < length; i++) {
+    data[i] = the_hole;
+  }
+}
+
+
+void Map::ZapPrototypeTransitions() {
+  FixedArray* proto_transitions = GetPrototypeTransitions();
+  MemsetPointer(proto_transitions->data_start(),
+                GetHeap()->the_hole_value(),
+                proto_transitions->length());
+}
+
+
 // static
 void Map::AddDependentCompilationInfo(Handle<Map> map,
                                       DependentCode::DependencyGroup group,
@@ -12244,10 +12346,10 @@ const char* DependentCode::DependencyGroupName(DependencyGroup group) {
 Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
                                        Handle<Object> prototype,
                                        PrototypeOptimizationMode mode) {
-  Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
+  Handle<Map> new_map = GetPrototypeTransition(map, prototype);
   if (new_map.is_null()) {
     new_map = Copy(map, "TransitionToPrototype");
-    TransitionArray::PutPrototypeTransition(map, prototype, new_map);
+    PutPrototypeTransition(map, prototype, new_map);
     new_map->SetPrototype(prototype, mode);
   }
   return new_map;
index 9a553fd3770e3ac1be4aec6192f1835dee306670..8ddcd8b04fc7a8d0cf4171f598cf2ba50ecfc65f 100644 (file)
@@ -5869,11 +5869,26 @@ class Map: public HeapObject {
   // map with DICTIONARY_ELEMENTS was found in the prototype chain.
   bool DictionaryElementsInPrototypeChainOnly();
 
-  inline Map* ElementsTransitionMap();
+  inline bool HasTransitionArray() const;
+  inline bool HasElementsTransition();
+  inline Map* elements_transition_map();
 
+  inline Map* GetTransition(int transition_index);
+  inline int SearchSpecialTransition(Symbol* name);
+  inline int SearchTransition(PropertyKind kind, Name* name,
+                              PropertyAttributes attributes);
   inline FixedArrayBase* GetInitialElements();
 
-  DECL_ACCESSORS(raw_transitions, Object)
+  DECL_ACCESSORS(transitions, TransitionArray)
+  inline void init_transitions(Object* undefined);
+
+  static inline Handle<String> ExpectedTransitionKey(Handle<Map> map);
+  static inline Handle<Map> ExpectedTransitionTarget(Handle<Map> map);
+
+  // Try to follow an existing transition to a field with attributes NONE. The
+  // return value indicates whether the transition was successful.
+  static inline Handle<Map> FindTransitionToField(Handle<Map> map,
+                                                  Handle<Name> key);
 
   Map* FindRootMap();
   Map* FindFieldOwner(int descriptor);
@@ -5947,8 +5962,6 @@ class Map: public HeapObject {
   inline Object* GetConstructor() const;
   inline void SetConstructor(Object* constructor,
                              WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
-  // [back pointer]: points back to the parent map from which a transition
-  // leads to this map. The field overlaps with the constructor (see above).
   inline Object* GetBackPointer();
   inline void SetBackPointer(Object* value,
                              WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
@@ -5981,8 +5994,38 @@ class Map: public HeapObject {
   // [weak cell cache]: cache that stores a weak cell pointing to this map.
   DECL_ACCESSORS(weak_cell_cache, Object)
 
+  // [prototype transitions]: cache of prototype transitions.
+  // Prototype transition is a transition that happens
+  // when we change object's prototype to a new one.
+  // Cache format:
+  //    0: finger - index of the first free cell in the cache
+  //    1 + i: target map
+  inline FixedArray* GetPrototypeTransitions();
+  inline bool HasPrototypeTransitions();
+
+  static const int kProtoTransitionNumberOfEntriesOffset = 0;
+  static const int kProtoTransitionHeaderSize = 1;
+
+  inline int NumberOfProtoTransitions() {
+    FixedArray* cache = GetPrototypeTransitions();
+    if (cache->length() == 0) return 0;
+    return
+        Smi::cast(cache->get(kProtoTransitionNumberOfEntriesOffset))->value();
+  }
+
+  inline void SetNumberOfProtoTransitions(int value) {
+    FixedArray* cache = GetPrototypeTransitions();
+    DCHECK(cache->length() != 0);
+    cache->set(kProtoTransitionNumberOfEntriesOffset, Smi::FromInt(value));
+  }
+
   inline PropertyDetails GetLastDescriptorDetails();
 
+  // The size of transition arrays are limited so they do not end up in large
+  // object space. Otherwise ClearNonLiveTransitions would leak memory while
+  // applying in-place right trimming.
+  inline bool CanHaveMoreTransitions();
+
   int LastAdded() {
     int number_of_own_descriptors = NumberOfOwnDescriptors();
     DCHECK(number_of_own_descriptors > 0);
@@ -6150,6 +6193,11 @@ class Map: public HeapObject {
   // Removes a code object from the code cache at the given index.
   void RemoveFromCodeCache(Name* name, Code* code, int index);
 
+  // Set all map transitions from this map to dead maps to null.  Also clear
+  // back pointers in transition targets so that we do not process this map
+  // again while following back pointers.
+  void ClearNonLiveTransitions(Heap* heap);
+
   // Computes a hash value for this map, to be used in HashTables and such.
   int Hash();
 
@@ -6215,6 +6263,18 @@ class Map: public HeapObject {
   inline int visitor_id();
   inline void set_visitor_id(int visitor_id);
 
+  typedef void (*TraverseCallback)(Map* map, void* data);
+
+  void TraverseTransitionTree(TraverseCallback callback, void* data);
+
+  // When you set the prototype of an object using the __proto__ accessor you
+  // need a new map for the object (the prototype is stored in the map).  In
+  // order not to multiply maps unnecessarily we store these as transitions in
+  // the original map.  That way we can transition to the same map if the same
+  // prototype is set, rather than creating a new map every time.  The
+  // transitions are in the form of a map where the keys are prototype objects
+  // and the values are the maps they transition to.
+  static const int kMaxCachedPrototypeTransitions = 256;
   static Handle<Map> TransitionToPrototype(Handle<Map> map,
                                            Handle<Object> prototype,
                                            PrototypeOptimizationMode mode);
@@ -6228,10 +6288,6 @@ class Map: public HeapObject {
   static const int kPrototypeOffset = kBitField3Offset + kPointerSize;
   static const int kConstructorOrBackPointerOffset =
       kPrototypeOffset + kPointerSize;
-  // When there is only one transition, it is stored directly in this field;
-  // otherwise a transition array is used.
-  // For prototype maps, this slot is used to store a pointer to the prototype
-  // object using this map.
   static const int kTransitionsOffset =
       kConstructorOrBackPointerOffset + kPointerSize;
   static const int kDescriptorsOffset = kTransitionsOffset + kPointerSize;
@@ -6374,6 +6430,15 @@ class Map: public HeapObject {
   static Handle<Map> TransitionElementsToSlow(Handle<Map> object,
                                               ElementsKind to_kind);
 
+  // Zaps the contents of backing data structures. Note that the
+  // heap verifier (i.e. VerifyMarkingVisitor) relies on zapping of objects
+  // holding weak references when incremental marking is used, because it also
+  // iterates over objects that are otherwise unreachable.
+  // In general we only want to call these functions in release mode when
+  // heap verification is turned on.
+  void ZapPrototypeTransitions();
+  void ZapTransitions();
+
   void DeprecateTransitionTree();
   bool DeprecateTarget(PropertyKind kind, Name* key,
                        PropertyAttributes attributes,
@@ -6402,6 +6467,16 @@ class Map: public HeapObject {
                            HeapType* old_field_type,
                            HeapType* new_field_type);
 
+  static inline void SetPrototypeTransitions(
+      Handle<Map> map,
+      Handle<FixedArray> prototype_transitions);
+
+  static Handle<Map> GetPrototypeTransition(Handle<Map> map,
+                                            Handle<Object> prototype);
+  static Handle<Map> PutPrototypeTransition(Handle<Map> map,
+                                            Handle<Object> prototype,
+                                            Handle<Map> target_map);
+
   static const int kFastPropertiesSoftLimit = 12;
   static const int kMaxFastProperties = 128;
 
index f31eff96ba19e6e8e1dca0f1a4b3ee0c7c654a53..fd8eb8b0b652a463365591b3a0b7a9f00e3bb9a4 100644 (file)
@@ -11,19 +11,55 @@ namespace v8 {
 namespace internal {
 
 
+#define FIELD_ADDR(p, offset) \
+  (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
+
+#define WRITE_FIELD(p, offset, value) \
+  (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value)
+
+#define CONDITIONAL_WRITE_BARRIER(heap, object, offset, value, mode)    \
+  if (mode == UPDATE_WRITE_BARRIER) {                                   \
+    heap->incremental_marking()->RecordWrite(                           \
+      object, HeapObject::RawField(object, offset), value);             \
+    if (heap->InNewSpace(value)) {                                      \
+      heap->RecordWrite(object->address(), offset);                     \
+    }                                                                   \
+  }
+
+
 TransitionArray* TransitionArray::cast(Object* object) {
   DCHECK(object->IsTransitionArray());
   return reinterpret_cast<TransitionArray*>(object);
 }
 
 
+bool TransitionArray::HasElementsTransition() {
+  return SearchSpecial(GetHeap()->elements_transition_symbol()) != kNotFound;
+}
+
+
+Object* TransitionArray::back_pointer_storage() {
+  return get(kBackPointerStorageIndex);
+}
+
+
+void TransitionArray::set_back_pointer_storage(Object* back_pointer,
+                                               WriteBarrierMode mode) {
+  Heap* heap = GetHeap();
+  WRITE_FIELD(this, kBackPointerStorageOffset, back_pointer);
+  CONDITIONAL_WRITE_BARRIER(
+      heap, this, kBackPointerStorageOffset, back_pointer, mode);
+}
+
+
 bool TransitionArray::HasPrototypeTransitions() {
-  return get(kPrototypeTransitionsIndex) != Smi::FromInt(0);
+  return IsFullTransitionArray() &&
+      get(kPrototypeTransitionsIndex) != Smi::FromInt(0);
 }
 
 
 FixedArray* TransitionArray::GetPrototypeTransitions() {
-  DCHECK(HasPrototypeTransitions());  // Callers must check first.
+  DCHECK(IsFullTransitionArray());
   Object* prototype_transitions = get(kPrototypeTransitionsIndex);
   return FixedArray::cast(prototype_transitions);
 }
@@ -31,68 +67,88 @@ FixedArray* TransitionArray::GetPrototypeTransitions() {
 
 void TransitionArray::SetPrototypeTransitions(FixedArray* transitions,
                                               WriteBarrierMode mode) {
+  DCHECK(IsFullTransitionArray());
   DCHECK(transitions->IsFixedArray());
-  set(kPrototypeTransitionsIndex, transitions, mode);
+  Heap* heap = GetHeap();
+  WRITE_FIELD(this, kPrototypeTransitionsOffset, transitions);
+  CONDITIONAL_WRITE_BARRIER(
+      heap, this, kPrototypeTransitionsOffset, transitions, mode);
 }
 
 
 Object** TransitionArray::GetPrototypeTransitionsSlot() {
-  return RawFieldOfElementAt(kPrototypeTransitionsIndex);
+  return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
+                              kPrototypeTransitionsOffset);
 }
 
 
 Object** TransitionArray::GetKeySlot(int transition_number) {
+  DCHECK(!IsSimpleTransition());
   DCHECK(transition_number < number_of_transitions());
   return RawFieldOfElementAt(ToKeyIndex(transition_number));
 }
 
 
 Name* TransitionArray::GetKey(int transition_number) {
+  if (IsSimpleTransition()) {
+    Map* target = GetTarget(kSimpleTransitionIndex);
+    int descriptor = target->LastAdded();
+    Name* key = target->instance_descriptors()->GetKey(descriptor);
+    return key;
+  }
   DCHECK(transition_number < number_of_transitions());
   return Name::cast(get(ToKeyIndex(transition_number)));
 }
 
 
-Name* TransitionArray::GetKey(Object* raw_transitions, int transition_number) {
-  if (IsSimpleTransition(raw_transitions)) {
-    DCHECK(transition_number == 0);
-    return GetSimpleTransitionKey(GetSimpleTransition(raw_transitions));
-  }
-  DCHECK(IsFullTransitionArray(raw_transitions));
-  return TransitionArray::cast(raw_transitions)->GetKey(transition_number);
-}
-
-
 void TransitionArray::SetKey(int transition_number, Name* key) {
+  DCHECK(!IsSimpleTransition());
   DCHECK(transition_number < number_of_transitions());
   set(ToKeyIndex(transition_number), key);
 }
 
 
 Map* TransitionArray::GetTarget(int transition_number) {
+  if (IsSimpleTransition()) {
+    DCHECK(transition_number == kSimpleTransitionIndex);
+    return Map::cast(get(kSimpleTransitionTarget));
+  }
   DCHECK(transition_number < number_of_transitions());
   return Map::cast(get(ToTargetIndex(transition_number)));
 }
 
 
-Map* TransitionArray::GetTarget(Object* raw_transitions,
-                                int transition_number) {
-  if (IsSimpleTransition(raw_transitions)) {
-    DCHECK(transition_number == 0);
-    return GetSimpleTransition(raw_transitions);
+void TransitionArray::SetTarget(int transition_number, Map* value) {
+  if (IsSimpleTransition()) {
+    DCHECK(transition_number == kSimpleTransitionIndex);
+    return set(kSimpleTransitionTarget, value);
   }
-  DCHECK(IsFullTransitionArray(raw_transitions));
-  return TransitionArray::cast(raw_transitions)->GetTarget(transition_number);
+  DCHECK(transition_number < number_of_transitions());
+  set(ToTargetIndex(transition_number), value);
 }
 
 
-void TransitionArray::SetTarget(int transition_number, Map* value) {
-  DCHECK(transition_number < number_of_transitions());
-  set(ToTargetIndex(transition_number), value);
+PropertyDetails TransitionArray::GetTargetDetails(int transition_number) {
+  Map* map = GetTarget(transition_number);
+  return map->GetLastDescriptorDetails();
+}
+
+
+Object* TransitionArray::GetTargetValue(int transition_number) {
+  Map* map = GetTarget(transition_number);
+  return map->instance_descriptors()->GetValue(map->LastAdded());
 }
 
 
 int TransitionArray::SearchName(Name* name, int* out_insertion_index) {
+  if (IsSimpleTransition()) {
+    Name* key = GetKey(kSimpleTransitionIndex);
+    if (key->Equals(name)) return kSimpleTransitionIndex;
+    if (out_insertion_index != NULL) {
+      *out_insertion_index = key->Hash() > name->Hash() ? 0 : 1;
+    }
+    return kNotFound;
+  }
   return internal::Search<ALL_ENTRIES>(this, name, 0, out_insertion_index);
 }
 
@@ -169,10 +225,19 @@ void TransitionArray::NoIncrementalWriteBarrierSet(int transition_number,
 
 
 void TransitionArray::SetNumberOfTransitions(int number_of_transitions) {
-  DCHECK(number_of_transitions <= Capacity(this));
-  set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
+  if (IsFullTransitionArray()) {
+    DCHECK(number_of_transitions <= number_of_transitions_storage());
+    WRITE_FIELD(this, kTransitionLengthOffset,
+                Smi::FromInt(number_of_transitions));
+  }
 }
 
+
+#undef FIELD_ADDR
+#undef WRITE_FIELD
+#undef CONDITIONAL_WRITE_BARRIER
+
+
 } }  // namespace v8::internal
 
 #endif  // V8_TRANSITIONS_INL_H_
index 6154b4c1e10db478fc58186d4a396f2e4c5038c3..43fc90b1b51796ddd8c96fd478f902ea822c8a3a 100644 (file)
@@ -12,110 +12,141 @@ namespace v8 {
 namespace internal {
 
 
-// static
-void TransitionArray::Insert(Handle<Map> map, Handle<Name> name,
-                             Handle<Map> target, SimpleTransitionFlag flag) {
-  Isolate* isolate = map->GetIsolate();
-  target->SetBackPointer(*map);
-
-  // If the map doesn't have any transitions at all yet, install the new one.
-  if (CanStoreSimpleTransition(map->raw_transitions())) {
-    if (flag == SIMPLE_PROPERTY_TRANSITION) {
-      Handle<WeakCell> cell = Map::WeakCellForMap(target);
-      map->set_raw_transitions(*cell);
-      return;
-    }
-    // If the flag requires a full TransitionArray, allocate one.
-    Handle<TransitionArray> result = Allocate(isolate, 0, 1);
-    map->set_raw_transitions(*result);
+Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
+                                                  int number_of_transitions,
+                                                  int slack) {
+  Handle<FixedArray> array = isolate->factory()->NewFixedArray(
+      LengthFor(number_of_transitions + slack));
+  array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
+  array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
+  return Handle<TransitionArray>::cast(array);
+}
+
+
+Handle<TransitionArray> TransitionArray::AllocateSimple(Isolate* isolate,
+                                                        Handle<Map> target) {
+  Handle<FixedArray> array =
+      isolate->factory()->NewFixedArray(kSimpleTransitionSize);
+  array->set(kSimpleTransitionTarget, *target);
+  return Handle<TransitionArray>::cast(array);
+}
+
+
+void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin,
+                                                        int origin_transition,
+                                                        int target_transition) {
+  NoIncrementalWriteBarrierSet(target_transition,
+                               origin->GetKey(origin_transition),
+                               origin->GetTarget(origin_transition));
+}
+
+
+Handle<TransitionArray> TransitionArray::NewWith(Handle<Map> map,
+                                                 Handle<Name> name,
+                                                 Handle<Map> target,
+                                                 SimpleTransitionFlag flag) {
+  Handle<TransitionArray> result;
+  Isolate* isolate = name->GetIsolate();
+
+  if (flag == SIMPLE_PROPERTY_TRANSITION) {
+    result = AllocateSimple(isolate, target);
+  } else {
+    result = Allocate(isolate, 1);
+    result->NoIncrementalWriteBarrierSet(0, *name, *target);
   }
+  result->set_back_pointer_storage(map->GetBackPointer());
+  return result;
+}
 
-  bool is_special_transition = flag == SPECIAL_TRANSITION;
-  // If the map has a simple transition, check if it should be overwritten.
-  if (IsSimpleTransition(map->raw_transitions())) {
-    Map* old_target = GetSimpleTransition(map->raw_transitions());
-    Name* key = GetSimpleTransitionKey(old_target);
-    PropertyDetails old_details = GetSimpleTargetDetails(old_target);
-    PropertyDetails new_details = is_special_transition
-                                      ? PropertyDetails(NONE, DATA, 0)
-                                      : GetTargetDetails(*name, *target);
-    if (flag == SIMPLE_PROPERTY_TRANSITION && key->Equals(*name) &&
-        old_details.kind() == new_details.kind() &&
-        old_details.attributes() == new_details.attributes()) {
-      Handle<WeakCell> cell = Map::WeakCellForMap(target);
-      map->set_raw_transitions(*cell);
-      return;
-    }
-    // Otherwise allocate a full TransitionArray with slack for a new entry.
-    Handle<TransitionArray> result = Allocate(isolate, 1, 1);
-    // Re-read existing data; the allocation might have caused it to be cleared.
-    if (IsSimpleTransition(map->raw_transitions())) {
-      old_target = GetSimpleTransition(map->raw_transitions());
-      result->NoIncrementalWriteBarrierSet(
-          0, GetSimpleTransitionKey(old_target), old_target);
-    } else {
-      result->SetNumberOfTransitions(0);
-    }
-    map->set_raw_transitions(*result);
+
+Handle<TransitionArray> TransitionArray::ExtendToFullTransitionArray(
+    Handle<Map> containing_map) {
+  DCHECK(!containing_map->transitions()->IsFullTransitionArray());
+  int nof = containing_map->transitions()->number_of_transitions();
+
+  // A transition array may shrink during GC.
+  Handle<TransitionArray> result = Allocate(containing_map->GetIsolate(), nof);
+  DisallowHeapAllocation no_gc;
+  int new_nof = containing_map->transitions()->number_of_transitions();
+  if (new_nof != nof) {
+    DCHECK(new_nof == 0);
+    result->Shrink(ToKeyIndex(0));
+    result->SetNumberOfTransitions(0);
+  } else if (nof == 1) {
+    result->NoIncrementalWriteBarrierCopyFrom(
+        containing_map->transitions(), kSimpleTransitionIndex, 0);
   }
 
-  // At this point, we know that the map has a full TransitionArray.
-  DCHECK(IsFullTransitionArray(map->raw_transitions()));
+  result->set_back_pointer_storage(
+      containing_map->transitions()->back_pointer_storage());
+  return result;
+}
 
-  int number_of_transitions = 0;
-  int new_nof = 0;
-  int insertion_index = kNotFound;
+
+Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map,
+                                                Handle<Name> name,
+                                                Handle<Map> target,
+                                                SimpleTransitionFlag flag) {
+  if (!map->HasTransitionArray()) {
+    return TransitionArray::NewWith(map, name, target, flag);
+  }
+
+  int number_of_transitions = map->transitions()->number_of_transitions();
+  int new_nof = number_of_transitions;
+
+  bool is_special_transition = flag == SPECIAL_TRANSITION;
   DCHECK_EQ(is_special_transition, IsSpecialTransition(*name));
   PropertyDetails details = is_special_transition
                                 ? PropertyDetails(NONE, DATA, 0)
                                 : GetTargetDetails(*name, *target);
 
-  {
+  int insertion_index = kNotFound;
+  int index =
+      is_special_transition
+          ? map->transitions()->SearchSpecial(Symbol::cast(*name),
+                                              &insertion_index)
+          : map->transitions()->Search(details.kind(), *name,
+                                       details.attributes(), &insertion_index);
+  if (index == kNotFound) {
+    ++new_nof;
+  } else {
+    insertion_index = index;
+  }
+  DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
+
+  CHECK(new_nof <= kMaxNumberOfTransitions);
+
+  if (new_nof <= map->transitions()->number_of_transitions_storage()) {
     DisallowHeapAllocation no_gc;
-    TransitionArray* array = TransitionArray::cast(map->raw_transitions());
-    number_of_transitions = array->number_of_transitions();
-    new_nof = number_of_transitions;
+    TransitionArray* array = map->transitions();
 
-    int index =
-        is_special_transition
-            ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
-            : array->Search(details.kind(), *name, details.attributes(),
-                            &insertion_index);
-    // If an existing entry was found, overwrite it and return.
     if (index != kNotFound) {
       array->SetTarget(index, *target);
-      return;
+      return handle(array);
     }
 
-    ++new_nof;
-    CHECK(new_nof <= kMaxNumberOfTransitions);
-    DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
-
-    // If there is enough capacity, insert new entry into the existing array.
-    if (new_nof <= Capacity(array)) {
-      array->SetNumberOfTransitions(new_nof);
-      for (index = number_of_transitions; index > insertion_index; --index) {
-        array->SetKey(index, array->GetKey(index - 1));
-        array->SetTarget(index, array->GetTarget(index - 1));
-      }
-      array->SetKey(index, *name);
-      array->SetTarget(index, *target);
-      SLOW_DCHECK(array->IsSortedNoDuplicates());
-      return;
+    array->SetNumberOfTransitions(new_nof);
+    for (index = number_of_transitions; index > insertion_index; --index) {
+      Name* key = array->GetKey(index - 1);
+      array->SetKey(index, key);
+      array->SetTarget(index, array->GetTarget(index - 1));
     }
+    array->SetKey(index, *name);
+    array->SetTarget(index, *target);
+    SLOW_DCHECK(array->IsSortedNoDuplicates());
+    return handle(array);
   }
 
-  // We're gonna need a bigger TransitionArray.
   Handle<TransitionArray> result = Allocate(
       map->GetIsolate(), new_nof,
       Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions));
 
-  // The map's transition array may have shrunk during the allocation above as
+  // The map's transition array may grown smaller during the allocation above as
   // it was weakly traversed, though it is guaranteed not to disappear. Trim the
   // result copy if needed, and recompute variables.
-  DCHECK(IsFullTransitionArray(map->raw_transitions()));
+  DCHECK(map->HasTransitionArray());
   DisallowHeapAllocation no_gc;
-  TransitionArray* array = TransitionArray::cast(map->raw_transitions());
+  TransitionArray* array = map->transitions();
   if (array->number_of_transitions() != number_of_transitions) {
     DCHECK(array->number_of_transitions() < number_of_transitions);
 
@@ -123,11 +154,11 @@ void TransitionArray::Insert(Handle<Map> map, Handle<Name> name,
     new_nof = number_of_transitions;
 
     insertion_index = kNotFound;
-    int index =
-        is_special_transition
-            ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
-            : array->Search(details.kind(), *name, details.attributes(),
-                            &insertion_index);
+    index = is_special_transition ? map->transitions()->SearchSpecial(
+                                        Symbol::cast(*name), &insertion_index)
+                                  : map->transitions()->Search(
+                                        details.kind(), *name,
+                                        details.attributes(), &insertion_index);
     if (index == kNotFound) {
       ++new_nof;
     } else {
@@ -152,332 +183,12 @@ void TransitionArray::Insert(Handle<Map> map, Handle<Name> name,
     result->NoIncrementalWriteBarrierCopyFrom(array, i, i + 1);
   }
 
+  result->set_back_pointer_storage(array->back_pointer_storage());
   SLOW_DCHECK(result->IsSortedNoDuplicates());
-  map->set_raw_transitions(*result);
-}
-
-
-// static
-Map* TransitionArray::SearchTransition(Map* map, PropertyKind kind, Name* name,
-                                       PropertyAttributes attributes) {
-  Object* raw_transitions = map->raw_transitions();
-  if (IsSimpleTransition(raw_transitions)) {
-    Map* target = GetSimpleTransition(raw_transitions);
-    Name* key = GetSimpleTransitionKey(target);
-    if (!key->Equals(name)) return NULL;
-    PropertyDetails details = GetSimpleTargetDetails(target);
-    if (details.attributes() != attributes) return NULL;
-    if (details.kind() != kind) return NULL;
-    return target;
-  }
-  if (IsFullTransitionArray(raw_transitions)) {
-    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
-    int transition = transitions->Search(kind, name, attributes);
-    if (transition == kNotFound) return NULL;
-    return transitions->GetTarget(transition);
-  }
-  return NULL;
+  return result;
 }
 
 
-// static
-Map* TransitionArray::SearchSpecial(Map* map, Symbol* name) {
-  Object* raw_transitions = map->raw_transitions();
-  if (IsFullTransitionArray(raw_transitions)) {
-    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
-    int transition = transitions->SearchSpecial(name);
-    if (transition == kNotFound) return NULL;
-    return transitions->GetTarget(transition);
-  }
-  return NULL;
-}
-
-
-// static
-Handle<Map> TransitionArray::FindTransitionToField(Handle<Map> map,
-                                                   Handle<Name> name) {
-  DisallowHeapAllocation no_gc;
-  Map* target = SearchTransition(*map, kData, *name, NONE);
-  if (target == NULL) return Handle<Map>::null();
-  PropertyDetails details = target->GetLastDescriptorDetails();
-  DCHECK_EQ(NONE, details.attributes());
-  if (details.type() != DATA) return Handle<Map>::null();
-  return Handle<Map>(target);
-}
-
-
-// static
-Handle<String> TransitionArray::ExpectedTransitionKey(Handle<Map> map) {
-  DisallowHeapAllocation no_gc;
-  Object* raw_transition = map->raw_transitions();
-  if (!IsSimpleTransition(raw_transition)) return Handle<String>::null();
-  Map* target = GetSimpleTransition(raw_transition);
-  PropertyDetails details = GetSimpleTargetDetails(target);
-  if (details.type() != DATA) return Handle<String>::null();
-  if (details.attributes() != NONE) return Handle<String>::null();
-  Name* name = GetSimpleTransitionKey(target);
-  if (!name->IsString()) return Handle<String>::null();
-  return Handle<String>(String::cast(name));
-}
-
-
-// static
-bool TransitionArray::CanHaveMoreTransitions(Handle<Map> map) {
-  Object* raw_transitions = map->raw_transitions();
-  if (IsFullTransitionArray(raw_transitions)) {
-    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
-    return transitions->number_of_transitions() < kMaxNumberOfTransitions;
-  }
-  return true;
-}
-
-
-// static
-Handle<Map> TransitionArray::PutPrototypeTransition(Handle<Map> map,
-                                                    Handle<Object> prototype,
-                                                    Handle<Map> target_map) {
-  DCHECK(HeapObject::cast(*prototype)->map()->IsMap());
-  // Don't cache prototype transition if this map is either shared, or a map of
-  // a prototype.
-  if (map->is_prototype_map()) return map;
-  if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map;
-
-  const int header = kProtoTransitionHeaderSize;
-
-  Handle<FixedArray> cache(GetPrototypeTransitions(*map));
-  int capacity = cache->length() - header;
-  int transitions = NumberOfPrototypeTransitions(*cache) + 1;
-
-  if (transitions > capacity) {
-    // Grow array by factor 2 up to MaxCachedPrototypeTransitions.
-    int new_capacity = Min(kMaxCachedPrototypeTransitions, transitions * 2);
-    if (new_capacity == capacity) return map;
-
-    cache = FixedArray::CopySize(cache, header + new_capacity);
-    if (capacity < 0) {
-      // There was no prototype transitions array before, so the size
-      // couldn't be copied. Initialize it explicitly.
-      SetNumberOfPrototypeTransitions(*cache, 0);
-    }
-
-    SetPrototypeTransitions(map, cache);
-  }
-
-  // Reload number of transitions as GC might shrink them.
-  int last = NumberOfPrototypeTransitions(*cache);
-  int entry = header + last;
-
-  cache->set(entry, *target_map);
-  SetNumberOfPrototypeTransitions(*cache, last + 1);
-
-  return map;
-}
-
-
-// static
-Handle<Map> TransitionArray::GetPrototypeTransition(Handle<Map> map,
-                                                    Handle<Object> prototype) {
-  DisallowHeapAllocation no_gc;
-  FixedArray* cache = GetPrototypeTransitions(*map);
-  int number_of_transitions = NumberOfPrototypeTransitions(cache);
-  for (int i = 0; i < number_of_transitions; i++) {
-    Map* target = Map::cast(cache->get(kProtoTransitionHeaderSize + i));
-    if (target->prototype() == *prototype) return handle(target);
-  }
-  return Handle<Map>();
-}
-
-
-// static
-FixedArray* TransitionArray::GetPrototypeTransitions(Map* map) {
-  Object* raw_transitions = map->raw_transitions();
-  Heap* heap = map->GetHeap();
-  if (!IsFullTransitionArray(raw_transitions)) {
-    return heap->empty_fixed_array();
-  }
-  TransitionArray* transitions = TransitionArray::cast(raw_transitions);
-  if (!transitions->HasPrototypeTransitions()) {
-    return heap->empty_fixed_array();
-  }
-  return transitions->GetPrototypeTransitions();
-}
-
-
-// static
-void TransitionArray::SetNumberOfPrototypeTransitions(
-    FixedArray* proto_transitions, int value) {
-  DCHECK(proto_transitions->length() != 0);
-  proto_transitions->set(kProtoTransitionNumberOfEntriesOffset,
-                         Smi::FromInt(value));
-}
-
-
-// static
-int TransitionArray::NumberOfTransitions(Object* raw_transitions) {
-  if (CanStoreSimpleTransition(raw_transitions)) return 0;
-  if (IsSimpleTransition(raw_transitions)) return 1;
-  DCHECK(IsFullTransitionArray(raw_transitions));
-  return TransitionArray::cast(raw_transitions)->number_of_transitions();
-}
-
-
-// static
-int TransitionArray::Capacity(Object* raw_transitions) {
-  if (!IsFullTransitionArray(raw_transitions)) return 1;
-  TransitionArray* t = TransitionArray::cast(raw_transitions);
-  if (t->length() <= kFirstIndex) return 0;
-  return (t->length() - kFirstIndex) / kTransitionSize;
-}
-
-
-// Private static helper functions.
-
-Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
-                                                  int number_of_transitions,
-                                                  int slack) {
-  Handle<FixedArray> array = isolate->factory()->NewFixedArray(
-      LengthFor(number_of_transitions + slack));
-  array->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
-  array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
-  return Handle<TransitionArray>::cast(array);
-}
-
-
-void TransitionArray::NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin,
-                                                        int origin_transition,
-                                                        int target_transition) {
-  NoIncrementalWriteBarrierSet(target_transition,
-                               origin->GetKey(origin_transition),
-                               origin->GetTarget(origin_transition));
-}
-
-
-static void ZapTransitionArray(TransitionArray* transitions) {
-  MemsetPointer(transitions->data_start(),
-                transitions->GetHeap()->the_hole_value(),
-                transitions->length());
-}
-
-
-void TransitionArray::ReplaceTransitions(Handle<Map> map,
-                                         Object* new_transitions) {
-  Object* raw_transitions = map->raw_transitions();
-  if (IsFullTransitionArray(raw_transitions)) {
-    TransitionArray* old_transitions = TransitionArray::cast(raw_transitions);
-#ifdef DEBUG
-    CheckNewTransitionsAreConsistent(map, old_transitions, new_transitions);
-    DCHECK(old_transitions != new_transitions);
-#endif
-    // Transition arrays are not shared. When one is replaced, it should not
-    // keep referenced objects alive, so we zap it.
-    // When there is another reference to the array somewhere (e.g. a handle),
-    // not zapping turns from a waste of memory into a source of crashes.
-    ZapTransitionArray(old_transitions);
-  }
-  map->set_raw_transitions(new_transitions);
-}
-
-
-static void ZapPrototypeTransitions(Object* raw_transitions) {
-  DCHECK(TransitionArray::IsFullTransitionArray(raw_transitions));
-  TransitionArray* transitions = TransitionArray::cast(raw_transitions);
-  if (!transitions->HasPrototypeTransitions()) return;
-  FixedArray* proto_transitions = transitions->GetPrototypeTransitions();
-  MemsetPointer(proto_transitions->data_start(),
-                proto_transitions->GetHeap()->the_hole_value(),
-                proto_transitions->length());
-}
-
-
-void TransitionArray::SetPrototypeTransitions(
-    Handle<Map> map, Handle<FixedArray> proto_transitions) {
-  EnsureHasFullTransitionArray(map);
-  if (Heap::ShouldZapGarbage()) {
-    Object* raw_transitions = map->raw_transitions();
-    DCHECK(raw_transitions != *proto_transitions);
-    ZapPrototypeTransitions(raw_transitions);
-  }
-  TransitionArray* transitions = TransitionArray::cast(map->raw_transitions());
-  transitions->SetPrototypeTransitions(*proto_transitions);
-}
-
-
-void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) {
-  Object* raw_transitions = map->raw_transitions();
-  if (IsFullTransitionArray(raw_transitions)) return;
-  int nof = IsSimpleTransition(raw_transitions) ? 1 : 0;
-  Handle<TransitionArray> result = Allocate(map->GetIsolate(), nof);
-  DisallowHeapAllocation no_gc;
-  // Reload pointer after the allocation that just happened.
-  raw_transitions = map->raw_transitions();
-  int new_nof = IsSimpleTransition(raw_transitions) ? 1 : 0;
-  if (new_nof != nof) {
-    DCHECK(new_nof == 0);
-    result->Shrink(ToKeyIndex(0));
-    result->SetNumberOfTransitions(0);
-  } else if (nof == 1) {
-    Map* target = GetSimpleTransition(raw_transitions);
-    Name* key = GetSimpleTransitionKey(target);
-    result->NoIncrementalWriteBarrierSet(0, key, target);
-  }
-  ReplaceTransitions(map, *result);
-}
-
-
-void TransitionArray::TraverseTransitionTreeInternal(Map* map,
-                                                     TraverseCallback callback,
-                                                     void* data) {
-  Object* raw_transitions = map->raw_transitions();
-  if (IsFullTransitionArray(raw_transitions)) {
-    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
-    if (transitions->HasPrototypeTransitions()) {
-      FixedArray* proto_trans = transitions->GetPrototypeTransitions();
-      for (int i = 0; i < NumberOfPrototypeTransitions(proto_trans); ++i) {
-        int index = TransitionArray::kProtoTransitionHeaderSize + i;
-        TraverseTransitionTreeInternal(Map::cast(proto_trans->get(index)),
-                                       callback, data);
-      }
-    }
-    for (int i = 0; i < transitions->number_of_transitions(); ++i) {
-      TraverseTransitionTreeInternal(transitions->GetTarget(i), callback, data);
-    }
-  } else if (IsSimpleTransition(raw_transitions)) {
-    TraverseTransitionTreeInternal(GetSimpleTransition(raw_transitions),
-                                   callback, data);
-  }
-  callback(map, data);
-}
-
-
-#ifdef DEBUG
-void TransitionArray::CheckNewTransitionsAreConsistent(
-    Handle<Map> map, TransitionArray* old_transitions, Object* transitions) {
-  // This function only handles full transition arrays.
-  DCHECK(IsFullTransitionArray(transitions));
-  TransitionArray* new_transitions = TransitionArray::cast(transitions);
-  for (int i = 0; i < old_transitions->number_of_transitions(); i++) {
-    Map* target = old_transitions->GetTarget(i);
-    if (target->instance_descriptors() == map->instance_descriptors()) {
-      Name* key = old_transitions->GetKey(i);
-      int new_target_index;
-      if (TransitionArray::IsSpecialTransition(key)) {
-        new_target_index = new_transitions->SearchSpecial(Symbol::cast(key));
-      } else {
-        PropertyDetails details =
-            TransitionArray::GetTargetDetails(key, target);
-        new_target_index =
-            new_transitions->Search(details.kind(), key, details.attributes());
-      }
-      DCHECK_NE(TransitionArray::kNotFound, new_target_index);
-      DCHECK_EQ(target, new_transitions->GetTarget(new_target_index));
-    }
-  }
-}
-#endif
-
-
-// Private non-static helper functions (operating on full transition arrays).
-
 int TransitionArray::SearchDetails(int transition, PropertyKind kind,
                                    PropertyAttributes attributes,
                                    int* out_insertion_index) {
index 648559ba4cd2652fd836b691e81c9fbb226a48d9..999ad86c558c176f8bb112df840b626f81c36cbb 100644 (file)
@@ -16,98 +16,47 @@ namespace internal {
 
 
 // TransitionArrays are fixed arrays used to hold map transitions for property,
-// constant, and element changes. "Simple" transitions storing only a single
-// property transition are stored inline (i.e. the target map is stored
-// directly); otherwise a full transition array is used that has
+// constant, and element changes. They can either be simple transition arrays
+// that store a single property transition, or a full transition array that has
 // prototype transitions and multiple property transitons. The details related
 // to property transitions are accessed in the descriptor array of the target
 // map. In the case of a simple transition, the key is also read from the
 // descriptor array of the target map.
 //
-// This class provides a static interface that operates directly on maps
-// and handles the distinction between simple and full transitions storage.
+// The simple format of the these objects is:
+// [0] Undefined or back pointer map
+// [1] Single transition
 //
 // The full format is:
-// [0] Smi(0) or fixed array of prototype transitions
-// [1] Number of transitions
-// [2] First transition
-// [2 + number of transitions * kTransitionSize]: start of slack
+// [0] Undefined or back pointer map
+// [1] Smi(0) or fixed array of prototype transitions
+// [2] Number of transitions
+// [3] First transition
+// [3 + number of transitions * kTransitionSize]: start of slack
 class TransitionArray: public FixedArray {
  public:
-  // Insert a new transition into |map|'s transition array, extending it
-  // as necessary.
-  static void Insert(Handle<Map> map, Handle<Name> name, Handle<Map> target,
-                     SimpleTransitionFlag flag);
-
-  static Map* SearchTransition(Map* map, PropertyKind kind, Name* name,
-                               PropertyAttributes attributes);
-
-  static Map* SearchSpecial(Map* map, Symbol* name);
+  // Accessors for fetching instance transition at transition number.
+  inline Name* GetKey(int transition_number);
+  inline void SetKey(int transition_number, Name* value);
+  inline Object** GetKeySlot(int transition_number);
+  int GetSortedKeyIndex(int transition_number) { return transition_number; }
 
-  static Handle<Map> FindTransitionToField(Handle<Map> map, Handle<Name> name);
+  Name* GetSortedKey(int transition_number) {
+    return GetKey(transition_number);
+  }
 
-  static Handle<String> ExpectedTransitionKey(Handle<Map> map);
+  inline Map* GetTarget(int transition_number);
+  inline void SetTarget(int transition_number, Map* target);
 
-  static Handle<Map> ExpectedTransitionTarget(Handle<Map> map) {
-    DCHECK(!ExpectedTransitionKey(map).is_null());
-    return Handle<Map>(GetSimpleTransition(map->raw_transitions()));
-  }
-  // Returns true if |raw_transition| can be overwritten with a simple
-  // transition (because it's either uninitialized, or has been cleared).
-  static inline bool CanStoreSimpleTransition(Object* raw_transition) {
-    return raw_transition->IsSmi() ||
-           (raw_transition->IsWeakCell() &&
-            WeakCell::cast(raw_transition)->cleared());
-  }
-  static inline bool IsSimpleTransition(Object* raw_transition) {
-    DCHECK(!raw_transition->IsWeakCell() ||
-           WeakCell::cast(raw_transition)->cleared() ||
-           WeakCell::cast(raw_transition)->value()->IsMap());
-    return raw_transition->IsWeakCell() &&
-           !WeakCell::cast(raw_transition)->cleared();
-  }
-  static inline Map* GetSimpleTransition(Object* raw_transition) {
-    DCHECK(IsSimpleTransition(raw_transition));
-    return Map::cast(WeakCell::cast(raw_transition)->value());
-  }
-  static inline bool IsFullTransitionArray(Object* raw_transitions) {
-    return raw_transitions->IsTransitionArray();
-  }
+  inline PropertyDetails GetTargetDetails(int transition_number);
+  inline Object* GetTargetValue(int transition_number);
 
-  // The size of transition arrays are limited so they do not end up in large
-  // object space. Otherwise ClearNonLiveReferences would leak memory while
-  // applying in-place right trimming.
-  static bool CanHaveMoreTransitions(Handle<Map> map);
-
-  // ===== PROTOTYPE TRANSITIONS =====
-  // When you set the prototype of an object using the __proto__ accessor you
-  // need a new map for the object (the prototype is stored in the map).  In
-  // order not to multiply maps unnecessarily we store these as transitions in
-  // the original map.  That way we can transition to the same map if the same
-  // prototype is set, rather than creating a new map every time.  The
-  // transitions are in the form of a map where the keys are prototype objects
-  // and the values are the maps they transition to.
-  // Cache format:
-  //    0: finger - index of the first free cell in the cache
-  //    1 + i: target map
-  static const int kMaxCachedPrototypeTransitions = 256;
-  static Handle<Map> PutPrototypeTransition(Handle<Map> map,
-                                            Handle<Object> prototype,
-                                            Handle<Map> target_map);
-
-  static Handle<Map> GetPrototypeTransition(Handle<Map> map,
-                                            Handle<Object> prototype);
-
-  static FixedArray* GetPrototypeTransitions(Map* map);
-
-  static int NumberOfPrototypeTransitions(FixedArray* proto_transitions) {
-    if (proto_transitions->length() == 0) return 0;
-    Object* raw = proto_transitions->get(kProtoTransitionNumberOfEntriesOffset);
-    return Smi::cast(raw)->value();
-  }
+  inline bool HasElementsTransition();
 
-  static void SetNumberOfPrototypeTransitions(FixedArray* proto_transitions,
-                                              int value);
+  inline Object* back_pointer_storage();
+  inline void set_back_pointer_storage(
+      Object* back_pointer,
+      WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
 
   inline FixedArray* GetPrototypeTransitions();
   inline void SetPrototypeTransitions(
@@ -116,92 +65,133 @@ class TransitionArray: public FixedArray {
   inline Object** GetPrototypeTransitionsSlot();
   inline bool HasPrototypeTransitions();
 
-  // ===== ITERATION =====
+  // Returns the number of transitions in the array.
+  int number_of_transitions() {
+    if (IsSimpleTransition()) return 1;
+    if (length() <= kFirstIndex) return 0;
+    return Smi::cast(get(kTransitionLengthIndex))->value();
+  }
 
-  typedef void (*TraverseCallback)(Map* map, void* data);
+  int number_of_transitions_storage() {
+    if (IsSimpleTransition()) return 1;
+    if (length() <= kFirstIndex) return 0;
+    return (length() - kFirstIndex) / kTransitionSize;
+  }
 
-  // Traverse the transition tree in postorder.
-  static void TraverseTransitionTree(Map* map, TraverseCallback callback,
-                                     void* data) {
-    // Make sure that we do not allocate in the callback.
-    DisallowHeapAllocation no_allocation;
-    TraverseTransitionTreeInternal(map, callback, data);
+  int NumberOfSlackTransitions() {
+    return number_of_transitions_storage() - number_of_transitions();
   }
 
-  // ===== LOW-LEVEL ACCESSORS =====
+  inline void SetNumberOfTransitions(int number_of_transitions);
+  inline int number_of_entries() { return number_of_transitions(); }
 
-  // Accessors for fetching instance transition at transition number.
-  static inline Name* GetKey(Object* raw_transitions, int transition_number);
-  inline Name* GetKey(int transition_number);
-  inline void SetKey(int transition_number, Name* value);
-  inline Object** GetKeySlot(int transition_number);
-  int GetSortedKeyIndex(int transition_number) { return transition_number; }
+  // Creates a FullTransitionArray from a SimpleTransitionArray in
+  // containing_map.
+  static Handle<TransitionArray> ExtendToFullTransitionArray(
+      Handle<Map> containing_map);
+
+  // Return a transition array, using the array from the owning map if it
+  // already has one (copying into a larger array if necessary), otherwise
+  // creating a new one according to flag.
+  // TODO(verwaest): This should not cause an existing transition to be
+  // overwritten.
+  static Handle<TransitionArray> Insert(Handle<Map> map, Handle<Name> name,
+                                        Handle<Map> target,
+                                        SimpleTransitionFlag flag);
+  // Search a  transition for a given kind, property name and attributes.
+  int Search(PropertyKind kind, Name* name, PropertyAttributes attributes,
+             int* out_insertion_index = NULL);
 
-  Name* GetSortedKey(int transition_number) {
-    return GetKey(transition_number);
+  // Search a non-property transition (like elements kind, observe or frozen
+  // transitions).
+  inline int SearchSpecial(Symbol* symbol, int* out_insertion_index = NULL) {
+    return SearchName(symbol, out_insertion_index);
   }
 
-  static inline Map* GetTarget(Object* raw_transitions, int transition_number);
-  inline Map* GetTarget(int transition_number);
-  inline void SetTarget(int transition_number, Map* target);
-
   static inline PropertyDetails GetTargetDetails(Name* name, Map* target);
 
-  // Returns the number of transitions in the array.
-  static int NumberOfTransitions(Object* raw_transitions);
-  // Required for templatized Search interface.
-  inline int number_of_entries() { return number_of_transitions(); }
+  // Allocates a TransitionArray.
+  static Handle<TransitionArray> Allocate(Isolate* isolate,
+                                          int number_of_transitions,
+                                          int slack = 0);
 
-  inline void SetNumberOfTransitions(int number_of_transitions);
+  bool IsSimpleTransition() {
+    return length() == kSimpleTransitionSize &&
+        get(kSimpleTransitionTarget)->IsHeapObject() &&
+        // The IntrusivePrototypeTransitionIterator may have set the map of the
+        // prototype transitions array to a smi. In that case, there are
+        // prototype transitions, hence this transition array is a full
+        // transition array.
+        HeapObject::cast(get(kSimpleTransitionTarget))->map()->IsMap() &&
+        get(kSimpleTransitionTarget)->IsMap();
+  }
 
-  static int Capacity(Object* raw_transitions);
+  bool IsFullTransitionArray() {
+    return length() > kFirstIndex ||
+        (length() == kFirstIndex && !IsSimpleTransition());
+  }
 
   // Casting.
   static inline TransitionArray* cast(Object* obj);
 
+  // Constant for denoting key was not found.
+  static const int kNotFound = -1;
+
+  static const int kBackPointerStorageIndex = 0;
+
+  // Layout for full transition arrays.
+  static const int kPrototypeTransitionsIndex = 1;
+  static const int kTransitionLengthIndex = 2;
+  static const int kFirstIndex = 3;
+
+  // Layout for simple transition arrays.
+  static const int kSimpleTransitionTarget = 1;
+  static const int kSimpleTransitionSize = 2;
+  static const int kSimpleTransitionIndex = 0;
+  STATIC_ASSERT(kSimpleTransitionIndex != kNotFound);
+
+  static const int kBackPointerStorageOffset = FixedArray::kHeaderSize;
+
+  // Layout for the full transition array header.
+  static const int kPrototypeTransitionsOffset = kBackPointerStorageOffset +
+                                                 kPointerSize;
+  static const int kTransitionLengthOffset =
+      kPrototypeTransitionsOffset + kPointerSize;
+
+  // Layout of map transition entries in full transition arrays.
+  static const int kTransitionKey = 0;
+  static const int kTransitionTarget = 1;
   static const int kTransitionSize = 2;
-  static const int kProtoTransitionHeaderSize = 1;
 
 #if defined(DEBUG) || defined(OBJECT_PRINT)
   // For our gdb macros, we should perhaps change these in the future.
   void Print();
 
   // Print all the transitions.
-  static void PrintTransitions(std::ostream& os, Object* transitions,
-                               bool print_header = true);  // NOLINT
+  void PrintTransitions(std::ostream& os, bool print_header = true);  // NOLINT
 #endif
 
 #ifdef DEBUG
   bool IsSortedNoDuplicates(int valid_entries = -1);
-  static bool IsSortedNoDuplicates(Map* map);
-  static bool IsConsistentWithBackPointers(Map* map);
+  bool IsConsistentWithBackPointers(Map* current_map);
+  bool IsEqualTo(TransitionArray* other);
 
   // Returns true for a non-property transitions like elements kind, observed
   // or frozen transitions.
   static inline bool IsSpecialTransition(Name* name);
 #endif
 
-  // Constant for denoting key was not found.
-  static const int kNotFound = -1;
-
   // The maximum number of transitions we want in a transition array (should
   // fit in a page).
   static const int kMaxNumberOfTransitions = 1024 + 512;
 
- private:
-  // Layout for full transition arrays.
-  static const int kPrototypeTransitionsIndex = 0;
-  static const int kTransitionLengthIndex = 1;
-  static const int kFirstIndex = 2;
-
-  // Layout of map transition entries in full transition arrays.
-  static const int kTransitionKey = 0;
-  static const int kTransitionTarget = 1;
-  STATIC_ASSERT(kTransitionSize == 2);
-
-  static const int kProtoTransitionNumberOfEntriesOffset = 0;
-  STATIC_ASSERT(kProtoTransitionHeaderSize == 1);
+  // Returns the fixed array length required to hold number_of_transitions
+  // transitions.
+  static int LengthFor(int number_of_transitions) {
+    return ToKeyIndex(number_of_transitions);
+  }
 
+ private:
   // Conversion from transition number to array indices.
   static int ToKeyIndex(int transition_number) {
     return kFirstIndex +
@@ -215,55 +205,20 @@ class TransitionArray: public FixedArray {
            kTransitionTarget;
   }
 
-  // Returns the fixed array length required to hold number_of_transitions
-  // transitions.
-  static int LengthFor(int number_of_transitions) {
-    return ToKeyIndex(number_of_transitions);
-  }
-
-  // Allocates a TransitionArray.
-  static Handle<TransitionArray> Allocate(Isolate* isolate,
-                                          int number_of_transitions,
-                                          int slack = 0);
-
-  static void EnsureHasFullTransitionArray(Handle<Map> map);
-  static void ReplaceTransitions(Handle<Map> map, Object* new_transitions);
+  static Handle<TransitionArray> AllocateSimple(
+      Isolate* isolate, Handle<Map> target);
 
-  // Search a  transition for a given kind, property name and attributes.
-  int Search(PropertyKind kind, Name* name, PropertyAttributes attributes,
-             int* out_insertion_index = NULL);
+  // Allocate a new transition array with a single entry.
+  static Handle<TransitionArray> NewWith(Handle<Map> map,
+                                         Handle<Name> name,
+                                         Handle<Map> target,
+                                         SimpleTransitionFlag flag);
 
-  // Search a non-property transition (like elements kind, observe or frozen
-  // transitions).
-  inline int SearchSpecial(Symbol* symbol, int* out_insertion_index = NULL) {
-    return SearchName(symbol, out_insertion_index);
-  }
   // Search a first transition for a given property name.
   inline int SearchName(Name* name, int* out_insertion_index = NULL);
   int SearchDetails(int transition, PropertyKind kind,
                     PropertyAttributes attributes, int* out_insertion_index);
 
-  int number_of_transitions() {
-    if (length() < kFirstIndex) return 0;
-    return Smi::cast(get(kTransitionLengthIndex))->value();
-  }
-
-  static inline PropertyDetails GetSimpleTargetDetails(Map* transition) {
-    return transition->GetLastDescriptorDetails();
-  }
-
-  static inline Name* GetSimpleTransitionKey(Map* transition) {
-    int descriptor = transition->LastAdded();
-    return transition->instance_descriptors()->GetKey(descriptor);
-  }
-
-  static void TraverseTransitionTreeInternal(Map* map,
-                                             TraverseCallback callback,
-                                             void* data);
-
-  static void SetPrototypeTransitions(Handle<Map> map,
-                                      Handle<FixedArray> proto_transitions);
-
   // Compares two tuples <key, kind, attributes>, returns -1 if
   // tuple1 is "less" than tuple2, 0 if tuple1 equal to tuple2 and 1 otherwise.
   static inline int CompareKeys(Name* key1, uint32_t hash1, PropertyKind kind1,
@@ -292,12 +247,6 @@ class TransitionArray: public FixedArray {
                                                 int origin_transition,
                                                 int target_transition);
 
-#ifdef DEBUG
-  static void CheckNewTransitionsAreConsistent(Handle<Map> map,
-                                               TransitionArray* old_transitions,
-                                               Object* transitions);
-#endif
-
   DISALLOW_IMPLICIT_CONSTRUCTORS(TransitionArray);
 };
 
index b5a86746ee3e71006e9d1be233ae82d3fdacc597..d7c24156a3d2aed5fad23b591898cf7e510f4902 100644 (file)
@@ -2141,12 +2141,6 @@ TEST(InstanceOfStubWriteBarrier) {
 }
 
 
-static int NumberOfProtoTransitions(Map* map) {
-  return TransitionArray::NumberOfPrototypeTransitions(
-      TransitionArray::GetPrototypeTransitions(map));
-}
-
-
 TEST(PrototypeTransitionClearing) {
   if (FLAG_never_compact) return;
   CcTest::InitializeVM();
@@ -2159,7 +2153,7 @@ TEST(PrototypeTransitionClearing) {
       v8::Utils::OpenHandle(
           *v8::Handle<v8::Object>::Cast(
               CcTest::global()->Get(v8_str("base"))));
-  int initialTransitions = NumberOfProtoTransitions(baseObject->map());
+  int initialTransitions = baseObject->map()->NumberOfProtoTransitions();
 
   CompileRun(
       "var live = [];"
@@ -2172,17 +2166,16 @@ TEST(PrototypeTransitionClearing) {
 
   // Verify that only dead prototype transitions are cleared.
   CHECK_EQ(initialTransitions + 10,
-           NumberOfProtoTransitions(baseObject->map()));
+      baseObject->map()->NumberOfProtoTransitions());
   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   const int transitions = 10 - 3;
   CHECK_EQ(initialTransitions + transitions,
-           NumberOfProtoTransitions(baseObject->map()));
+      baseObject->map()->NumberOfProtoTransitions());
 
   // Verify that prototype transitions array was compacted.
-  FixedArray* trans =
-      TransitionArray::GetPrototypeTransitions(baseObject->map());
+  FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
   for (int i = initialTransitions; i < initialTransitions + transitions; i++) {
-    int j = TransitionArray::kProtoTransitionHeaderSize + i;
+    int j = Map::kProtoTransitionHeaderSize + i;
     CHECK(trans->get(j)->IsMap());
   }
 
@@ -2200,7 +2193,7 @@ TEST(PrototypeTransitionClearing) {
   i::FLAG_always_compact = true;
   Handle<Map> map(baseObject->map());
   CHECK(!space->LastPage()->Contains(
-      TransitionArray::GetPrototypeTransitions(*map)->address()));
+      map->GetPrototypeTransitions()->address()));
   CHECK(space->LastPage()->Contains(prototype->address()));
 }
 
@@ -2883,7 +2876,7 @@ TEST(OptimizedAllocationArrayLiterals) {
 
 
 static int CountMapTransitions(Map* map) {
-  return TransitionArray::NumberOfTransitions(map->raw_transitions());
+  return map->transitions()->number_of_transitions();
 }
 
 
@@ -3062,7 +3055,7 @@ TEST(TransitionArraySimpleToFull) {
   CompileRun("o = new F;"
              "root = new F");
   root = GetByName("root");
-  DCHECK(TransitionArray::IsSimpleTransition(root->map()->raw_transitions()));
+  DCHECK(root->map()->transitions()->IsSimpleTransition());
   AddPropertyTo(2, root, "happy");
 
   // Count number of live transitions after marking.  Note that one transition
index 3be173453a5b407b6614af55f0dd348594df0030..c7aaf29d6643e420254aeefa6d4df871ed6ca99e 100644 (file)
@@ -342,10 +342,9 @@ class Expectations {
     SetDataField(property_index, attributes, representation, heap_type);
 
     Handle<String> name = MakeName("prop", property_index);
-    Map* target =
-        TransitionArray::SearchTransition(*map, kData, *name, attributes);
-    CHECK(target != NULL);
-    return handle(target);
+    int t = map->SearchTransition(kData, *name, attributes);
+    CHECK_NE(TransitionArray::kNotFound, t);
+    return handle(map->GetTransition(t));
   }
 
   Handle<Map> AddAccessorConstant(Handle<Map> map,
@@ -1478,10 +1477,9 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
       }
 
       Handle<String> name = MakeName("prop", i);
-      Map* target =
-          TransitionArray::SearchTransition(*map2, kData, *name, NONE);
-      CHECK(target != NULL);
-      map2 = handle(target);
+      int t = map2->SearchTransition(kData, *name, NONE);
+      CHECK_NE(TransitionArray::kNotFound, t);
+      map2 = handle(map2->GetTransition(t));
     }
 
     map2 = Map::ReconfigureProperty(map2, kSplitProp, kData, NONE,
@@ -1501,12 +1499,12 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
 
   // Fill in transition tree of |map2| so that it can't have more transitions.
   for (int i = 0; i < TransitionArray::kMaxNumberOfTransitions; i++) {
-    CHECK(TransitionArray::CanHaveMoreTransitions(map2));
+    CHECK(map2->CanHaveMoreTransitions());
     Handle<String> name = MakeName("foo", i);
     Map::CopyWithField(map2, name, any_type, NONE, Representation::Smi(),
                        INSERT_TRANSITION).ToHandleChecked();
   }
-  CHECK(!TransitionArray::CanHaveMoreTransitions(map2));
+  CHECK(!map2->CanHaveMoreTransitions());
 
   // Try to update |map|, since there is no place for propX transition at |map2|
   // |map| should become "copy-generalized".
index 800c2a0e4436950798df310c1f2d7fa4eaf6e1f7..59c9f74c96dbdb41ef34ccb1b55e634936fcf522 100644 (file)
@@ -20,6 +20,16 @@ using namespace v8::internal;
 // Helper functions.
 //
 
+static void ConnectTransition(Handle<Map> parent,
+                              Handle<TransitionArray> transitions,
+                              Handle<Map> child) {
+  if (!parent->HasTransitionArray() || *transitions != parent->transitions()) {
+    parent->set_transitions(*transitions);
+  }
+  child->SetBackPointer(*parent);
+}
+
+
 static void CheckPropertyDetailsFieldsConsistency(PropertyType type,
                                                   PropertyKind kind,
                                                   PropertyLocation location) {
@@ -59,32 +69,34 @@ TEST(TransitionArray_SimpleFieldTransitions) {
                          attributes, Representation::Tagged(),
                          OMIT_TRANSITION).ToHandleChecked();
 
-  CHECK(map0->raw_transitions()->IsSmi());
-
-  TransitionArray::Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION);
-  CHECK(TransitionArray::IsSimpleTransition(map0->raw_transitions()));
-  CHECK_EQ(*map1,
-           TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
-  CHECK_EQ(1, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
-  CHECK_EQ(*name1, TransitionArray::GetKey(map0->raw_transitions(), 0));
-  CHECK_EQ(*map1, TransitionArray::GetTarget(map0->raw_transitions(), 0));
-
-  TransitionArray::Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION);
-  CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions()));
-
-  CHECK_EQ(*map1,
-           TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
-  CHECK_EQ(*map2,
-           TransitionArray::SearchTransition(*map0, kData, *name2, attributes));
-  CHECK_EQ(2, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
-  for (int i = 0; i < 2; i++) {
-    Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
-    Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
-    CHECK((key == *name1 && target == *map1) ||
-          (key == *name2 && target == *map2));
-  }
-
-  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  int transition;
+  transitions =
+      transitions->Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map1);
+  CHECK(transitions->IsSimpleTransition());
+  transition = transitions->Search(kData, *name1, attributes);
+  CHECK_EQ(TransitionArray::kSimpleTransitionIndex, transition);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transitions =
+      transitions->Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map2);
+  CHECK(transitions->IsFullTransitionArray());
+
+  transition = transitions->Search(kData, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transition = transitions->Search(kData, *name2, attributes);
+  CHECK_EQ(*name2, transitions->GetKey(transition));
+  CHECK_EQ(*map2, transitions->GetTarget(transition));
+
+  DCHECK(transitions->IsSortedNoDuplicates());
 }
 
 
@@ -108,32 +120,31 @@ TEST(TransitionArray_FullFieldTransitions) {
                          attributes, Representation::Tagged(),
                          OMIT_TRANSITION).ToHandleChecked();
 
-  CHECK(map0->raw_transitions()->IsSmi());
-
-  TransitionArray::Insert(map0, name1, map1, PROPERTY_TRANSITION);
-  CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions()));
-  CHECK_EQ(*map1,
-           TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
-  CHECK_EQ(1, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
-  CHECK_EQ(*name1, TransitionArray::GetKey(map0->raw_transitions(), 0));
-  CHECK_EQ(*map1, TransitionArray::GetTarget(map0->raw_transitions(), 0));
-
-  TransitionArray::Insert(map0, name2, map2, PROPERTY_TRANSITION);
-  CHECK(TransitionArray::IsFullTransitionArray(map0->raw_transitions()));
-
-  CHECK_EQ(*map1,
-           TransitionArray::SearchTransition(*map0, kData, *name1, attributes));
-  CHECK_EQ(*map2,
-           TransitionArray::SearchTransition(*map0, kData, *name2, attributes));
-  CHECK_EQ(2, TransitionArray::NumberOfTransitions(map0->raw_transitions()));
-  for (int i = 0; i < 2; i++) {
-    Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
-    Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
-    CHECK((key == *name1 && target == *map1) ||
-          (key == *name2 && target == *map2));
-  }
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  int transition;
+  transitions = transitions->Insert(map0, name1, map1, PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map1);
+  CHECK(transitions->IsFullTransitionArray());
+  transition = transitions->Search(kData, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transitions = transitions->Insert(map0, name2, map2, PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map2);
+  CHECK(transitions->IsFullTransitionArray());
 
-  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
+  transition = transitions->Search(kData, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transition = transitions->Search(kData, *name2, attributes);
+  CHECK_EQ(*name2, transitions->GetKey(transition));
+  CHECK_EQ(*map2, transitions->GetTarget(transition));
+
+  DCHECK(transitions->IsSortedNoDuplicates());
 }
 
 
@@ -149,7 +160,9 @@ TEST(TransitionArray_DifferentFieldNames) {
   PropertyAttributes attributes = NONE;
 
   Handle<Map> map0 = Map::Create(isolate, 0);
-  CHECK(map0->raw_transitions()->IsSmi());
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
 
   for (int i = 0; i < PROPS_COUNT; i++) {
     EmbeddedVector<char, 64> buffer;
@@ -162,25 +175,17 @@ TEST(TransitionArray_DifferentFieldNames) {
     names[i] = name;
     maps[i] = map;
 
-    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
   }
 
   for (int i = 0; i < PROPS_COUNT; i++) {
-    CHECK_EQ(*maps[i], TransitionArray::SearchTransition(
-                           *map0, kData, *names[i], attributes));
-  }
-  for (int i = 0; i < PROPS_COUNT; i++) {
-    Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
-    Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
-    for (int j = 0; j < PROPS_COUNT; j++) {
-      if (*names[i] == key) {
-        CHECK_EQ(*maps[i], target);
-        break;
-      }
-    }
+    int transition = transitions->Search(kData, *names[i], attributes);
+    CHECK_EQ(*names[i], transitions->GetKey(transition));
+    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
   }
 
-  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
+  DCHECK(transitions->IsSortedNoDuplicates());
 }
 
 
@@ -191,7 +196,9 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
   Factory* factory = isolate->factory();
 
   Handle<Map> map0 = Map::Create(isolate, 0);
-  CHECK(map0->raw_transitions()->IsSmi());
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
 
   const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
   STATIC_ASSERT(ATTRS_COUNT == 8);
@@ -208,20 +215,20 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
                            OMIT_TRANSITION).ToHandleChecked();
     attr_maps[i] = map;
 
-    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
   }
 
   // Ensure that transitions for |name| field are valid.
   for (int i = 0; i < ATTRS_COUNT; i++) {
     PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
-    CHECK_EQ(*attr_maps[i], TransitionArray::SearchTransition(
-                                *map0, kData, *name, attributes));
-    // All transitions use the same key, so this check doesn't need to
-    // care about ordering.
-    CHECK_EQ(*name, TransitionArray::GetKey(map0->raw_transitions(), i));
+
+    int transition = transitions->Search(kData, *name, attributes);
+    CHECK_EQ(*name, transitions->GetKey(transition));
+    CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition));
   }
 
-  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
+  DCHECK(transitions->IsSortedNoDuplicates());
 }
 
 
@@ -236,7 +243,9 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
   Handle<Map> maps[PROPS_COUNT];
 
   Handle<Map> map0 = Map::Create(isolate, 0);
-  CHECK(map0->raw_transitions()->IsSmi());
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
 
   // Some number of fields.
   for (int i = 0; i < PROPS_COUNT; i++) {
@@ -250,7 +259,8 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
     names[i] = name;
     maps[i] = map;
 
-    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
   }
 
   const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
@@ -268,36 +278,25 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
                            OMIT_TRANSITION).ToHandleChecked();
     attr_maps[i] = map;
 
-    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
   }
 
   // Ensure that transitions for |name| field are valid.
   for (int i = 0; i < ATTRS_COUNT; i++) {
-    PropertyAttributes attr = static_cast<PropertyAttributes>(i);
-    CHECK_EQ(*attr_maps[i],
-             TransitionArray::SearchTransition(*map0, kData, *name, attr));
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    int transition = transitions->Search(kData, *name, attributes);
+    CHECK_EQ(*name, transitions->GetKey(transition));
+    CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition));
   }
 
   // Ensure that info about the other fields still valid.
-  CHECK_EQ(PROPS_COUNT + ATTRS_COUNT,
-           TransitionArray::NumberOfTransitions(map0->raw_transitions()));
-  for (int i = 0; i < PROPS_COUNT + ATTRS_COUNT; i++) {
-    Name* key = TransitionArray::GetKey(map0->raw_transitions(), i);
-    Map* target = TransitionArray::GetTarget(map0->raw_transitions(), i);
-    if (key == *name) {
-      // Attributes transition.
-      PropertyAttributes attributes =
-          target->GetLastDescriptorDetails().attributes();
-      CHECK_EQ(*attr_maps[static_cast<int>(attributes)], target);
-    } else {
-      for (int j = 0; j < PROPS_COUNT; j++) {
-        if (*names[j] == key) {
-          CHECK_EQ(*maps[j], target);
-          break;
-        }
-      }
-    }
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    int transition = transitions->Search(kData, *names[i], NONE);
+    CHECK_EQ(*names[i], transitions->GetKey(transition));
+    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
   }
 
-  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
+  DCHECK(transitions->IsSortedNoDuplicates());
 }