LCOV - code coverage report
Current view: top level - src - transitions.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 175 190 92.1 %
Date: 2017-04-26 Functions: 21 23 91.3 %

          Line data    Source code
       1             : // Copyright 2012 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/transitions.h"
       6             : 
       7             : #include "src/objects-inl.h"
       8             : #include "src/transitions-inl.h"
       9             : #include "src/utils.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : 
      15             : // static
      16    11753523 : void TransitionArray::Insert(Handle<Map> map, Handle<Name> name,
      17             :                              Handle<Map> target, SimpleTransitionFlag flag) {
      18             :   Isolate* isolate = map->GetIsolate();
      19             :   target->SetBackPointer(*map);
      20             : 
      21             :   // If the map doesn't have any transitions at all yet, install the new one.
      22    11753524 :   if (CanStoreSimpleTransition(map->raw_transitions())) {
      23    10939175 :     if (flag == SIMPLE_PROPERTY_TRANSITION) {
      24    10752254 :       Handle<WeakCell> cell = Map::WeakCellForMap(target);
      25    10752254 :       ReplaceTransitions(map, *cell);
      26             :       return;
      27             :     }
      28             :     // If the flag requires a full TransitionArray, allocate one.
      29      186921 :     Handle<TransitionArray> result = Allocate(isolate, 0, 1);
      30      186921 :     ReplaceTransitions(map, *result);
      31             :   }
      32             : 
      33     1001270 :   bool is_special_transition = flag == SPECIAL_TRANSITION;
      34             :   // If the map has a simple transition, check if it should be overwritten.
      35     1001270 :   if (IsSimpleTransition(map->raw_transitions())) {
      36             :     Map* old_target = GetSimpleTransition(map->raw_transitions());
      37      144052 :     Name* key = GetSimpleTransitionKey(old_target);
      38      144052 :     PropertyDetails old_details = GetSimpleTargetDetails(old_target);
      39             :     PropertyDetails new_details = is_special_transition
      40             :                                       ? PropertyDetails::Empty()
      41      144052 :                                       : GetTargetDetails(*name, *target);
      42      337573 :     if (flag == SIMPLE_PROPERTY_TRANSITION && key->Equals(*name) &&
      43      186878 :         old_details.kind() == new_details.kind() &&
      44             :         old_details.attributes() == new_details.attributes()) {
      45       38961 :       Handle<WeakCell> cell = Map::WeakCellForMap(target);
      46       38961 :       ReplaceTransitions(map, *cell);
      47             :       return;
      48             :     }
      49             :     // Otherwise allocate a full TransitionArray with slack for a new entry.
      50      105091 :     Handle<TransitionArray> result = Allocate(isolate, 1, 1);
      51             :     // Re-read existing data; the allocation might have caused it to be cleared.
      52      105091 :     if (IsSimpleTransition(map->raw_transitions())) {
      53             :       old_target = GetSimpleTransition(map->raw_transitions());
      54      210182 :       result->Set(0, GetSimpleTransitionKey(old_target), old_target);
      55             :     } else {
      56             :       result->SetNumberOfTransitions(0);
      57             :     }
      58      105091 :     ReplaceTransitions(map, *result);
      59             :   }
      60             : 
      61             :   // At this point, we know that the map has a full TransitionArray.
      62             :   DCHECK(IsFullTransitionArray(map->raw_transitions()));
      63             : 
      64             :   int number_of_transitions = 0;
      65             :   int new_nof = 0;
      66      962312 :   int insertion_index = kNotFound;
      67             :   DCHECK_EQ(is_special_transition, IsSpecialTransition(*name));
      68             :   PropertyDetails details = is_special_transition
      69             :                                 ? PropertyDetails::Empty()
      70      962312 :                                 : GetTargetDetails(*name, *target);
      71             : 
      72             :   {
      73             :     DisallowHeapAllocation no_gc;
      74             :     TransitionArray* array = TransitionArray::cast(map->raw_transitions());
      75      962312 :     number_of_transitions = array->number_of_transitions();
      76             :     new_nof = number_of_transitions;
      77             : 
      78             :     int index =
      79             :         is_special_transition
      80             :             ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
      81             :             : array->Search(details.kind(), *name, details.attributes(),
      82     1734990 :                             &insertion_index);
      83             :     // If an existing entry was found, overwrite it and return.
      84      962312 :     if (index != kNotFound) {
      85             :       array->SetTarget(index, *target);
      86             :       return;
      87             :     }
      88             : 
      89      835977 :     ++new_nof;
      90      835977 :     CHECK(new_nof <= kMaxNumberOfTransitions);
      91             :     DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
      92             : 
      93             :     // If there is enough capacity, insert new entry into the existing array.
      94      835977 :     if (new_nof <= Capacity(array)) {
      95             :       array->SetNumberOfTransitions(new_nof);
      96    16074709 :       for (index = number_of_transitions; index > insertion_index; --index) {
      97    15006273 :         array->SetKey(index, array->GetKey(index - 1));
      98             :         array->SetTarget(index, array->GetTarget(index - 1));
      99             :       }
     100             :       array->SetKey(index, *name);
     101             :       array->SetTarget(index, *target);
     102             :       SLOW_DCHECK(array->IsSortedNoDuplicates());
     103             :       return;
     104             :     }
     105             :   }
     106             : 
     107             :   // We're gonna need a bigger TransitionArray.
     108             :   Handle<TransitionArray> result = Allocate(
     109             :       map->GetIsolate(), new_nof,
     110      603518 :       Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions));
     111             : 
     112             :   // The map's transition array may have shrunk during the allocation above as
     113             :   // it was weakly traversed, though it is guaranteed not to disappear. Trim the
     114             :   // result copy if needed, and recompute variables.
     115             :   DCHECK(IsFullTransitionArray(map->raw_transitions()));
     116             :   DisallowHeapAllocation no_gc;
     117             :   TransitionArray* array = TransitionArray::cast(map->raw_transitions());
     118      301759 :   if (array->number_of_transitions() != number_of_transitions) {
     119             :     DCHECK(array->number_of_transitions() < number_of_transitions);
     120             : 
     121           0 :     number_of_transitions = array->number_of_transitions();
     122             :     new_nof = number_of_transitions;
     123             : 
     124           0 :     insertion_index = kNotFound;
     125             :     int index =
     126             :         is_special_transition
     127             :             ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
     128             :             : array->Search(details.kind(), *name, details.attributes(),
     129           0 :                             &insertion_index);
     130           0 :     if (index == kNotFound) {
     131           0 :       ++new_nof;
     132             :     } else {
     133           0 :       insertion_index = index;
     134             :     }
     135             :     DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
     136             : 
     137           0 :     result->Shrink(ToKeyIndex(new_nof));
     138             :     result->SetNumberOfTransitions(new_nof);
     139             :   }
     140             : 
     141      301759 :   if (array->HasPrototypeTransitions()) {
     142             :     result->SetPrototypeTransitions(array->GetPrototypeTransitions());
     143             :   }
     144             : 
     145             :   DCHECK_NE(kNotFound, insertion_index);
     146      995422 :   for (int i = 0; i < insertion_index; ++i) {
     147      995422 :     result->Set(i, array->GetKey(i), array->GetTarget(i));
     148             :   }
     149      301759 :   result->Set(insertion_index, *name, *target);
     150     1164829 :   for (int i = insertion_index; i < number_of_transitions; ++i) {
     151     1122622 :     result->Set(i + 1, array->GetKey(i), array->GetTarget(i));
     152             :   }
     153             : 
     154             :   SLOW_DCHECK(result->IsSortedNoDuplicates());
     155      301759 :   ReplaceTransitions(map, *result);
     156             : }
     157             : 
     158             : 
     159             : // static
     160    46862108 : Map* TransitionArray::SearchTransition(Map* map, PropertyKind kind, Name* name,
     161             :                                        PropertyAttributes attributes) {
     162             :   DCHECK(name->IsUniqueName());
     163             :   Object* raw_transitions = map->raw_transitions();
     164    46862108 :   if (IsSimpleTransition(raw_transitions)) {
     165             :     Map* target = GetSimpleTransition(raw_transitions);
     166    10272029 :     Name* key = GetSimpleTransitionKey(target);
     167    10272028 :     if (key != name) return nullptr;
     168    10169457 :     PropertyDetails details = GetSimpleTargetDetails(target);
     169    10169458 :     if (details.attributes() != attributes) return nullptr;
     170    10160301 :     if (details.kind() != kind) return nullptr;
     171    10156900 :     return target;
     172             :   }
     173    36590090 :   if (IsFullTransitionArray(raw_transitions)) {
     174             :     TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     175    21194067 :     int transition = transitions->Search(kind, name, attributes);
     176    21194067 :     if (transition == kNotFound) return nullptr;
     177    20542098 :     return transitions->GetTarget(transition);
     178             :   }
     179             :   return NULL;
     180             : }
     181             : 
     182             : 
     183             : // static
     184     3304137 : Map* TransitionArray::SearchSpecial(Map* map, Symbol* name) {
     185             :   Object* raw_transitions = map->raw_transitions();
     186     3304137 :   if (IsFullTransitionArray(raw_transitions)) {
     187             :     TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     188             :     int transition = transitions->SearchSpecial(name);
     189     2678443 :     if (transition == kNotFound) return NULL;
     190     2674499 :     return transitions->GetTarget(transition);
     191             :   }
     192             :   return NULL;
     193             : }
     194             : 
     195             : 
     196             : // static
     197    14819554 : Handle<Map> TransitionArray::FindTransitionToField(Handle<Map> map,
     198             :                                                    Handle<Name> name) {
     199             :   DCHECK(name->IsUniqueName());
     200             :   DisallowHeapAllocation no_gc;
     201    14819554 :   Map* target = SearchTransition(*map, kData, *name, NONE);
     202    14819554 :   if (target == NULL) return Handle<Map>::null();
     203             :   PropertyDetails details = target->GetLastDescriptorDetails();
     204             :   DCHECK_EQ(NONE, details.attributes());
     205    14677859 :   if (details.location() != kField) return Handle<Map>::null();
     206             :   DCHECK_EQ(kData, details.kind());
     207    14677844 :   return Handle<Map>(target);
     208             : }
     209             : 
     210             : 
     211             : // static
     212    42977068 : Handle<String> TransitionArray::ExpectedTransitionKey(Handle<Map> map) {
     213             :   DisallowHeapAllocation no_gc;
     214             :   Object* raw_transition = map->raw_transitions();
     215    42977068 :   if (!IsSimpleTransition(raw_transition)) return Handle<String>::null();
     216             :   Map* target = GetSimpleTransition(raw_transition);
     217    28264546 :   PropertyDetails details = GetSimpleTargetDetails(target);
     218    28264546 :   if (details.location() != kField) return Handle<String>::null();
     219             :   DCHECK_EQ(kData, details.kind());
     220    28264546 :   if (details.attributes() != NONE) return Handle<String>::null();
     221    28264545 :   Name* name = GetSimpleTransitionKey(target);
     222    28264545 :   if (!name->IsString()) return Handle<String>::null();
     223    28264545 :   return Handle<String>(String::cast(name));
     224             : }
     225             : 
     226             : 
     227             : // static
     228    11694048 : bool TransitionArray::CanHaveMoreTransitions(Handle<Map> map) {
     229    11694048 :   if (map->is_dictionary_map()) return false;
     230             :   Object* raw_transitions = map->raw_transitions();
     231    11566929 :   if (IsFullTransitionArray(raw_transitions)) {
     232             :     TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     233      554251 :     return transitions->number_of_transitions() < kMaxNumberOfTransitions;
     234             :   }
     235             :   return true;
     236             : }
     237             : 
     238             : 
     239             : // static
     240       63923 : bool TransitionArray::CompactPrototypeTransitionArray(FixedArray* array) {
     241             :   const int header = kProtoTransitionHeaderSize;
     242       63923 :   int number_of_transitions = NumberOfPrototypeTransitions(array);
     243       63923 :   if (number_of_transitions == 0) {
     244             :     // Empty array cannot be compacted.
     245             :     return false;
     246             :   }
     247             :   int new_number_of_transitions = 0;
     248       50928 :   for (int i = 0; i < number_of_transitions; i++) {
     249       39952 :     Object* cell = array->get(header + i);
     250       39952 :     if (!WeakCell::cast(cell)->cleared()) {
     251       23000 :       if (new_number_of_transitions != i) {
     252           0 :         array->set(header + new_number_of_transitions, cell);
     253             :       }
     254       23000 :       new_number_of_transitions++;
     255             :     }
     256             :   }
     257             :   // Fill slots that became free with undefined value.
     258       27928 :   for (int i = new_number_of_transitions; i < number_of_transitions; i++) {
     259       16952 :     array->set_undefined(header + i);
     260             :   }
     261       10976 :   if (number_of_transitions != new_number_of_transitions) {
     262             :     SetNumberOfPrototypeTransitions(array, new_number_of_transitions);
     263             :   }
     264       10976 :   return new_number_of_transitions < number_of_transitions;
     265             : }
     266             : 
     267             : 
     268             : // static
     269       55447 : Handle<FixedArray> TransitionArray::GrowPrototypeTransitionArray(
     270             :     Handle<FixedArray> array, int new_capacity, Isolate* isolate) {
     271             :   // Grow array by factor 2 up to MaxCachedPrototypeTransitions.
     272       55447 :   int capacity = array->length() - kProtoTransitionHeaderSize;
     273             :   new_capacity = Min(kMaxCachedPrototypeTransitions, new_capacity);
     274             :   DCHECK_GT(new_capacity, capacity);
     275       55447 :   int grow_by = new_capacity - capacity;
     276       55447 :   array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by, TENURED);
     277       55447 :   if (capacity < 0) {
     278             :     // There was no prototype transitions array before, so the size
     279             :     // couldn't be copied. Initialize it explicitly.
     280             :     SetNumberOfPrototypeTransitions(*array, 0);
     281             :   }
     282       55447 :   return array;
     283             : }
     284             : 
     285             : 
     286             : // static
     287           0 : int TransitionArray::NumberOfPrototypeTransitionsForTest(Map* map) {
     288           0 :   FixedArray* transitions = GetPrototypeTransitions(map);
     289           0 :   CompactPrototypeTransitionArray(transitions);
     290           0 :   return TransitionArray::NumberOfPrototypeTransitions(transitions);
     291             : }
     292             : 
     293             : 
     294             : // static
     295      139748 : void TransitionArray::PutPrototypeTransition(Handle<Map> map,
     296             :                                              Handle<Object> prototype,
     297             :                                              Handle<Map> target_map) {
     298             :   DCHECK(HeapObject::cast(*prototype)->map()->IsMap());
     299             :   // Don't cache prototype transition if this map is either shared, or a map of
     300             :   // a prototype.
     301      185539 :   if (map->is_prototype_map()) return;
     302      120886 :   if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return;
     303             : 
     304             :   const int header = kProtoTransitionHeaderSize;
     305             : 
     306       93957 :   Handle<WeakCell> target_cell = Map::WeakCellForMap(target_map);
     307             : 
     308       93957 :   Handle<FixedArray> cache(GetPrototypeTransitions(*map));
     309       93957 :   int capacity = cache->length() - header;
     310       93957 :   int transitions = NumberOfPrototypeTransitions(*cache) + 1;
     311             : 
     312       93957 :   if (transitions > capacity) {
     313             :     // Grow the array if compacting it doesn't free space.
     314       63923 :     if (!CompactPrototypeTransitionArray(*cache)) {
     315       55447 :       if (capacity == kMaxCachedPrototypeTransitions) return;
     316             :       cache = GrowPrototypeTransitionArray(cache, 2 * transitions,
     317       55447 :                                            map->GetIsolate());
     318       55447 :       SetPrototypeTransitions(map, cache);
     319             :     }
     320             :   }
     321             : 
     322             :   // Reload number of transitions as they might have been compacted.
     323       93957 :   int last = NumberOfPrototypeTransitions(*cache);
     324       93957 :   int entry = header + last;
     325             : 
     326       93957 :   cache->set(entry, *target_cell);
     327             :   SetNumberOfPrototypeTransitions(*cache, last + 1);
     328             : }
     329             : 
     330             : 
     331             : // static
     332     4156555 : Handle<Map> TransitionArray::GetPrototypeTransition(Handle<Map> map,
     333             :                                                     Handle<Object> prototype) {
     334             :   DisallowHeapAllocation no_gc;
     335     4156555 :   FixedArray* cache = GetPrototypeTransitions(*map);
     336     4156555 :   int number_of_transitions = NumberOfPrototypeTransitions(cache);
     337     4156555 :   for (int i = 0; i < number_of_transitions; i++) {
     338             :     WeakCell* target_cell =
     339     5932186 :         WeakCell::cast(cache->get(kProtoTransitionHeaderSize + i));
     340    10522359 :     if (!target_cell->cleared() &&
     341             :         Map::cast(target_cell->value())->prototype() == *prototype) {
     342             :       return handle(Map::cast(target_cell->value()));
     343             :     }
     344             :   }
     345      139748 :   return Handle<Map>();
     346             : }
     347             : 
     348             : 
     349             : // static
     350     4250512 : FixedArray* TransitionArray::GetPrototypeTransitions(Map* map) {
     351             :   Object* raw_transitions = map->raw_transitions();
     352      151685 :   Heap* heap = map->GetHeap();
     353     4250512 :   if (!IsFullTransitionArray(raw_transitions)) {
     354      127739 :     return heap->empty_fixed_array();
     355             :   }
     356             :   TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     357     4122773 :   if (!transitions->HasPrototypeTransitions()) {
     358       23946 :     return heap->empty_fixed_array();
     359             :   }
     360     4098827 :   return transitions->GetPrototypeTransitions();
     361             : }
     362             : 
     363             : 
     364             : // static
     365           0 : void TransitionArray::SetNumberOfPrototypeTransitions(
     366             :     FixedArray* proto_transitions, int value) {
     367             :   DCHECK(proto_transitions->length() != 0);
     368             :   proto_transitions->set(kProtoTransitionNumberOfEntriesOffset,
     369             :                          Smi::FromInt(value));
     370           0 : }
     371             : 
     372             : 
     373             : // static
     374     4204659 : int TransitionArray::NumberOfTransitions(Object* raw_transitions) {
     375     4204659 :   if (CanStoreSimpleTransition(raw_transitions)) return 0;
     376     3487919 :   if (IsSimpleTransition(raw_transitions)) return 1;
     377             :   // Prototype maps don't have transitions.
     378      879738 :   if (raw_transitions->IsPrototypeInfo()) return 0;
     379             :   DCHECK(IsFullTransitionArray(raw_transitions));
     380      879738 :   return TransitionArray::cast(raw_transitions)->number_of_transitions();
     381             : }
     382             : 
     383             : 
     384             : // static
     385      885313 : int TransitionArray::Capacity(Object* raw_transitions) {
     386      885313 :   if (!IsFullTransitionArray(raw_transitions)) return 1;
     387             :   TransitionArray* t = TransitionArray::cast(raw_transitions);
     388      885313 :   if (t->length() <= kFirstIndex) return 0;
     389      884141 :   return (t->length() - kFirstIndex) / kTransitionSize;
     390             : }
     391             : 
     392             : 
     393             : // Private static helper functions.
     394             : 
     395      634745 : Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
     396             :                                                   int number_of_transitions,
     397             :                                                   int slack) {
     398             :   Handle<FixedArray> array = isolate->factory()->NewTransitionArray(
     399     1269490 :       LengthFor(number_of_transitions + slack));
     400             :   array->set(kPrototypeTransitionsIndex, Smi::kZero);
     401             :   array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
     402      634745 :   return Handle<TransitionArray>::cast(array);
     403             : }
     404             : 
     405             : 
     406             : // static
     407      301759 : void TransitionArray::ZapTransitionArray(TransitionArray* transitions) {
     408             :   // Do not zap the next link that is used by GC.
     409             :   STATIC_ASSERT(kNextLinkIndex + 1 == kPrototypeTransitionsIndex);
     410             :   MemsetPointer(transitions->data_start() + kPrototypeTransitionsIndex,
     411             :                 transitions->GetHeap()->the_hole_value(),
     412      603518 :                 transitions->length() - kPrototypeTransitionsIndex);
     413             :   transitions->SetNumberOfTransitions(0);
     414      301759 : }
     415             : 
     416             : 
     417    11425959 : void TransitionArray::ReplaceTransitions(Handle<Map> map,
     418             :                                          Object* new_transitions) {
     419             :   Object* raw_transitions = map->raw_transitions();
     420    11425959 :   if (IsFullTransitionArray(raw_transitions)) {
     421             :     TransitionArray* old_transitions = TransitionArray::cast(raw_transitions);
     422             : #ifdef DEBUG
     423             :     CheckNewTransitionsAreConsistent(map, old_transitions, new_transitions);
     424             :     DCHECK(old_transitions != new_transitions);
     425             : #endif
     426             :     // Transition arrays are not shared. When one is replaced, it should not
     427             :     // keep referenced objects alive, so we zap it.
     428             :     // When there is another reference to the array somewhere (e.g. a handle),
     429             :     // not zapping turns from a waste of memory into a source of crashes.
     430      301759 :     ZapTransitionArray(old_transitions);
     431             :   }
     432    11425959 :   map->set_raw_transitions(new_transitions);
     433    11425960 : }
     434             : 
     435             : 
     436       55447 : void TransitionArray::SetPrototypeTransitions(
     437             :     Handle<Map> map, Handle<FixedArray> proto_transitions) {
     438       55447 :   EnsureHasFullTransitionArray(map);
     439             :   TransitionArray* transitions = TransitionArray::cast(map->raw_transitions());
     440             :   transitions->SetPrototypeTransitions(*proto_transitions);
     441       55447 : }
     442             : 
     443             : 
     444       55447 : void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) {
     445             :   Object* raw_transitions = map->raw_transitions();
     446      110894 :   if (IsFullTransitionArray(raw_transitions)) return;
     447       40974 :   int nof = IsSimpleTransition(raw_transitions) ? 1 : 0;
     448       40974 :   Handle<TransitionArray> result = Allocate(map->GetIsolate(), nof);
     449             :   DisallowHeapAllocation no_gc;
     450             :   // Reload pointer after the allocation that just happened.
     451             :   raw_transitions = map->raw_transitions();
     452       40974 :   int new_nof = IsSimpleTransition(raw_transitions) ? 1 : 0;
     453       40974 :   if (new_nof != nof) {
     454             :     DCHECK(new_nof == 0);
     455           0 :     result->Shrink(ToKeyIndex(0));
     456             :     result->SetNumberOfTransitions(0);
     457       40974 :   } else if (nof == 1) {
     458             :     Map* target = GetSimpleTransition(raw_transitions);
     459        4808 :     Name* key = GetSimpleTransitionKey(target);
     460        4808 :     result->Set(0, key, target);
     461             :   }
     462       40974 :   ReplaceTransitions(map, *result);
     463             : }
     464             : 
     465             : 
     466      689538 : void TransitionArray::TraverseTransitionTreeInternal(Map* map,
     467             :                                                      TraverseCallback callback,
     468             :                                                      void* data) {
     469             :   Object* raw_transitions = map->raw_transitions();
     470      689538 :   if (IsFullTransitionArray(raw_transitions)) {
     471             :     TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     472        2540 :     if (transitions->HasPrototypeTransitions()) {
     473             :       FixedArray* proto_trans = transitions->GetPrototypeTransitions();
     474         450 :       for (int i = 0; i < NumberOfPrototypeTransitions(proto_trans); ++i) {
     475         270 :         int index = TransitionArray::kProtoTransitionHeaderSize + i;
     476             :         WeakCell* cell = WeakCell::cast(proto_trans->get(index));
     477         270 :         if (!cell->cleared()) {
     478             :           TraverseTransitionTreeInternal(Map::cast(cell->value()), callback,
     479         270 :                                          data);
     480             :         }
     481             :       }
     482             :     }
     483        4540 :     for (int i = 0; i < transitions->number_of_transitions(); ++i) {
     484        4540 :       TraverseTransitionTreeInternal(transitions->GetTarget(i), callback, data);
     485             :     }
     486      686998 :   } else if (IsSimpleTransition(raw_transitions)) {
     487             :     TraverseTransitionTreeInternal(GetSimpleTransition(raw_transitions),
     488      498606 :                                    callback, data);
     489             :   }
     490      689538 :   callback(map, data);
     491      689538 : }
     492             : 
     493             : 
     494             : #ifdef DEBUG
     495             : void TransitionArray::CheckNewTransitionsAreConsistent(
     496             :     Handle<Map> map, TransitionArray* old_transitions, Object* transitions) {
     497             :   // This function only handles full transition arrays.
     498             :   DCHECK(IsFullTransitionArray(transitions));
     499             :   TransitionArray* new_transitions = TransitionArray::cast(transitions);
     500             :   for (int i = 0; i < old_transitions->number_of_transitions(); i++) {
     501             :     Map* target = old_transitions->GetTarget(i);
     502             :     if (target->instance_descriptors() == map->instance_descriptors()) {
     503             :       Name* key = old_transitions->GetKey(i);
     504             :       int new_target_index;
     505             :       if (TransitionArray::IsSpecialTransition(key)) {
     506             :         new_target_index = new_transitions->SearchSpecial(Symbol::cast(key));
     507             :       } else {
     508             :         PropertyDetails details =
     509             :             TransitionArray::GetTargetDetails(key, target);
     510             :         new_target_index =
     511             :             new_transitions->Search(details.kind(), key, details.attributes());
     512             :       }
     513             :       DCHECK_NE(TransitionArray::kNotFound, new_target_index);
     514             :       DCHECK_EQ(target, new_transitions->GetTarget(new_target_index));
     515             :     }
     516             :   }
     517             : }
     518             : #endif
     519             : 
     520             : 
     521             : // Private non-static helper functions (operating on full transition arrays).
     522             : 
     523    20683573 : int TransitionArray::SearchDetails(int transition, PropertyKind kind,
     524             :                                    PropertyAttributes attributes,
     525             :                                    int* out_insertion_index) {
     526    20683573 :   int nof_transitions = number_of_transitions();
     527             :   DCHECK(transition < nof_transitions);
     528             :   Name* key = GetKey(transition);
     529    41427624 :   for (; transition < nof_transitions && GetKey(transition) == key;
     530             :        transition++) {
     531             :     Map* target = GetTarget(transition);
     532             :     PropertyDetails target_details = GetTargetDetails(key, target);
     533             : 
     534             :     int cmp = CompareDetails(kind, attributes, target_details.kind(),
     535             :                              target_details.attributes());
     536    20705939 :     if (cmp == 0) {
     537             :       return transition;
     538       37506 :     } else if (cmp < 0) {
     539             :       break;
     540             :     }
     541             :   }
     542       15142 :   if (out_insertion_index != NULL) *out_insertion_index = transition;
     543             :   return kNotFound;
     544             : }
     545             : 
     546             : 
     547    21966745 : int TransitionArray::Search(PropertyKind kind, Name* name,
     548             :                             PropertyAttributes attributes,
     549             :                             int* out_insertion_index) {
     550    21966745 :   int transition = SearchName(name, out_insertion_index);
     551    21966744 :   if (transition == kNotFound) return kNotFound;
     552    20683576 :   return SearchDetails(transition, kind, attributes, out_insertion_index);
     553             : }
     554             : }  // namespace internal
     555             : }  // namespace v8

Generated by: LCOV version 1.10