Reland: Simplify and compact transitions storage
authorjkummerow <jkummerow@chromium.org>
Fri, 6 Mar 2015 14:08:33 +0000 (06:08 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 6 Mar 2015 14:08:47 +0000 (14:08 +0000)
Original issue: https://codereview.chromium.org/980573002/

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.

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

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

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 6fb6870..2809072 100644 (file)
@@ -1286,28 +1286,31 @@ void V8HeapExplorer::ExtractContextReferences(int entry, Context* context) {
 
 
 void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) {
-  if (map->HasTransitionArray()) {
-    TransitionArray* transitions = map->transitions();
+  Object* raw_transitions = map->raw_transitions();
+  if (TransitionArray::IsFullTransitionArray(raw_transitions)) {
+    TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     int transitions_entry = GetEntry(transitions)->index();
 
     if (FLAG_collect_maps && map->CanTransition()) {
-      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);
+      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);
     }
 
     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 a59d8ba..9ea06d2 100644 (file)
@@ -2477,7 +2477,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->init_transitions(undefined_value());
+  map->set_raw_transitions(Smi::FromInt(0));
   map->set_unused_property_fields(0);
   map->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
@@ -2611,7 +2611,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()->init_transitions(undefined_value());
+  meta_map()->set_raw_transitions(Smi::FromInt(0));
   meta_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     meta_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
@@ -2620,7 +2620,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()->init_transitions(undefined_value());
+  fixed_array_map()->set_raw_transitions(Smi::FromInt(0));
   fixed_array_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     fixed_array_map()->set_layout_descriptor(
@@ -2629,7 +2629,7 @@ bool Heap::CreateInitialMaps() {
 
   undefined_map()->set_code_cache(empty_fixed_array());
   undefined_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
-  undefined_map()->init_transitions(undefined_value());
+  undefined_map()->set_raw_transitions(Smi::FromInt(0));
   undefined_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     undefined_map()->set_layout_descriptor(
@@ -2638,7 +2638,7 @@ bool Heap::CreateInitialMaps() {
 
   null_map()->set_code_cache(empty_fixed_array());
   null_map()->set_dependent_code(DependentCode::cast(empty_fixed_array()));
-  null_map()->init_transitions(undefined_value());
+  null_map()->set_raw_transitions(Smi::FromInt(0));
   null_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     null_map()->set_layout_descriptor(LayoutDescriptor::FastPointerLayout());
@@ -2647,7 +2647,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()->init_transitions(undefined_value());
+  constant_pool_array_map()->set_raw_transitions(Smi::FromInt(0));
   constant_pool_array_map()->set_instance_descriptors(empty_descriptor_array());
   if (FLAG_unbox_double_fields) {
     constant_pool_array_map()->set_layout_descriptor(
index 741414a..44262e4 100644 (file)
@@ -1470,8 +1470,9 @@ class MarkCompactMarkingVisitor::ObjectStatsTracker<
       heap->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE,
                                          fixed_array_size);
     }
-    if (map_obj->HasTransitionArray()) {
-      int fixed_array_size = map_obj->transitions()->Size();
+    if (TransitionArray::IsFullTransitionArray(map_obj->raw_transitions())) {
+      int fixed_array_size =
+          TransitionArray::cast(map_obj->raw_transitions())->Size();
       heap->RecordFixedArraySubTypeStats(TRANSITION_ARRAY_SUB_TYPE,
                                          fixed_array_size);
     }
@@ -2406,10 +2407,12 @@ void MarkCompactCollector::ClearNonLiveReferences() {
 
 
 void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
-  int number_of_transitions = map->NumberOfProtoTransitions();
-  FixedArray* prototype_transitions = map->GetPrototypeTransitions();
+  FixedArray* prototype_transitions =
+      TransitionArray::GetPrototypeTransitions(map);
+  int number_of_transitions =
+      TransitionArray::NumberOfPrototypeTransitions(prototype_transitions);
 
-  const int header = Map::kProtoTransitionHeaderSize;
+  const int header = TransitionArray::kProtoTransitionHeaderSize;
   int new_number_of_transitions = 0;
   for (int i = 0; i < number_of_transitions; i++) {
     Object* cached_map = prototype_transitions->get(header + i);
@@ -2423,7 +2426,8 @@ void MarkCompactCollector::ClearNonLivePrototypeTransitions(Map* map) {
   }
 
   if (new_number_of_transitions != number_of_transitions) {
-    map->SetNumberOfProtoTransitions(new_number_of_transitions);
+    TransitionArray::SetNumberOfPrototypeTransitions(prototype_transitions,
+                                                     new_number_of_transitions);
   }
 
   // Fill slots that became free with undefined value.
@@ -2444,7 +2448,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);
+    ClearMapTransitions(parent, map);
   }
 }
 
@@ -2458,28 +2462,43 @@ bool MarkCompactCollector::ClearMapBackPointer(Map* target) {
 }
 
 
-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;
+void MarkCompactCollector::ClearMapTransitions(Map* map, Map* dead_transition) {
+  Object* transitions = map->raw_transitions();
+  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
 
-  TransitionArray* t = map->transitions();
+  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;
+  }
 
   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 < t->number_of_transitions(); ++i) {
-    Map* target = t->GetTarget(i);
+  for (int i = 0; i < num_transitions; ++i) {
+    Map* target = TransitionArray::GetTarget(transitions, 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);
@@ -2494,9 +2513,7 @@ 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 (transition_index == t->number_of_transitions()) return;
-
-  int number_of_own_descriptors = map->NumberOfOwnDescriptors();
+  if (transition_index == num_transitions) return;
 
   if (descriptors_owner_died) {
     if (number_of_own_descriptors > 0) {
@@ -2512,14 +2529,17 @@ void MarkCompactCollector::ClearMapTransitions(Map* map) {
   // 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 = t->number_of_transitions_storage() - transition_index;
+  int trim = TransitionArray::Capacity(transitions) - 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, t->IsSimpleTransition() ? trim
-                                   : trim * TransitionArray::kTransitionSize);
+        t, trim * TransitionArray::kTransitionSize);
     t->SetNumberOfTransitions(transition_index);
+    // The map still has a full transition array.
+    DCHECK(TransitionArray::IsFullTransitionArray(map->raw_transitions()));
   }
-  DCHECK(map->HasTransitionArray());
 }
 
 
@@ -4231,7 +4251,7 @@ void MarkCompactCollector::SweepSpaces() {
 
   EvacuateNewSpaceAndCandidates();
 
-  // ClearNonLiveTransitions depends on precise sweeping of map space to
+  // ClearNonLiveReferences 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 82f7ee6..3b0815e 100644 (file)
@@ -812,7 +812,7 @@ class MarkCompactCollector {
   void ClearNonLiveReferences();
   void ClearNonLivePrototypeTransitions(Map* map);
   void ClearNonLiveMapTransitions(Map* map, MarkBit map_mark);
-  void ClearMapTransitions(Map* map);
+  void ClearMapTransitions(Map* map, Map* dead_transition);
   bool ClearMapBackPointer(Map* map);
   void TrimDescriptorArray(Map* map, DescriptorArray* descriptors,
                            int number_of_own_descriptors);
index 58afeae..b4240d2 100644 (file)
@@ -584,18 +584,13 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSDataView(Map* map,
 template <typename StaticVisitor>
 void StaticMarkingVisitor<StaticVisitor>::MarkMapContents(Heap* heap,
                                                           Map* map) {
-  // 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);
+  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));
   }
 
   // Since descriptor arrays are potentially shared, ensure that only the
@@ -631,20 +626,18 @@ 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 ClearNonLiveTransitions.
+    // prototype transitions in ClearNonLiveReferences.
     Object** slot = transitions->GetPrototypeTransitionsSlot();
     HeapObject* obj = HeapObject::cast(*slot);
     heap->mark_compact_collector()->RecordSlot(slot, slot, obj);
     StaticVisitor::MarkObjectWithoutPush(heap, obj);
   }
 
-  for (int i = 0; i < transitions->number_of_transitions(); ++i) {
+  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
+  for (int i = 0; i < num_transitions; ++i) {
     StaticVisitor::VisitPointer(heap, transitions->GetKeySlot(i));
   }
 }
index 831ed20..ca679e7 100644 (file)
@@ -2553,10 +2553,11 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
       number_ = number;
     }
     void LookupTransition(Map* map, Name* name, PropertyAttributes attributes) {
-      int transition_index = map->SearchTransition(kData, name, attributes);
-      if (transition_index == TransitionArray::kNotFound) return NotFound();
+      Map* target =
+          TransitionArray::SearchTransition(map, kData, name, attributes);
+      if (target == NULL) return NotFound();
       lookup_type_ = TRANSITION_TYPE;
-      transition_ = handle(map->GetTransition(transition_index));
+      transition_ = handle(target);
       number_ = transition_->LastAdded();
       details_ = transition_->instance_descriptors()->GetDetails(number_);
     }
index b9a98d4..0cfe446 100644 (file)
@@ -360,19 +360,19 @@ Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() {
         bool follow_expected = false;
         Handle<Map> target;
         if (seq_one_byte) {
-          key = Map::ExpectedTransitionKey(map);
+          key = TransitionArray::ExpectedTransitionKey(map);
           follow_expected = !key.is_null() && ParseJsonString(key);
         }
         // If the expected transition hits, follow it.
         if (follow_expected) {
-          target = Map::ExpectedTransitionTarget(map);
+          target = TransitionArray::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 = Map::FindTransitionToField(map, key);
+          target = TransitionArray::FindTransitionToField(map, key);
           // If a transition was found, follow it and continue.
           transitioning = !target.is_null();
         }
index 78a07c7..b635331 100644 (file)
@@ -320,10 +320,8 @@ void Map::MapVerify() {
   VerifyHeapPointer(prototype());
   VerifyHeapPointer(instance_descriptors());
   SLOW_DCHECK(instance_descriptors()->IsSortedNoDuplicates());
-  if (HasTransitionArray()) {
-    SLOW_DCHECK(transitions()->IsSortedNoDuplicates());
-    SLOW_DCHECK(transitions()->IsConsistentWithBackPointers(this));
-  }
+  SLOW_DCHECK(TransitionArray::IsSortedNoDuplicates(this));
+  SLOW_DCHECK(TransitionArray::IsConsistentWithBackPointers(this));
   // TODO(ishell): turn it back to SLOW_DCHECK.
   CHECK(!FLAG_unbox_double_fields ||
         layout_descriptor()->IsConsistentWithMap(this));
@@ -344,7 +342,6 @@ 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));
@@ -1208,14 +1205,28 @@ 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;
 }
 
 
-bool TransitionArray::IsConsistentWithBackPointers(Map* current_map) {
-  for (int i = 0; i < number_of_transitions(); ++i) {
-    if (!CheckOneBackPointer(current_map, GetTarget(i))) return false;
+// 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;
   }
   return true;
 }
index 97502a9..b3921d6 100644 (file)
@@ -1880,41 +1880,6 @@ 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)
 
@@ -3098,7 +3063,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 {
@@ -5317,22 +5282,6 @@ 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);
@@ -5435,127 +5384,13 @@ Object* Map::GetBackPointer() {
 }
 
 
-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);
-}
-
-
-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);
+Map* Map::ElementsTransitionMap() {
+  return TransitionArray::SearchSpecial(
+      this, GetHeap()->elements_transition_symbol());
 }
 
 
