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    11747470 : 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    11747472 :   if (CanStoreSimpleTransition(map->raw_transitions())) {
      23    10933669 :     if (flag == SIMPLE_PROPERTY_TRANSITION) {
      24    10747014 :       Handle<WeakCell> cell = Map::WeakCellForMap(target);
      25    10747014 :       ReplaceTransitions(map, *cell);
      26             :       return;
      27             :     }
      28             :     // If the flag requires a full TransitionArray, allocate one.
      29      186655 :     Handle<TransitionArray> result = Allocate(isolate, 0, 1);
      30      186655 :     ReplaceTransitions(map, *result);
      31             :   }
      32             : 
      33     1000458 :   bool is_special_transition = flag == SPECIAL_TRANSITION;
      34             :   // If the map has a simple transition, check if it should be overwritten.
      35     1000458 :   if (IsSimpleTransition(map->raw_transitions())) {
      36             :     Map* old_target = GetSimpleTransition(map->raw_transitions());
      37      143890 :     Name* key = GetSimpleTransitionKey(old_target);
      38      143890 :     PropertyDetails old_details = GetSimpleTargetDetails(old_target);
      39             :     PropertyDetails new_details = is_special_transition
      40             :                                       ? PropertyDetails::Empty()
      41      143890 :                                       : GetTargetDetails(*name, *target);
      42      337168 :     if (flag == SIMPLE_PROPERTY_TRANSITION && key->Equals(*name) &&
      43      186635 :         old_details.kind() == new_details.kind() &&
      44             :         old_details.attributes() == new_details.attributes()) {
      45       38880 :       Handle<WeakCell> cell = Map::WeakCellForMap(target);
      46       38880 :       ReplaceTransitions(map, *cell);
      47             :       return;
      48             :     }
      49             :     // Otherwise allocate a full TransitionArray with slack for a new entry.
      50      105010 :     Handle<TransitionArray> result = Allocate(isolate, 1, 1);
      51             :     // Re-read existing data; the allocation might have caused it to be cleared.
      52      105010 :     if (IsSimpleTransition(map->raw_transitions())) {
      53             :       old_target = GetSimpleTransition(map->raw_transitions());
      54      210020 :       result->Set(0, GetSimpleTransitionKey(old_target), old_target);
      55             :     } else {
      56             :       result->SetNumberOfTransitions(0);
      57             :     }
      58      105010 :     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      961578 :   int insertion_index = kNotFound;
      67             :   DCHECK_EQ(is_special_transition, IsSpecialTransition(*name));
      68             :   PropertyDetails details = is_special_transition
      69             :                                 ? PropertyDetails::Empty()
      70      961578 :                                 : GetTargetDetails(*name, *target);
      71             : 
      72             :   {
      73             :     DisallowHeapAllocation no_gc;
      74             :     TransitionArray* array = TransitionArray::cast(map->raw_transitions());
      75      961578 :     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     1733788 :                             &insertion_index);
      83             :     // If an existing entry was found, overwrite it and return.
      84      961578 :     if (index != kNotFound) {
      85             :       array->SetTarget(index, *target);
      86             :       return;
      87             :     }
      88             : 
      89      835361 :     ++new_nof;
      90      835361 :     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      835361 :     if (new_nof <= Capacity(array)) {
      95             :       array->SetNumberOfTransitions(new_nof);
      96    16074368 :       for (index = number_of_transitions; index > insertion_index; --index) {
      97    15006808 :         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      603162 :       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      301581 :   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      301581 :   if (array->HasPrototypeTransitions()) {
     142             :     result->SetPrototypeTransitions(array->GetPrototypeTransitions());
     143             :   }
     144             : 
     145             :   DCHECK_NE(kNotFound, insertion_index);
     146      996400 :   for (int i = 0; i < insertion_index; ++i) {
     147      996400 :     result->Set(i, array->GetKey(i), array->GetTarget(i));
     148             :   }
     149      301581 :   result->Set(insertion_index, *name, *target);
     150     1163021 :   for (int i = insertion_index; i < number_of_transitions; ++i) {
     151     1119718 :     result->Set(i + 1, array->GetKey(i), array->GetTarget(i));
     152             :   }
     153             : 
     154             :   SLOW_DCHECK(result->IsSortedNoDuplicates());
     155      301581 :   ReplaceTransitions(map, *result);
     156             : }
     157             : 
     158             : 
     159             : // static
     160    46840272 : Map* TransitionArray::SearchTransition(Map* map, PropertyKind kind, Name* name,
     161             :                                        PropertyAttributes attributes) {
     162             :   DCHECK(name->IsUniqueName());
     163             :   Object* raw_transitions = map->raw_transitions();
     164    46840272 :   if (IsSimpleTransition(raw_transitions)) {
     165             :     Map* target = GetSimpleTransition(raw_transitions);
     166    10264276 :     Name* key = GetSimpleTransitionKey(target);
     167    10264277 :     if (key != name) return nullptr;
     168    10161782 :     PropertyDetails details = GetSimpleTargetDetails(target);
     169    10161781 :     if (details.attributes() != attributes) return nullptr;
     170    10152624 :     if (details.kind() != kind) return nullptr;
     171    10149224 :     return target;
     172             :   }
     173    36575998 :   if (IsFullTransitionArray(raw_transitions)) {
     174             :     TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     175    21188707 :     int transition = transitions->Search(kind, name, attributes);
     176    21188707 :     if (transition == kNotFound) return nullptr;
     177    20537010 :     return transitions->GetTarget(transition);
     178             :   }
     179             :   return NULL;
     180             : }
     181             : 
     182             : 
     183             : // static
     184     3300808 : Map* TransitionArray::SearchSpecial(Map* map, Symbol* name) {
     185             :   Object* raw_transitions = map->raw_transitions();
     186     3300808 :   if (IsFullTransitionArray(raw_transitions)) {
     187             :     TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     188             :     int transition = transitions->SearchSpecial(name);
     189     2676986 :     if (transition == kNotFound) return NULL;
     190     2673042 :     return transitions->GetTarget(transition);
     191             :   }
     192             :   return NULL;
     193             : }
     194             : 
     195             : 
     196             : // static
     197    14819536 : Handle<Map> TransitionArray::FindTransitionToField(Handle<Map> map,
     198             :                                                    Handle<Name> name) {
     199             :   DCHECK(name->IsUniqueName());
     200             :   DisallowHeapAllocation no_gc;
     201    14819536 :   Map* target = SearchTransition(*map, kData, *name, NONE);
     202    14819536 :   if (target == NULL) return Handle<Map>::null();
     203             :   PropertyDetails details = target->GetLastDescriptorDetails();
     204             :   DCHECK_EQ(NONE, details.attributes());
     205    14677847 :   if (details.location() != kField) return Handle<Map>::null();
     206             :   DCHECK_EQ(kData, details.kind());
     207    14677832 :   return Handle<Map>(target);
     208             : }
     209             : 
     210             : 
     211             : // static
     212    42976906 : Handle<String> TransitionArray::ExpectedTransitionKey(Handle<Map> map) {
     213             :   DisallowHeapAllocation no_gc;
     214             :   Object* raw_transition = map->raw_transitions();
     215    42976906 :   if (!IsSimpleTransition(raw_transition)) return Handle<String>::null();
     216             :   Map* target = GetSimpleTransition(raw_transition);
     217    28264402 :   PropertyDetails details = GetSimpleTargetDetails(target);
     218    28264402 :   if (details.location() != kField) return Handle<String>::null();
     219             :   DCHECK_EQ(kData, details.kind());
     220    28264402 :   if (details.attributes() != NONE) return Handle<String>::null();
     221    28264401 :   Name* name = GetSimpleTransitionKey(target);
     222    28264401 :   if (!name->IsString()) return Handle<String>::null();
     223    28264401 :   return Handle<String>(String::cast(name));
     224             : }
     225             : 
     226             : 
     227             : // static
     228    11688207 : bool TransitionArray::CanHaveMoreTransitions(Handle<Map> map) {
     229    11688207 :   if (map->is_dictionary_map()) return false;
     230             :   Object* raw_transitions = map->raw_transitions();
     231    11561086 :   if (IsFullTransitionArray(raw_transitions)) {
     232             :     TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     233      553982 :     return transitions->number_of_transitions() < kMaxNumberOfTransitions;
     234             :   }
     235             :   return true;
     236             : }
     237             : 
     238             : 
     239             : // static
     240       63749 : bool TransitionArray::CompactPrototypeTransitionArray(FixedArray* array) {
     241             :   const int header = kProtoTransitionHeaderSize;
     242       63749 :   int number_of_transitions = NumberOfPrototypeTransitions(array);
     243       63749 :   if (number_of_transitions == 0) {
     244             :     // Empty array cannot be compacted.
     245             :     return false;
     246             :   }
     247             :   int new_number_of_transitions = 0;
     248       50210 :   for (int i = 0; i < number_of_transitions; i++) {
     249       39324 :     Object* cell = array->get(header + i);
     250       39324 :     if (!WeakCell::cast(cell)->cleared()) {
     251       22384 :       if (new_number_of_transitions != i) {
     252           0 :         array->set(header + new_number_of_transitions, cell);
     253             :       }
     254       22384 :       new_number_of_transitions++;
     255             :     }
     256             :   }
     257             :   // Fill slots that became free with undefined value.
     258       27826 :   for (int i = new_number_of_transitions; i < number_of_transitions; i++) {
     259       16940 :     array->set_undefined(header + i);
     260             :   }
     261       10886 :   if (number_of_transitions != new_number_of_transitions) {
     262             :     SetNumberOfPrototypeTransitions(array, new_number_of_transitions);
     263             :   }
     264       10886 :   return new_number_of_transitions < number_of_transitions;
     265             : }
     266             : 
     267             : 
     268             : // static
     269       55279 : Handle<FixedArray> TransitionArray::GrowPrototypeTransitionArray(
     270             :     Handle<FixedArray> array, int new_capacity, Isolate* isolate) {
     271             :   // Grow array by factor 2 up to MaxCachedPrototypeTransitions.
     272       55279 :   int capacity = array->length() - kProtoTransitionHeaderSize;
     273             :   new_capacity = Min(kMaxCachedPrototypeTransitions, new_capacity);
     274             :   DCHECK_GT(new_capacity, capacity);
     275       55279 :   int grow_by = new_capacity - capacity;
     276       55279 :   array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by, TENURED);
     277       55279 :   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       55279 :   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      138924 : 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      184463 :   if (map->is_prototype_map()) return;
     302      120062 :   if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return;
     303             : 
     304             :   const int header = kProtoTransitionHeaderSize;
     305             : 
     306       93385 :   Handle<WeakCell> target_cell = Map::WeakCellForMap(target_map);
     307             : 
     308       93385 :   Handle<FixedArray> cache(GetPrototypeTransitions(*map));
     309       93385 :   int capacity = cache->length() - header;
     310       93385 :   int transitions = NumberOfPrototypeTransitions(*cache) + 1;
     311             : 
     312       93385 :   if (transitions > capacity) {
     313             :     // Grow the array if compacting it doesn't free space.
     314       63749 :     if (!CompactPrototypeTransitionArray(*cache)) {
     315       55279 :       if (capacity == kMaxCachedPrototypeTransitions) return;
     316             :       cache = GrowPrototypeTransitionArray(cache, 2 * transitions,
     317       55279 :                                            map->GetIsolate());
     318       55279 :       SetPrototypeTransitions(map, cache);
     319             :     }
     320             :   }
     321             : 
     322             :   // Reload number of transitions as they might have been compacted.
     323       93385 :   int last = NumberOfPrototypeTransitions(*cache);
     324       93385 :   int entry = header + last;
     325             : 
     326       93385 :   cache->set(entry, *target_cell);
     327             :   SetNumberOfPrototypeTransitions(*cache, last + 1);
     328             : }
     329             : 
     330             : 
     331             : // static
     332     4154295 : Handle<Map> TransitionArray::GetPrototypeTransition(Handle<Map> map,
     333             :                                                     Handle<Object> prototype) {
     334             :   DisallowHeapAllocation no_gc;
     335     4154295 :   FixedArray* cache = GetPrototypeTransitions(*map);
     336     4154295 :   int number_of_transitions = NumberOfPrototypeTransitions(cache);
     337     4154295 :   for (int i = 0; i < number_of_transitions; i++) {
     338             :     WeakCell* target_cell =
     339     5926442 :         WeakCell::cast(cache->get(kProtoTransitionHeaderSize + i));
     340    10510895 :     if (!target_cell->cleared() &&
     341             :         Map::cast(target_cell->value())->prototype() == *prototype) {
     342             :       return handle(Map::cast(target_cell->value()));
     343             :     }
     344             :   }
     345      138924 :   return Handle<Map>();
     346             : }
     347             : 
     348             : 
     349             : // static
     350     4247680 : FixedArray* TransitionArray::GetPrototypeTransitions(Map* map) {
     351             :   Object* raw_transitions = map->raw_transitions();
     352      151265 :   Heap* heap = map->GetHeap();
     353     4247680 :   if (!IsFullTransitionArray(raw_transitions)) {
     354      127427 :     return heap->empty_fixed_array();
     355             :   }
     356             :   TransitionArray* transitions = TransitionArray::cast(raw_transitions);
     357     4120253 :   if (!transitions->HasPrototypeTransitions()) {
     358       23838 :     return heap->empty_fixed_array();
     359             :   }
     360     4096415 :   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     4201686 : int TransitionArray::NumberOfTransitions(Object* raw_transitions) {
     375     4201686 :   if (CanStoreSimpleTransition(raw_transitions)) return 0;
     376     3485616 :   if (IsSimpleTransition(raw_transitions)) return 1;
     377             :   // Prototype maps don't have transitions.
     378      878776 :   if (raw_transitions->IsPrototypeInfo()) return 0;
     379             :   DCHECK(IsFullTransitionArray(raw_transitions));
     380      878776 :   return TransitionArray::cast(raw_transitions)->number_of_transitions();
     381             : }
     382             : 
     383             : 
     384             : // static
     385      884641 : int TransitionArray::Capacity(Object* raw_transitions) {
     386      884641 :   if (!IsFullTransitionArray(raw_transitions)) return 1;
     387             :   TransitionArray* t = TransitionArray::cast(raw_transitions);
     388      884641 :   if (t->length() <= kFirstIndex) return 0;
     389      883469 :   return (t->length() - kFirstIndex) / kTransitionSize;
     390             : }
     391             : 
     392             : 
     393             : // Private static helper functions.
     394             : 
     395      634190 : Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
     396             :                                                   int number_of_transitions,
     397             :                                                   int slack) {
     398             :   Handle<FixedArray> array = isolate->factory()->NewTransitionArray(
     399     1268380 :       LengthFor(number_of_transitions + slack));
     400             :   array->set(kPrototypeTransitionsIndex, Smi::kZero);
     401             :   array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
     402      634190 :   return Handle<TransitionArray>::cast(array);
     403             : }
     404             : 
     405             : 
     406             : // static
     407      301581 : 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      603162 :                 transitions->length() - kPrototypeTransitionsIndex);
     413             :   transitions->SetNumberOfTransitions(0);
     414      301581 : }
     415             : 
     416             : 
     417    11420084 : void TransitionArray::ReplaceTransitions(Handle<Map> map,
     418             :                                          Object* new_transitions) {
     419             :   Object* raw_transitions = map->raw_transitions();
     420    11420084 :   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      301581 :     ZapTransitionArray(old_transitions);
     431             :   }
     432    11420084 :   map->set_raw_transitions(new_transitions);
     433    11420084 : }
     434             : 
     435             : 
     436       55279 : void TransitionArray::SetPrototypeTransitions(
     437             :     Handle<Map> map, Handle<FixedArray> proto_transitions) {
     438       55279 :   EnsureHasFullTransitionArray(map);
     439             :   TransitionArray* transitions = TransitionArray::cast(map->raw_transitions());
     440             :   transitions->SetPrototypeTransitions(*proto_transitions);
     441       55279 : }
     442             : 
     443             : 
     444       55279 : void TransitionArray::EnsureHasFullTransitionArray(Handle<Map> map) {
     445             :   Object* raw_transitions = map->raw_transitions();
     446      110558 :   if (IsFullTransitionArray(raw_transitions)) return;
     447       40944 :   int nof = IsSimpleTransition(raw_transitions) ? 1 : 0;
     448       40944 :   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       40944 :   int new_nof = IsSimpleTransition(raw_transitions) ? 1 : 0;
     453       40944 :   if (new_nof != nof) {
     454             :     DCHECK(new_nof == 0);
     455           0 :     result->Shrink(ToKeyIndex(0));
     456             :     result->SetNumberOfTransitions(0);
     457       40944 :   } 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       40944 :   ReplaceTransitions(map, *result);
     463             : }
     464             : 
     465             : 
     466      688728 : void TransitionArray::TraverseTransitionTreeInternal(Map* map,
     467             :                                                      TraverseCallback callback,
     468             :                                                      void* data) {
     469             :   Object* raw_transitions = map->raw_transitions();
     470      688728 :   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      686188 :   } else if (IsSimpleTransition(raw_transitions)) {
     487             :     TraverseTransitionTreeInternal(GetSimpleTransition(raw_transitions),
     488      498044 :                                    callback, data);
     489             :   }
     490      688728 :   callback(map, data);
     491      688728 : }
     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    20678372 : int TransitionArray::SearchDetails(int transition, PropertyKind kind,
     524             :                                    PropertyAttributes attributes,
     525             :                                    int* out_insertion_index) {
     526    20678372 :   int nof_transitions = number_of_transitions();
     527             :   DCHECK(transition < nof_transitions);
     528             :   Name* key = GetKey(transition);
     529    41417225 :   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    20700736 :     if (cmp == 0) {
     537             :       return transition;
     538       37509 :     } else if (cmp < 0) {
     539             :       break;
     540             :     }
     541             :   }
     542       15145 :   if (out_insertion_index != NULL) *out_insertion_index = transition;
     543             :   return kNotFound;
     544             : }
     545             : 
     546             : 
     547    21960917 : int TransitionArray::Search(PropertyKind kind, Name* name,
     548             :                             PropertyAttributes attributes,
     549             :                             int* out_insertion_index) {
     550    21960917 :   int transition = SearchName(name, out_insertion_index);
     551    21960917 :   if (transition == kNotFound) return kNotFound;
     552    20678372 :   return SearchDetails(transition, kind, attributes, out_insertion_index);
     553             : }
     554             : }  // namespace internal
     555             : }  // namespace v8

Generated by: LCOV version 1.10