-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);
-}
+ACCESSORS(Map, raw_transitions, Object, kTransitionsOffset)
 
 
 void Map::SetBackPointer(Object* value, WriteBarrierMode mode) {
@@ -5574,6 +5409,7 @@ 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.
@@ -5583,12 +5419,15 @@ 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 3fd1579..1b31c1b 100644 (file)
@@ -432,8 +432,9 @@ void Map::MapPrint(std::ostream& os) {  // NOLINT
   if (FLAG_unbox_double_fields) {
     os << "\n - layout descriptor: " << Brief(layout_descriptor());
   }
-  if (HasTransitionArray()) {
-    os << "\n - transitions: " << Brief(transitions());
+  if (TransitionArray::NumberOfTransitions(raw_transitions()) > 0) {
+    os << "\n - transitions: ";
+    TransitionArray::PrintTransitions(os, raw_transitions());
   }
   os << "\n - prototype: " << Brief(prototype());
   os << "\n - constructor: " << Brief(GetConstructor());
@@ -1138,19 +1139,20 @@ void DescriptorArray::PrintDescriptors(std::ostream& os) {  // NOLINT
 
 void TransitionArray::Print() {
   OFStream os(stdout);
-  this->PrintTransitions(os);
+  TransitionArray::PrintTransitions(os, this);
   os << std::flush;
 }
 
 
-void TransitionArray::PrintTransitions(std::ostream& os,
+void TransitionArray::PrintTransitions(std::ostream& os, Object* transitions,
                                        bool print_header) {  // NOLINT
+  int num_transitions = NumberOfTransitions(transitions);
   if (print_header) {
-    os << "Transition array " << number_of_transitions() << "\n";
+    os << "Transition array " << num_transitions << "\n";
   }
-  for (int i = 0; i < number_of_transitions(); i++) {
-    Name* key = GetKey(i);
-    Map* target = GetTarget(i);
+  for (int i = 0; i < num_transitions; i++) {
+    Name* key = GetKey(transitions, i);
+    Map* target = GetTarget(transitions, i);
     os << "   ";
 #ifdef OBJECT_PRINT
     key->NamePrint(os);
@@ -1158,16 +1160,17 @@ void TransitionArray::PrintTransitions(std::ostream& os,
     key->ShortPrint(os);
 #endif
     os << ": ";
-    if (key == GetHeap()->nonextensible_symbol()) {
+    Heap* heap = key->GetHeap();
+    if (key == heap->nonextensible_symbol()) {
       os << " (transition to non-extensible)";
-    } else if (key == GetHeap()->sealed_symbol()) {
+    } else if (key == heap->sealed_symbol()) {
       os << " (transition to sealed)";
-    } else if (key == GetHeap()->frozen_symbol()) {
+    } else if (key == heap->frozen_symbol()) {
       os << " (transition to frozen)";
-    } else if (key == GetHeap()->elements_transition_symbol()) {
+    } else if (key == heap->elements_transition_symbol()) {
       os << " (transition to " << ElementsKindToString(target->elements_kind())
          << ")";
-    } else if (key == GetHeap()->observed_symbol()) {
+    } else if (key == heap->observed_symbol()) {
       os << " (transition to Object.observe)";
     } else {
       PropertyDetails details = GetTargetDetails(key, target);
@@ -1177,7 +1180,9 @@ void TransitionArray::PrintTransitions(std::ostream& os,
       }
       os << (details.kind() == kData ? "data" : "accessor");
       if (details.location() == kDescriptor) {
-        os << " " << Brief(GetTargetValue(i));
+        Object* value =
+            target->instance_descriptors()->GetValue(target->LastAdded());
+        os << " " << Brief(value);
       }
       os << "), attrs: " << details.attributes();
     }
@@ -1187,8 +1192,7 @@ void TransitionArray::PrintTransitions(std::ostream& os,
 
 
 void JSObject::PrintTransitions(std::ostream& os) {  // NOLINT
-  if (!map()->HasTransitionArray()) return;
-  map()->transitions()->PrintTransitions(os, false);
+  TransitionArray::PrintTransitions(os, map()->raw_transitions());
 }
 #endif  // defined(DEBUG) || defined(OBJECT_PRINT)
 } }  // namespace v8::internal
index ad40130..5adc909 100644 (file)
@@ -1900,7 +1900,8 @@ 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(!old_map->HasTransitionArray());
+        DCHECK_EQ(0, TransitionArray::NumberOfTransitions(
+                         old_map->raw_transitions()));
         DCHECK(new_map->GetBackPointer()->IsUndefined());
       }
     } else {
@@ -2186,11 +2187,10 @@ Handle<Map> Map::CopyGeneralizeAllRepresentations(
 
 void Map::DeprecateTransitionTree() {
   if (is_deprecated()) return;
-  if (HasTransitionArray()) {
-    TransitionArray* transitions = this->transitions();
-    for (int i = 0; i < transitions->number_of_transitions(); i++) {
-      transitions->GetTarget(i)->DeprecateTransitionTree();
-    }
+  Object* transitions = raw_transitions();
+  int num_transitions = TransitionArray::NumberOfTransitions(transitions);
+  for (int i = 0; i < num_transitions; ++i) {
+    TransitionArray::GetTarget(transitions, i)->DeprecateTransitionTree();
   }
   deprecate();
   dependent_code()->DeoptimizeDependentCodeGroup(
@@ -2215,13 +2215,11 @@ bool Map::DeprecateTarget(PropertyKind kind, Name* key,
                           DescriptorArray* new_descriptors,
                           LayoutDescriptor* new_layout_descriptor) {
   bool transition_target_deprecated = false;
-  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;
-    }
+  Map* maybe_transition =
+      TransitionArray::SearchTransition(this, kind, key, attributes);
+  if (maybe_transition != NULL) {
+    maybe_transition->DeprecateTransitionTree();
+    transition_target_deprecated = true;
   }
 
   // Don't overwrite the empty descriptor array.
@@ -2264,15 +2262,11 @@ 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);
-    TransitionArray* transitions = current->transitions();
-    int transition =
-        transitions->Search(details.kind(), name, details.attributes());
-    if (transition == TransitionArray::kNotFound) break;
-
-    Map* next = transitions->GetTarget(transition);
+    Map* next = TransitionArray::SearchTransition(current, details.kind(), name,
+                                                  details.attributes());
+    if (next == NULL) break;
     DescriptorArray* next_descriptors = next->instance_descriptors();
 
     PropertyDetails next_details = next_descriptors->GetDetails(i);
@@ -2320,12 +2314,12 @@ void Map::UpdateFieldType(int descriptor, Handle<Name> name,
   DisallowHeapAllocation no_allocation;
   PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
   if (details.type() != DATA) return;
-  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);
-    }
+  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);
   }
   // It is allowed to change representation here only from None to something.
   DCHECK(details.representation().Equals(new_representation) ||
@@ -2565,10 +2559,11 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
       next_attributes = old_details.attributes();
       next_representation = old_details.representation();
     }
-    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);
+    Map* transition = TransitionArray::SearchTransition(
+        *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
+    if (transition == NULL) break;
+    Handle<Map> tmp_map(transition, isolate);
+
     Handle<DescriptorArray> tmp_descriptors = handle(
         tmp_map->instance_descriptors(), isolate);
 
@@ -2653,10 +2648,10 @@ Handle<Map> Map::ReconfigureProperty(Handle<Map> old_map, int modify_index,
       next_kind = old_details.kind();
       next_attributes = old_details.attributes();
     }
-    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);
+    Map* transition = TransitionArray::SearchTransition(
+        *target_map, next_kind, old_descriptors->GetKey(i), next_attributes);
+    if (transition == NULL) break;
+    Handle<Map> tmp_map(transition, isolate);
     Handle<DescriptorArray> tmp_descriptors(
         tmp_map->instance_descriptors(), isolate);
 
@@ -2894,7 +2889,8 @@ 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 && !split_map->CanHaveMoreTransitions()) {
+  if (!transition_target_deprecated &&
+      !TransitionArray::CanHaveMoreTransitions(split_map)) {
     return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
                                             new_kind, new_attributes,
                                             "GenAll_CantHaveMoreTransitions");
@@ -2967,11 +2963,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);
-    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);
+    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;
     DescriptorArray* new_descriptors = new_map->instance_descriptors();
 
     PropertyDetails new_details = new_descriptors->GetDetails(i);
@@ -3613,9 +3609,9 @@ static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
   // have the cached transition.
   if (IsExternalArrayElementsKind(to_kind) &&
       !IsFixedTypedArrayElementsKind(map->elements_kind())) {
-    if (map->HasElementsTransition()) {
-        Map* next_map = map->elements_transition_map();
-        if (next_map->elements_kind() == to_kind) return next_map;
+    Map* next_map = map->ElementsTransitionMap();
+    if (next_map != NULL && next_map->elements_kind() == to_kind) {
+      return next_map;
     }
     return map;
   }
@@ -3623,13 +3619,14 @@ static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
   ElementsKind kind = map->elements_kind();
   while (kind != target_kind) {
     kind = GetNextTransitionElementsKind(kind);
-    if (!current_map->HasElementsTransition()) return current_map;
-    current_map = current_map->elements_transition_map();
+    Map* next_map = current_map->ElementsTransitionMap();
+    if (next_map == NULL) return current_map;
+    current_map = next_map;
   }
 
-  if (to_kind != kind && current_map->HasElementsTransition()) {
+  Map* next_map = current_map->ElementsTransitionMap();
+  if (to_kind != kind && next_map != NULL) {
     DCHECK(to_kind == DICTIONARY_ELEMENTS);
-    Map* next_map = current_map->elements_transition_map();
     if (next_map->elements_kind() == to_kind) return next_map;
   }
 
@@ -5704,13 +5701,15 @@ MaybeHandle<Object> JSObject::PreventExtensionsWithTransition(
   }
 
   Handle<Map> old_map(object->map(), isolate);
-  int transition_index = old_map->SearchSpecialTransition(*transition_marker);
-  if (transition_index != TransitionArray::kNotFound) {
-    Handle<Map> transition_map(old_map->GetTransition(transition_index));
+  Map* transition =
+      TransitionArray::SearchSpecial(*old_map, *transition_marker);
+  if (transition != NULL) {
+    Handle<Map> transition_map(transition, isolate);
     DCHECK(transition_map->has_dictionary_elements());
     DCHECK(!transition_map->is_extensible());
     JSObject::MigrateToMap(object, transition_map);
-  } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
+  } else if (object->HasFastProperties() &&
+             TransitionArray::CanHaveMoreTransitions(old_map)) {
     // Create a new descriptor array with the appropriate property attributes
     Handle<Map> new_map = Map::CopyForPreventExtensions(
         old_map, attrs, transition_marker, "CopyForPreventExtensions");
@@ -5769,12 +5768,13 @@ void JSObject::SetObserved(Handle<JSObject> object) {
   Handle<Map> new_map;
   Handle<Map> old_map(object->map(), isolate);
   DCHECK(!old_map->is_observed());
-  int transition_index =
-      old_map->SearchSpecialTransition(isolate->heap()->observed_symbol());
-  if (transition_index != TransitionArray::kNotFound) {
-    new_map = handle(old_map->GetTransition(transition_index), isolate);
+  Map* transition = TransitionArray::SearchSpecial(
+      *old_map, isolate->heap()->observed_symbol());
+  if (transition != NULL) {
+    new_map = handle(transition, isolate);
     DCHECK(new_map->is_observed());
-  } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
+  } else if (object->HasFastProperties() &&
+             TransitionArray::CanHaveMoreTransitions(old_map)) {
     new_map = Map::CopyForObserved(old_map);
   } else {
     new_map = Map::Copy(old_map, "SlowObserved");
@@ -6993,11 +6993,12 @@ void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
 
 // static
 void Map::TraceAllTransitions(Map* map) {
-  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));
+  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);
     Map::TraceAllTransitions(target);
   }
 }
@@ -7014,13 +7015,7 @@ void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
     Map::TraceTransition("NoTransition", *parent, *child, *name);
 #endif
   } else {
-    Handle<TransitionArray> transitions =
-        TransitionArray::Insert(parent, name, child, flag);
-    if (!parent->HasTransitionArray() ||
-        *transitions != parent->transitions()) {
-      parent->set_transitions(*transitions);
-    }
-    child->SetBackPointer(*parent);
+    TransitionArray::Insert(parent, name, child, flag);
     if (child->prototype()->IsJSObject()) {
       Handle<JSObject> proto(JSObject::cast(child->prototype()));
       if (!child->ShouldRegisterAsPrototypeUser(proto)) {
@@ -7044,7 +7039,8 @@ Handle<Map> Map::CopyReplaceDescriptors(
   Handle<Map> result = CopyDropDescriptors(map);
 
   if (!map->is_prototype_map()) {
-    if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) {
+    if (flag == INSERT_TRANSITION &&
+        TransitionArray::CanHaveMoreTransitions(map)) {
       result->InitializeDescriptors(*descriptors, *layout_descriptor);
 
       Handle<Name> name;
@@ -7068,7 +7064,8 @@ Handle<Map> Map::CopyReplaceDescriptors(
   if (FLAG_trace_maps &&
       // Mirror conditions above that did not call ConnectTransition().
       (map->is_prototype_map() ||
-       !(flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()))) {
+       !(flag == INSERT_TRANSITION &&
+         TransitionArray::CanHaveMoreTransitions(map)))) {
     PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
            reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
            reason);
@@ -7126,22 +7123,24 @@ 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) {
-    DCHECK(!map->HasElementsTransition() ||
-        ((map->elements_transition_map()->elements_kind() ==
-          DICTIONARY_ELEMENTS ||
+    maybe_elements_transition_map = map->ElementsTransitionMap();
+    DCHECK(
+        maybe_elements_transition_map == NULL ||
+        ((maybe_elements_transition_map->elements_kind() ==
+              DICTIONARY_ELEMENTS ||
           IsExternalArrayElementsKind(
-              map->elements_transition_map()->elements_kind())) &&
-         (kind == DICTIONARY_ELEMENTS ||
-          IsExternalArrayElementsKind(kind))));
+              maybe_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 &&
-                           map->CanHaveMoreTransitions() &&
-                           !map->HasElementsTransition();
+                           TransitionArray::CanHaveMoreTransitions(map) &&
+                           maybe_elements_transition_map == NULL;
 
   if (insert_transition) {
     Handle<Map> new_map = CopyForTransition(map, "CopyAsElementsKind");
@@ -7165,7 +7164,7 @@ Handle<Map> Map::CopyForObserved(Handle<Map> map) {
   Isolate* isolate = map->GetIsolate();
 
   bool insert_transition =
-      map->CanHaveMoreTransitions() && !map->is_prototype_map();
+      TransitionArray::CanHaveMoreTransitions(map) && !map->is_prototype_map();
 
   if (insert_transition) {
     Handle<Map> new_map = CopyForTransition(map, "CopyForObserved");
@@ -7331,9 +7330,10 @@ Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
   // Migrate to the newest map before storing the property.
   map = Update(map);
 
-  int index = map->SearchTransition(kData, *name, attributes);
-  if (index != TransitionArray::kNotFound) {
-    Handle<Map> transition(map->GetTransition(index));
+  Map* maybe_transition =
+      TransitionArray::SearchTransition(*map, kData, *name, attributes);
+  if (maybe_transition != NULL) {
+    Handle<Map> transition(maybe_transition);
     int descriptor = transition->LastAdded();
 
     DCHECK_EQ(attributes, transition->instance_descriptors()
@@ -7422,9 +7422,10 @@ Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
                                        ? KEEP_INOBJECT_PROPERTIES
                                        : CLEAR_INOBJECT_PROPERTIES;
 
-  int index = map->SearchTransition(kAccessor, *name, attributes);
-  if (index != TransitionArray::kNotFound) {
-    Handle<Map> transition(map->GetTransition(index));
+  Map* maybe_transition =
+      TransitionArray::SearchTransition(*map, kAccessor, *name, attributes);
+  if (maybe_transition != NULL) {
+    Handle<Map> transition(maybe_transition, isolate);
     DescriptorArray* descriptors = transition->instance_descriptors();
     int descriptor = transition->LastAdded();
     DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
@@ -7496,9 +7497,8 @@ Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
   // Ensure the key is unique.
   descriptor->KeyToUniqueName();
 
-  if (flag == INSERT_TRANSITION &&
-      map->owns_descriptors() &&
-      map->CanHaveMoreTransitions()) {
+  if (flag == INSERT_TRANSITION && map->owns_descriptors() &&
+      TransitionArray::CanHaveMoreTransitions(map)) {
     return ShareDescriptor(map, descriptors, descriptor);
   }
 
@@ -7662,38 +7662,6 @@ 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
@@ -9898,10 +9866,10 @@ void JSFunction::CompleteInobjectSlackTracking() {
   map->set_counter(Map::kRetainingCounterStart);
 
   int slack = map->unused_property_fields();
-  map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
+  TransitionArray::TraverseTransitionTree(map, &GetMinInobjectSlack, &slack);
   if (slack != 0) {
     // Resize the initial map and all maps in its transition tree.
-    map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
+    TransitionArray::TraverseTransitionTree(map, &ShrinkInstanceSize, &slack);
   }
 }
 
@@ -10054,8 +10022,9 @@ Handle<Object> CacheInitialJSArrayMaps(
        i < kFastElementsKindCount; ++i) {
     Handle<Map> new_map;
     ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
-    if (current_map->HasElementsTransition()) {
-      new_map = handle(current_map->elements_transition_map());
+    Map* maybe_elements_transition = current_map->ElementsTransitionMap();
+    if (maybe_elements_transition != NULL) {
+      new_map = handle(maybe_elements_transition);
       DCHECK(new_map->elements_kind() == next_kind);
     } else {
       new_map = Map::CopyAsElementsKind(
@@ -11976,77 +11945,6 @@ 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,
@@ -12352,10 +12250,10 @@ const char* DependentCode::DependencyGroupName(DependencyGroup group) {
 Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
                                        Handle<Object> prototype,
                                        PrototypeOptimizationMode mode) {
-  Handle<Map> new_map = GetPrototypeTransition(map, prototype);
+  Handle<Map> new_map = TransitionArray::GetPrototypeTransition(map, prototype);
   if (new_map.is_null()) {
     new_map = Copy(map, "TransitionToPrototype");
-    PutPrototypeTransition(map, prototype, new_map);
+    TransitionArray::PutPrototypeTransition(map, prototype, new_map);
     new_map->SetPrototype(prototype, mode);
   }
   return new_map;
index a74db7b..ff23e87 100644 (file)
@@ -5892,26 +5892,14 @@ class Map: public HeapObject {
   // map with DICTIONARY_ELEMENTS was found in the prototype chain.
   bool DictionaryElementsInPrototypeChainOnly();
 
-  inline bool HasTransitionArray() const;
-  inline bool HasElementsTransition();
-  inline Map* elements_transition_map();
+  inline Map* ElementsTransitionMap();
 
-  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(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);
+  // [raw_transitions]: Provides access to the transitions storage field.
+  // Don't call set_raw_transitions() directly to overwrite transitions, use
+  // the TransitionArray::ReplaceTransitions() wrapper instead!
+  DECL_ACCESSORS(raw_transitions, Object)
 
   Map* FindRootMap();
   Map* FindFieldOwner(int descriptor);
@@ -5985,6 +5973,8 @@ 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);
@@ -6017,38 +6007,8 @@ 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);
@@ -6216,11 +6176,6 @@ 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();
 
@@ -6286,18 +6241,6 @@ 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);
@@ -6311,6 +6254,10 @@ 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;
@@ -6453,15 +6400,6 @@ 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,
@@ -6490,16 +6428,6 @@ 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 fd8eb8b..f31eff9 100644 (file)
@@ -11,55 +11,19 @@ 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 IsFullTransitionArray() &&
-      get(kPrototypeTransitionsIndex) != Smi::FromInt(0);
+  return get(kPrototypeTransitionsIndex) != Smi::FromInt(0);
 }
 
 
 FixedArray* TransitionArray::GetPrototypeTransitions() {
-  DCHECK(IsFullTransitionArray());
+  DCHECK(HasPrototypeTransitions());  // Callers must check first.
   Object* prototype_transitions = get(kPrototypeTransitionsIndex);
   return FixedArray::cast(prototype_transitions);
 }
@@ -67,88 +31,68 @@ FixedArray* TransitionArray::GetPrototypeTransitions() {
 
 void TransitionArray::SetPrototypeTransitions(FixedArray* transitions,
                                               WriteBarrierMode mode) {
-  DCHECK(IsFullTransitionArray());
   DCHECK(transitions->IsFixedArray());
-  Heap* heap = GetHeap();
-  WRITE_FIELD(this, kPrototypeTransitionsOffset, transitions);
-  CONDITIONAL_WRITE_BARRIER(
-      heap, this, kPrototypeTransitionsOffset, transitions, mode);
+  set(kPrototypeTransitionsIndex, transitions, mode);
 }
 
 
 Object** TransitionArray::GetPrototypeTransitionsSlot() {
-  return HeapObject::RawField(reinterpret_cast<HeapObject*>(this),
-                              kPrototypeTransitionsOffset);
+  return RawFieldOfElementAt(kPrototypeTransitionsIndex);
 }
 
 
 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)));
 }
 
 
-void TransitionArray::SetTarget(int transition_number, Map* value) {
-  if (IsSimpleTransition()) {
-    DCHECK(transition_number == kSimpleTransitionIndex);
-    return set(kSimpleTransitionTarget, value);
+Map* TransitionArray::GetTarget(Object* raw_transitions,
+                                int transition_number) {
+  if (IsSimpleTransition(raw_transitions)) {
+    DCHECK(transition_number == 0);
+    return GetSimpleTransition(raw_transitions);
   }
-  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();
+  DCHECK(IsFullTransitionArray(raw_transitions));
+  return TransitionArray::cast(raw_transitions)->GetTarget(transition_number);
 }
 
 
-Object* TransitionArray::GetTargetValue(int transition_number) {
-  Map* map = GetTarget(transition_number);
-  return map->instance_descriptors()->GetValue(map->LastAdded());
+void TransitionArray::SetTarget(int transition_number, Map* value) {
+  DCHECK(transition_number < number_of_transitions());
+  set(ToTargetIndex(transition_number), value);
 }
 
 
 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);
 }
 
@@ -225,19 +169,10 @@ void TransitionArray::NoIncrementalWriteBarrierSet(int transition_number,
 
 
 void TransitionArray::SetNumberOfTransitions(int number_of_transitions) {
-  if (IsFullTransitionArray()) {
-    DCHECK(number_of_transitions <= number_of_transitions_storage());
-    WRITE_FIELD(this, kTransitionLengthOffset,
-                Smi::FromInt(number_of_transitions));
-  }
+  DCHECK(number_of_transitions <= Capacity(this));
+  set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
 }
 
-
-#undef FIELD_ADDR
-#undef WRITE_FIELD
-#undef CONDITIONAL_WRITE_BARRIER
-
-
 } }  // namespace v8::internal
 
 #endif  // V8_TRANSITIONS_INL_H_
index 43fc90b..fa5ed7b 100644 (file)
@@ -12,141 +12,110 @@ namespace v8 {
 namespace internal {
 
 
-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;
-}
-
-
-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);
+// 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);
+      ReplaceTransitions(map, *cell);
+      return;
+    }
+    // If the flag requires a full TransitionArray, allocate one.
+    Handle<TransitionArray> result = Allocate(isolate, 0, 1);
+    ReplaceTransitions(map, *result);
   }
 
-  result->set_back_pointer_storage(
-      containing_map->transitions()->back_pointer_storage());
-  return result;
-}
-
-
-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);
+  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);
+      ReplaceTransitions(map, *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);
+    }
+    ReplaceTransitions(map, *result);
   }
 
-  int number_of_transitions = map->transitions()->number_of_transitions();
-  int new_nof = number_of_transitions;
+  // At this point, we know that the map has a full TransitionArray.
+  DCHECK(IsFullTransitionArray(map->raw_transitions()));
 
-  bool is_special_transition = flag == SPECIAL_TRANSITION;
+  int number_of_transitions = 0;
+  int new_nof = 0;
+  int insertion_index = kNotFound;
   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 = map->transitions();
+    TransitionArray* array = TransitionArray::cast(map->raw_transitions());
+    number_of_transitions = array->number_of_transitions();
+    new_nof = number_of_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 handle(array);
+      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));
+    ++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->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 grown smaller during the allocation above as
+  // The map's transition array may have shrunk 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(map->HasTransitionArray());
+  DCHECK(IsFullTransitionArray(map->raw_transitions()));
   DisallowHeapAllocation no_gc;
-  TransitionArray* array = map->transitions();
+  TransitionArray* array = TransitionArray::cast(map->raw_transitions());
   if (array->number_of_transitions() != number_of_transitions) {
     DCHECK(array->number_of_transitions() < number_of_transitions);
 
@@ -154,11 +123,11 @@ Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map,
     new_nof = number_of_transitions;
 
     insertion_index = kNotFound;
-    index = is_special_transition ? map->transitions()->SearchSpecial(
-                                        Symbol::cast(*name), &insertion_index)
-                                  : map->transitions()->Search(
-                                        details.kind(), *name,
-                                        details.attributes(), &insertion_index);
+    int index =
+        is_special_transition
+            ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
+            : array->Search(details.kind(), *name, details.attributes(),
+                            &insertion_index);
     if (index == kNotFound) {
       ++new_nof;
     } else {
@@ -183,12 +152,332 @@ Handle<TransitionArray> TransitionArray::Insert(Handle<Map> map,
     result->NoIncrementalWriteBarrierCopyFrom(array, i, i + 1);
   }
 
-  result->set_back_pointer_storage(array->back_pointer_storage());
   SLOW_DCHECK(result->IsSortedNoDuplicates());
-  return result;
+  ReplaceTransitions(map, *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;
 }
 
 
+// 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 999ad86..648559b 100644 (file)
@@ -16,47 +16,98 @@ namespace internal {
 
 
 // TransitionArrays are fixed arrays used to hold map transitions for property,
-// constant, and element changes. They can either be simple transition arrays
-// that store a single property transition, or a full transition array that has
+// 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
 // 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.
 //
-// The simple format of the these objects is:
-// [0] Undefined or back pointer map
-// [1] Single transition
+// This class provides a static interface that operates directly on maps
+// and handles the distinction between simple and full transitions storage.
 //
 // The full format is:
-// [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
+// [0] Smi(0) or fixed array of prototype transitions
+// [1] Number of transitions
+// [2] First transition
+// [2 + number of transitions * kTransitionSize]: start of slack
 class TransitionArray: public FixedArray {
  public:
-  // 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; }
+  // 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);
 
-  Name* GetSortedKey(int transition_number) {
-    return GetKey(transition_number);
-  }
+  static Map* SearchTransition(Map* map, PropertyKind kind, Name* name,
+                               PropertyAttributes attributes);
 
-  inline Map* GetTarget(int transition_number);
-  inline void SetTarget(int transition_number, Map* target);
+  static Map* SearchSpecial(Map* map, Symbol* name);
 
-  inline PropertyDetails GetTargetDetails(int transition_number);
-  inline Object* GetTargetValue(int transition_number);
+  static Handle<Map> FindTransitionToField(Handle<Map> map, Handle<Name> name);
 
-  inline bool HasElementsTransition();
+  static Handle<String> ExpectedTransitionKey(Handle<Map> map);
 
-  inline Object* back_pointer_storage();
-  inline void set_back_pointer_storage(
-      Object* back_pointer,
-      WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+  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();
+  }
+
+  // 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();
+  }
+
+  static void SetNumberOfPrototypeTransitions(FixedArray* proto_transitions,
+                                              int value);
 
   inline FixedArray* GetPrototypeTransitions();
   inline void SetPrototypeTransitions(
@@ -65,133 +116,92 @@ class TransitionArray: public FixedArray {
   inline Object** GetPrototypeTransitionsSlot();
   inline bool HasPrototypeTransitions();
 
-  // 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();
-  }
+  // ===== ITERATION =====
 
-  int number_of_transitions_storage() {
-    if (IsSimpleTransition()) return 1;
-    if (length() <= kFirstIndex) return 0;
-    return (length() - kFirstIndex) / kTransitionSize;
-  }
+  typedef void (*TraverseCallback)(Map* map, void* data);
 
-  int NumberOfSlackTransitions() {
-    return number_of_transitions_storage() - number_of_transitions();
+  // 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);
   }
 
-  inline void SetNumberOfTransitions(int number_of_transitions);
-  inline int number_of_entries() { return number_of_transitions(); }
+  // ===== LOW-LEVEL ACCESSORS =====
 
-  // 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);
+  // 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; }
 
-  // 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);
+  Name* GetSortedKey(int transition_number) {
+    return GetKey(transition_number);
   }
 
+  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);
 
-  // Allocates a TransitionArray.
-  static Handle<TransitionArray> Allocate(Isolate* isolate,
-                                          int number_of_transitions,
-                                          int slack = 0);
+  // 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(); }
 
-  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();
-  }
+  inline void SetNumberOfTransitions(int number_of_transitions);
 
-  bool IsFullTransitionArray() {
-    return length() > kFirstIndex ||
-        (length() == kFirstIndex && !IsSimpleTransition());
-  }
+  static int Capacity(Object* raw_transitions);
 
   // 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.
-  void PrintTransitions(std::ostream& os, bool print_header = true);  // NOLINT
+  static void PrintTransitions(std::ostream& os, Object* transitions,
+                               bool print_header = true);  // NOLINT
 #endif
 
 #ifdef DEBUG
   bool IsSortedNoDuplicates(int valid_entries = -1);
-  bool IsConsistentWithBackPointers(Map* current_map);
-  bool IsEqualTo(TransitionArray* other);
+  static bool IsSortedNoDuplicates(Map* map);
+  static bool IsConsistentWithBackPointers(Map* map);
 
   // 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;
 
-  // 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:
+  // 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);
+
   // Conversion from transition number to array indices.
   static int ToKeyIndex(int transition_number) {
     return kFirstIndex +
@@ -205,20 +215,55 @@ class TransitionArray: public FixedArray {
            kTransitionTarget;
   }
 
-  static Handle<TransitionArray> AllocateSimple(
-      Isolate* isolate, Handle<Map> target);
+  // 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);
 
-  // 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  transition for a given kind, property name and attributes.
+  int Search(PropertyKind kind, Name* name, PropertyAttributes attributes,
+             int* out_insertion_index = NULL);
 
+  // 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,
@@ -247,6 +292,12 @@ 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 047cd92..d46d59a 100644 (file)
@@ -2142,6 +2142,12 @@ TEST(InstanceOfStubWriteBarrier) {
 }
 
 
+static int NumberOfProtoTransitions(Map* map) {
+  return TransitionArray::NumberOfPrototypeTransitions(
+      TransitionArray::GetPrototypeTransitions(map));
+}
+
+
 TEST(PrototypeTransitionClearing) {
   if (FLAG_never_compact) return;
   CcTest::InitializeVM();
@@ -2154,7 +2160,7 @@ TEST(PrototypeTransitionClearing) {
       v8::Utils::OpenHandle(
           *v8::Handle<v8::Object>::Cast(
               CcTest::global()->Get(v8_str("base"))));
-  int initialTransitions = baseObject->map()->NumberOfProtoTransitions();
+  int initialTransitions = NumberOfProtoTransitions(baseObject->map());
 
   CompileRun(
       "var live = [];"
@@ -2167,16 +2173,17 @@ TEST(PrototypeTransitionClearing) {
 
   // Verify that only dead prototype transitions are cleared.
   CHECK_EQ(initialTransitions + 10,
-      baseObject->map()->NumberOfProtoTransitions());
+           NumberOfProtoTransitions(baseObject->map()));
   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   const int transitions = 10 - 3;
   CHECK_EQ(initialTransitions + transitions,
-      baseObject->map()->NumberOfProtoTransitions());
+           NumberOfProtoTransitions(baseObject->map()));
 
   // Verify that prototype transitions array was compacted.
-  FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
+  FixedArray* trans =
+      TransitionArray::GetPrototypeTransitions(baseObject->map());
   for (int i = initialTransitions; i < initialTransitions + transitions; i++) {
-    int j = Map::kProtoTransitionHeaderSize + i;
+    int j = TransitionArray::kProtoTransitionHeaderSize + i;
     CHECK(trans->get(j)->IsMap());
   }
 
@@ -2194,7 +2201,7 @@ TEST(PrototypeTransitionClearing) {
   i::FLAG_always_compact = true;
   Handle<Map> map(baseObject->map());
   CHECK(!space->LastPage()->Contains(
-      map->GetPrototypeTransitions()->address()));
+      TransitionArray::GetPrototypeTransitions(*map)->address()));
   CHECK(space->LastPage()->Contains(prototype->address()));
 }
 
@@ -2877,7 +2884,7 @@ TEST(OptimizedAllocationArrayLiterals) {
 
 
 static int CountMapTransitions(Map* map) {
-  return map->transitions()->number_of_transitions();
+  return TransitionArray::NumberOfTransitions(map->raw_transitions());
 }
 
 
@@ -3058,7 +3065,7 @@ TEST(TransitionArraySimpleToFull) {
   CompileRun("o = new F;"
              "root = new F");
   root = GetByName("root");
-  DCHECK(root->map()->transitions()->IsSimpleTransition());
+  DCHECK(TransitionArray::IsSimpleTransition(root->map()->raw_transitions()));
   AddPropertyTo(2, root, "happy");
 
   // Count number of live transitions after marking.  Note that one transition
index c7aaf29..3be1734 100644 (file)
@@ -342,9 +342,10 @@ class Expectations {
     SetDataField(property_index, attributes, representation, heap_type);
 
     Handle<String> name = MakeName("prop", property_index);
-    int t = map->SearchTransition(kData, *name, attributes);
-    CHECK_NE(TransitionArray::kNotFound, t);
-    return handle(map->GetTransition(t));
+    Map* target =
+        TransitionArray::SearchTransition(*map, kData, *name, attributes);
+    CHECK(target != NULL);
+    return handle(target);
   }
 
   Handle<Map> AddAccessorConstant(Handle<Map> map,
@@ -1477,9 +1478,10 @@ TEST(ReconfigurePropertySplitMapTransitionsOverflow) {
       }
 
       Handle<String> name = MakeName("prop", i);
-      int t = map2->SearchTransition(kData, *name, NONE);
-      CHECK_NE(TransitionArray::kNotFound, t);
-      map2 = handle(map2->GetTransition(t));
+      Map* target =
+          TransitionArray::SearchTransition(*map2, kData, *name, NONE);
+      CHECK(target != NULL);
+      map2 = handle(target);
     }
 
     map2 = Map::ReconfigureProperty(map2, kSplitProp, kData, NONE,
@@ -1499,12 +1501,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(map2->CanHaveMoreTransitions());
+    CHECK(TransitionArray::CanHaveMoreTransitions(map2));
     Handle<String> name = MakeName("foo", i);
     Map::CopyWithField(map2, name, any_type, NONE, Representation::Smi(),
                        INSERT_TRANSITION).ToHandleChecked();
   }
-  CHECK(!map2->CanHaveMoreTransitions());
+  CHECK(!TransitionArray::CanHaveMoreTransitions(map2));
 
   // Try to update |map|, since there is no place for propX transition at |map2|
   // |map| should become "copy-generalized".
index 59c9f74..800c2a0 100644 (file)
@@ -20,16 +20,6 @@ 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) {
@@ -69,34 +59,32 @@ TEST(TransitionArray_SimpleFieldTransitions) {
                          attributes, Representation::Tagged(),
                          OMIT_TRANSITION).ToHandleChecked();
 
-  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());
+  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));
 }
 
 
@@ -120,31 +108,32 @@ TEST(TransitionArray_FullFieldTransitions) {
                          attributes, Representation::Tagged(),
                          OMIT_TRANSITION).ToHandleChecked();
 
-  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());
-
-  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));
+  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));
+  }
 
-  DCHECK(transitions->IsSortedNoDuplicates());
+  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
 }
 
 
@@ -160,9 +149,7 @@ TEST(TransitionArray_DifferentFieldNames) {
   PropertyAttributes attributes = NONE;
 
   Handle<Map> map0 = Map::Create(isolate, 0);
-  CHECK(!map0->HasTransitionArray());
-  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
-  CHECK(transitions->IsFullTransitionArray());
+  CHECK(map0->raw_transitions()->IsSmi());
 
   for (int i = 0; i < PROPS_COUNT; i++) {
     EmbeddedVector<char, 64> buffer;
@@ -175,17 +162,25 @@ TEST(TransitionArray_DifferentFieldNames) {
     names[i] = name;
     maps[i] = map;
 
-    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
-    ConnectTransition(map0, transitions, map);
+    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
   }
 
   for (int i = 0; i < PROPS_COUNT; i++) {
-    int transition = transitions->Search(kData, *names[i], attributes);
-    CHECK_EQ(*names[i], transitions->GetKey(transition));
-    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
+    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;
+      }
+    }
   }
 
-  DCHECK(transitions->IsSortedNoDuplicates());
+  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
 }
 
 
@@ -196,9 +191,7 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
   Factory* factory = isolate->factory();
 
   Handle<Map> map0 = Map::Create(isolate, 0);
-  CHECK(!map0->HasTransitionArray());
-  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
-  CHECK(transitions->IsFullTransitionArray());
+  CHECK(map0->raw_transitions()->IsSmi());
 
   const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
   STATIC_ASSERT(ATTRS_COUNT == 8);
@@ -215,20 +208,20 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
                            OMIT_TRANSITION).ToHandleChecked();
     attr_maps[i] = map;
 
-    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
-    ConnectTransition(map0, transitions, map);
+    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
   }
 
   // Ensure that transitions for |name| field are valid.
   for (int i = 0; i < ATTRS_COUNT; i++) {
     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));
+    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));
   }
 
-  DCHECK(transitions->IsSortedNoDuplicates());
+  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
 }
 
 
@@ -243,9 +236,7 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
   Handle<Map> maps[PROPS_COUNT];
 
   Handle<Map> map0 = Map::Create(isolate, 0);
-  CHECK(!map0->HasTransitionArray());
-  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
-  CHECK(transitions->IsFullTransitionArray());
+  CHECK(map0->raw_transitions()->IsSmi());
 
   // Some number of fields.
   for (int i = 0; i < PROPS_COUNT; i++) {
@@ -259,8 +250,7 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
     names[i] = name;
     maps[i] = map;
 
-    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
-    ConnectTransition(map0, transitions, map);
+    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
   }
 
   const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
@@ -278,25 +268,36 @@ TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
                            OMIT_TRANSITION).ToHandleChecked();
     attr_maps[i] = map;
 
-    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
-    ConnectTransition(map0, transitions, map);
+    TransitionArray::Insert(map0, name, map, PROPERTY_TRANSITION);
   }
 
   // Ensure that transitions for |name| field are valid.
   for (int i = 0; i < ATTRS_COUNT; i++) {
-    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));
+    PropertyAttributes attr = static_cast<PropertyAttributes>(i);
+    CHECK_EQ(*attr_maps[i],
+             TransitionArray::SearchTransition(*map0, kData, *name, attr));
   }
 
   // Ensure that info about the other fields still valid.
-  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));
+  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;
+        }
+      }
+    }
   }
 
-  DCHECK(transitions->IsSortedNoDuplicates());
+  DCHECK(TransitionArray::IsSortedNoDuplicates(*map0));
 }