LCOV - code coverage report
Current view: top level - src - transitions.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 225 254 88.6 %
Date: 2017-10-20 Functions: 27 30 90.0 %

          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    99157516 : void TransitionsAccessor::Initialize() {
      15   198315032 :   raw_transitions_ = map_->raw_transitions();
      16    99157516 :   if (raw_transitions_->IsSmi()) {
      17    44841071 :     encoding_ = kUninitialized;
      18    54316460 :   } else if (HeapObject::cast(raw_transitions_)->IsWeakCell()) {
      19    27349214 :     encoding_ = kWeakCell;
      20    26967246 :   } else if (StoreHandler::IsHandler(raw_transitions_)) {
      21      323789 :     encoding_ = kHandler;
      22    53286893 :   } else if (HeapObject::cast(raw_transitions_)->IsTransitionArray()) {
      23    26285050 :     encoding_ = kFullTransitionArray;
      24             :   } else {
      25             :     DCHECK(HeapObject::cast(raw_transitions_)->IsPrototypeInfo());
      26      358394 :     encoding_ = kPrototypeInfo;
      27             :   }
      28    99157518 :   target_cell_ = nullptr;
      29             : #if DEBUG
      30             :   needs_reload_ = false;
      31             : #endif
      32    99157518 : }
      33             : 
      34      726061 : Map* TransitionsAccessor::GetSimpleTransition() {
      35      571467 :   switch (encoding()) {
      36             :     case kWeakCell:
      37      123362 :       return Map::cast(GetTargetCell<kWeakCell>()->value());
      38             :     case kHandler:
      39       31232 :       return Map::cast(GetTargetCell<kHandler>()->value());
      40             :     default:
      41             :       return nullptr;
      42             :   }
      43             : }
      44             : 
      45      101766 : bool TransitionsAccessor::HasSimpleTransitionTo(WeakCell* cell) {
      46             :   DCHECK(cell->value()->IsMap());
      47      101766 :   switch (encoding()) {
      48             :     case kWeakCell:
      49       15510 :       return raw_transitions_ == cell;
      50             :     case kHandler:
      51       14036 :       return StoreHandler::GetTransitionCell(raw_transitions_) == cell;
      52             :     case kPrototypeInfo:
      53             :     case kUninitialized:
      54             :     case kFullTransitionArray:
      55             :       return false;
      56             :   }
      57           0 :   UNREACHABLE();
      58             :   return false;  // Make GCC happy.
      59             : }
      60             : 
      61     6145953 : void TransitionsAccessor::Insert(Handle<Name> name, Handle<Map> target,
      62     6704500 :                                  SimpleTransitionFlag flag) {
      63             :   DCHECK(!map_handle_.is_null());
      64     6145953 :   Isolate* isolate = map_->GetIsolate();
      65     6145953 :   Handle<WeakCell> weak_cell_with_target = Map::WeakCellForMap(target);
      66             :   Reload();
      67     6145954 :   target->SetBackPointer(map_);
      68             : 
      69             :   // If the map doesn't have any transitions at all yet, install the new one.
      70     6145954 :   if (encoding() == kUninitialized) {
      71     5889108 :     if (flag == SIMPLE_PROPERTY_TRANSITION) {
      72     5648721 :       ReplaceTransitions(*weak_cell_with_target);
      73     5648721 :       return;
      74             :     }
      75             :     // If the flag requires a full TransitionArray, allocate one.
      76      240387 :     Handle<TransitionArray> result = TransitionArray::Allocate(isolate, 0, 1);
      77      240387 :     ReplaceTransitions(*result);
      78             :     Reload();
      79             :   }
      80             : 
      81      497233 :   bool is_special_transition = flag == SPECIAL_TRANSITION;
      82             :   // If the map has a simple transition, check if it should be overwritten.
      83      497233 :   Map* simple_transition = GetSimpleTransition();
      84      497233 :   if (simple_transition != nullptr) {
      85       80360 :     Name* key = GetSimpleTransitionKey(simple_transition);
      86       80360 :     PropertyDetails old_details = GetSimpleTargetDetails(simple_transition);
      87             :     PropertyDetails new_details = is_special_transition
      88             :                                       ? PropertyDetails::Empty()
      89       80360 :                                       : GetTargetDetails(*name, *target);
      90      179922 :     if (flag == SIMPLE_PROPERTY_TRANSITION && key->Equals(*name) &&
      91       95678 :         old_details.kind() == new_details.kind() &&
      92             :         old_details.attributes() == new_details.attributes()) {
      93       12711 :       ReplaceTransitions(*weak_cell_with_target);
      94             :       return;
      95             :     }
      96             :     // Otherwise allocate a full TransitionArray with slack for a new entry.
      97       67649 :     Handle<TransitionArray> result = TransitionArray::Allocate(isolate, 1, 1);
      98             :     // Reload state; the allocation might have caused it to be cleared.
      99             :     Reload();
     100       67649 :     simple_transition = GetSimpleTransition();
     101       67649 :     if (simple_transition != nullptr) {
     102             :       result->Set(0, GetSimpleTransitionKey(simple_transition),
     103      135298 :                   raw_transitions_);
     104             :     } else {
     105             :       result->SetNumberOfTransitions(0);
     106             :     }
     107       67649 :     ReplaceTransitions(*result);
     108             :     Reload();
     109             :   }
     110             : 
     111             :   // At this point, we know that the map has a full TransitionArray.
     112             :   DCHECK_EQ(kFullTransitionArray, encoding());
     113             : 
     114             :   int number_of_transitions = 0;
     115             :   int new_nof = 0;
     116      484522 :   int insertion_index = kNotFound;
     117             :   DCHECK_EQ(is_special_transition, IsSpecialTransition(*name));
     118             :   PropertyDetails details = is_special_transition
     119             :                                 ? PropertyDetails::Empty()
     120      484522 :                                 : GetTargetDetails(*name, *target);
     121             : 
     122             :   {
     123             :     DisallowHeapAllocation no_gc;
     124             :     TransitionArray* array = transitions();
     125      484522 :     number_of_transitions = array->number_of_transitions();
     126             :     new_nof = number_of_transitions;
     127             : 
     128             :     int index =
     129             :         is_special_transition
     130             :             ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
     131             :             : array->Search(details.kind(), *name, details.attributes(),
     132      726771 :                             &insertion_index);
     133             :     // If an existing entry was found, overwrite it and return.
     134      484522 :     if (index != kNotFound) {
     135             :       array->SetTarget(index, *weak_cell_with_target);
     136             :       return;
     137             :     }
     138             : 
     139      474032 :     ++new_nof;
     140      474032 :     CHECK_LE(new_nof, kMaxNumberOfTransitions);
     141             :     DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
     142             : 
     143             :     // If there is enough capacity, insert new entry into the existing array.
     144      474032 :     if (new_nof <= array->Capacity()) {
     145             :       array->SetNumberOfTransitions(new_nof);
     146    10417784 :       for (index = number_of_transitions; index > insertion_index; --index) {
     147             :         array->SetKey(index, array->GetKey(index - 1));
     148     9617768 :         array->SetTarget(index, array->GetRawTarget(index - 1));
     149             :       }
     150             :       array->SetKey(index, *name);
     151             :       array->SetTarget(index, *weak_cell_with_target);
     152             :       SLOW_DCHECK(array->IsSortedNoDuplicates());
     153             :       return;
     154             :     }
     155             :   }
     156             : 
     157             :   // We're gonna need a bigger TransitionArray.
     158             :   Handle<TransitionArray> result = TransitionArray::Allocate(
     159             :       isolate, new_nof,
     160       74024 :       Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions));
     161             : 
     162             :   // The map's transition array may have shrunk during the allocation above as
     163             :   // it was weakly traversed, though it is guaranteed not to disappear. Trim the
     164             :   // result copy if needed, and recompute variables.
     165             :   Reload();
     166             :   DisallowHeapAllocation no_gc;
     167             :   TransitionArray* array = transitions();
     168       74024 :   if (array->number_of_transitions() != number_of_transitions) {
     169             :     DCHECK(array->number_of_transitions() < number_of_transitions);
     170             : 
     171           0 :     number_of_transitions = array->number_of_transitions();
     172             :     new_nof = number_of_transitions;
     173             : 
     174           0 :     insertion_index = kNotFound;
     175             :     int index =
     176             :         is_special_transition
     177             :             ? array->SearchSpecial(Symbol::cast(*name), &insertion_index)
     178             :             : array->Search(details.kind(), *name, details.attributes(),
     179           0 :                             &insertion_index);
     180           0 :     if (index == kNotFound) {
     181           0 :       ++new_nof;
     182             :     } else {
     183           0 :       insertion_index = index;
     184             :     }
     185             :     DCHECK(insertion_index >= 0 && insertion_index <= number_of_transitions);
     186             : 
     187           0 :     result->Shrink(TransitionArray::ToKeyIndex(new_nof));
     188             :     result->SetNumberOfTransitions(new_nof);
     189             :   }
     190             : 
     191       74024 :   if (array->HasPrototypeTransitions()) {
     192             :     result->SetPrototypeTransitions(array->GetPrototypeTransitions());
     193             :   }
     194             : 
     195             :   DCHECK_NE(kNotFound, insertion_index);
     196      285925 :   for (int i = 0; i < insertion_index; ++i) {
     197      423802 :     result->Set(i, array->GetKey(i), array->GetRawTarget(i));
     198             :   }
     199       74024 :   result->Set(insertion_index, *name, *weak_cell_with_target);
     200      375979 :   for (int i = insertion_index; i < number_of_transitions; ++i) {
     201      455862 :     result->Set(i + 1, array->GetKey(i), array->GetRawTarget(i));
     202             :   }
     203             : 
     204             :   SLOW_DCHECK(result->IsSortedNoDuplicates());
     205       74024 :   ReplaceTransitions(*result);
     206             : }
     207             : 
     208      456291 : void TransitionsAccessor::UpdateHandler(Name* name, Object* handler) {
     209      444766 :   if (map_->is_dictionary_map()) return;
     210      209922 :   switch (encoding()) {
     211             :     case kPrototypeInfo:
     212             :     case kUninitialized:
     213           0 :       UNREACHABLE();
     214             :       return;
     215             :     case kWeakCell:
     216             :     case kHandler:
     217             :       DCHECK_EQ(GetSimpleTransition(), GetTargetFromRaw(handler));
     218      197929 :       ReplaceTransitions(handler);
     219      197929 :       return;
     220             :     case kFullTransitionArray: {
     221       11993 :       PropertyAttributes attributes = name->IsPrivate() ? DONT_ENUM : NONE;
     222       11993 :       int transition = transitions()->Search(kData, name, attributes);
     223             :       DCHECK_NE(kNotFound, transition);
     224             :       DCHECK_EQ(transitions()->GetTarget(transition),
     225             :                 GetTargetFromRaw(handler));
     226             :       transitions()->SetTarget(transition, handler);
     227             :       return;
     228             :     }
     229             :   }
     230             : }
     231             : 
     232     4303862 : Object* TransitionsAccessor::SearchHandler(Name* name,
     233     4351300 :                                            Handle<Map>* out_transition) {
     234     4303862 :   switch (encoding()) {
     235             :     case kPrototypeInfo:
     236             :     case kUninitialized:
     237             :     case kWeakCell:
     238             :       return nullptr;
     239             :     case kHandler: {
     240             :       Object* raw_handler = StoreHandler::ValidHandlerOrNull(
     241       21260 :           raw_transitions_, name, out_transition);
     242       21260 :       if (raw_handler == nullptr) return raw_handler;
     243             :       // Check transition key.
     244       11075 :       WeakCell* target_cell = StoreHandler::GetTransitionCell(raw_handler);
     245       11075 :       if (!IsMatchingMap(target_cell, name, kData, NONE)) return nullptr;
     246        1530 :       return raw_handler;
     247             :     }
     248             : 
     249             :     case kFullTransitionArray: {
     250       32356 :       int transition = transitions()->Search(kData, name, NONE);
     251       32356 :       if (transition == kNotFound) return nullptr;
     252       15082 :       Object* raw_handler = transitions()->GetRawTarget(transition);
     253       15082 :       if (StoreHandler::IsHandler(raw_handler)) {
     254             :         return StoreHandler::ValidHandlerOrNull(raw_handler, name,
     255        1554 :                                                 out_transition);
     256             :       }
     257             :       return nullptr;
     258             :     }
     259             :   }
     260           0 :   UNREACHABLE();
     261             :   return nullptr;  // Make GCC happy.
     262             : }
     263             : 
     264    32003680 : Map* TransitionsAccessor::SearchTransition(Name* name, PropertyKind kind,
     265    59106496 :                                            PropertyAttributes attributes) {
     266             :   DCHECK(name->IsUniqueName());
     267             :   WeakCell* cell = nullptr;
     268    32003680 :   switch (encoding()) {
     269             :     case kPrototypeInfo:
     270             :     case kUninitialized:
     271             :       return nullptr;
     272             :     case kWeakCell:
     273             :       cell = GetTargetCell<kWeakCell>();
     274     5532773 :       break;
     275             :     case kHandler:
     276             :       cell = GetTargetCell<kHandler>();
     277       62865 :       break;
     278             :     case kFullTransitionArray: {
     279    10871848 :       int transition = transitions()->Search(kind, name, attributes);
     280    10871848 :       if (transition == kNotFound) return nullptr;
     281    10635330 :       return transitions()->GetTarget(transition);
     282             :     }
     283             :   }
     284             :   DCHECK(!cell->cleared());
     285     5595637 :   if (!IsMatchingMap(cell, name, kind, attributes)) return nullptr;
     286     5518059 :   return Map::cast(cell->value());
     287             : }
     288             : 
     289     4687370 : Map* TransitionsAccessor::SearchSpecial(Symbol* name) {
     290     1912309 :   if (encoding() != kFullTransitionArray) return nullptr;
     291             :   int transition = transitions()->SearchSpecial(name);
     292     1388321 :   if (transition == kNotFound) return nullptr;
     293     1386740 :   return transitions()->GetTarget(transition);
     294             : }
     295             : 
     296             : // static
     297           0 : bool TransitionsAccessor::IsSpecialTransition(Name* name) {
     298           0 :   if (!name->IsSymbol()) return false;
     299           0 :   Heap* heap = name->GetHeap();
     300           0 :   return name == heap->nonextensible_symbol() ||
     301           0 :          name == heap->sealed_symbol() || name == heap->frozen_symbol() ||
     302           0 :          name == heap->elements_transition_symbol() ||
     303           0 :          name == heap->strict_function_transition_symbol();
     304             : }
     305             : 
     306    10298749 : Handle<Map> TransitionsAccessor::FindTransitionToField(Handle<Name> name) {
     307             :   DCHECK(name->IsUniqueName());
     308             :   DisallowHeapAllocation no_gc;
     309    10298749 :   Map* target = SearchTransition(*name, kData, NONE);
     310    10298749 :   if (target == nullptr) return Handle<Map>::null();
     311             :   PropertyDetails details = target->GetLastDescriptorDetails();
     312             :   DCHECK_EQ(NONE, details.attributes());
     313    10199752 :   if (details.location() != kField) return Handle<Map>::null();
     314             :   DCHECK_EQ(kData, details.kind());
     315    10199742 :   return Handle<Map>(target);
     316             : }
     317             : 
     318    49185650 : Handle<String> TransitionsAccessor::ExpectedTransitionKey() {
     319             :   DisallowHeapAllocation no_gc;
     320             :   WeakCell* cell = nullptr;
     321    29687580 :   switch (encoding()) {
     322             :     case kPrototypeInfo:
     323             :     case kUninitialized:
     324             :     case kFullTransitionArray:
     325             :       return Handle<String>::null();
     326             :     case kWeakCell:
     327             :       cell = GetTargetCell<kWeakCell>();
     328    19498065 :       break;
     329             :     case kHandler:
     330             :       cell = GetTargetCell<kHandler>();
     331           5 :       break;
     332             :   }
     333             :   DCHECK(!cell->cleared());
     334             :   Map* target = Map::cast(cell->value());
     335    19498070 :   PropertyDetails details = GetSimpleTargetDetails(target);
     336    19498070 :   if (details.location() != kField) return Handle<String>::null();
     337             :   DCHECK_EQ(kData, details.kind());
     338    19497715 :   if (details.attributes() != NONE) return Handle<String>::null();
     339    19497715 :   Name* name = GetSimpleTransitionKey(target);
     340    19497715 :   if (!name->IsString()) return Handle<String>::null();
     341             :   return handle(String::cast(name));
     342             : }
     343             : 
     344    19488806 : Handle<Map> TransitionsAccessor::ExpectedTransitionTarget() {
     345             :   DCHECK(!ExpectedTransitionKey().is_null());
     346    38977612 :   return handle(GetTarget(0));
     347             : }
     348             : 
     349    25377202 : bool TransitionsAccessor::CanHaveMoreTransitions() {
     350    25283984 :   if (map_->is_dictionary_map()) return false;
     351    12560236 :   if (encoding() == kFullTransitionArray) {
     352      174974 :     return transitions()->number_of_transitions() < kMaxNumberOfTransitions;
     353             :   }
     354             :   return true;
     355             : }
     356             : 
     357             : // static
     358     5606713 : bool TransitionsAccessor::IsMatchingMap(WeakCell* target_cell, Name* name,
     359             :                                         PropertyKind kind,
     360             :                                         PropertyAttributes attributes) {
     361             :   Map* target = Map::cast(target_cell->value());
     362             :   int descriptor = target->LastAdded();
     363             :   DescriptorArray* descriptors = target->instance_descriptors();
     364             :   Name* key = descriptors->GetKey(descriptor);
     365     5606713 :   if (key != name) return false;
     366     5527929 :   PropertyDetails details = descriptors->GetDetails(descriptor);
     367    11051118 :   return (details.kind() == kind && details.attributes() == attributes);
     368             : }
     369             : 
     370             : // static
     371      157249 : bool TransitionArray::CompactPrototypeTransitionArray(FixedArray* array) {
     372             :   const int header = kProtoTransitionHeaderSize;
     373      157249 :   int number_of_transitions = NumberOfPrototypeTransitions(array);
     374      157249 :   if (number_of_transitions == 0) {
     375             :     // Empty array cannot be compacted.
     376             :     return false;
     377             :   }
     378             :   int new_number_of_transitions = 0;
     379       24785 :   for (int i = 0; i < number_of_transitions; i++) {
     380       20618 :     Object* cell = array->get(header + i);
     381       20618 :     if (!WeakCell::cast(cell)->cleared()) {
     382       15692 :       if (new_number_of_transitions != i) {
     383           8 :         array->set(header + new_number_of_transitions, cell);
     384             :       }
     385       15692 :       new_number_of_transitions++;
     386             :     }
     387             :   }
     388             :   // Fill slots that became free with undefined value.
     389        9093 :   for (int i = new_number_of_transitions; i < number_of_transitions; i++) {
     390        4926 :     array->set_undefined(header + i);
     391             :   }
     392        4167 :   if (number_of_transitions != new_number_of_transitions) {
     393             :     SetNumberOfPrototypeTransitions(array, new_number_of_transitions);
     394             :   }
     395        4167 :   return new_number_of_transitions < number_of_transitions;
     396             : }
     397             : 
     398             : 
     399             : // static
     400      154802 : Handle<FixedArray> TransitionArray::GrowPrototypeTransitionArray(
     401             :     Handle<FixedArray> array, int new_capacity, Isolate* isolate) {
     402             :   // Grow array by factor 2 up to MaxCachedPrototypeTransitions.
     403      154802 :   int capacity = array->length() - kProtoTransitionHeaderSize;
     404             :   new_capacity = Min(kMaxCachedPrototypeTransitions, new_capacity);
     405             :   DCHECK_GT(new_capacity, capacity);
     406      154802 :   int grow_by = new_capacity - capacity;
     407      154802 :   array = isolate->factory()->CopyFixedArrayAndGrow(array, grow_by, TENURED);
     408      154802 :   if (capacity < 0) {
     409             :     // There was no prototype transitions array before, so the size
     410             :     // couldn't be copied. Initialize it explicitly.
     411             :     SetNumberOfPrototypeTransitions(*array, 0);
     412             :   }
     413      154802 :   return array;
     414             : }
     415             : 
     416      202818 : void TransitionsAccessor::PutPrototypeTransition(Handle<Object> prototype,
     417             :                                                  Handle<Map> target_map) {
     418             :   DCHECK(HeapObject::cast(*prototype)->map()->IsMap());
     419             :   // Don't cache prototype transition if this map is either shared, or a map of
     420             :   // a prototype.
     421      434644 :   if (map_->is_prototype_map()) return;
     422      189295 :   if (map_->is_dictionary_map() || !FLAG_cache_prototype_transitions) return;
     423             : 
     424             :   const int header = TransitionArray::kProtoTransitionHeaderSize;
     425             : 
     426      173810 :   Handle<FixedArray> cache(GetPrototypeTransitions());
     427      173810 :   int capacity = cache->length() - header;
     428      173810 :   int transitions = TransitionArray::NumberOfPrototypeTransitions(*cache) + 1;
     429             : 
     430      173810 :   if (transitions > capacity) {
     431             :     // Grow the array if compacting it doesn't free space.
     432      157249 :     if (!TransitionArray::CompactPrototypeTransitionArray(*cache)) {
     433      154802 :       if (capacity == TransitionArray::kMaxCachedPrototypeTransitions) return;
     434             :       cache = TransitionArray::GrowPrototypeTransitionArray(
     435      154802 :           cache, 2 * transitions, target_map->GetIsolate());
     436             :       Reload();
     437      154802 :       SetPrototypeTransitions(cache);
     438             :     }
     439             :   }
     440             : 
     441             :   // Reload number of transitions as they might have been compacted.
     442      173810 :   int last = TransitionArray::NumberOfPrototypeTransitions(*cache);
     443      173810 :   int entry = header + last;
     444             : 
     445      173810 :   Handle<WeakCell> target_cell = Map::WeakCellForMap(target_map);
     446             :   Reload();  // Reload after possible GC.
     447      173810 :   cache->set(entry, *target_cell);
     448             :   TransitionArray::SetNumberOfPrototypeTransitions(*cache, last + 1);
     449             : }
     450             : 
     451     2650252 : Handle<Map> TransitionsAccessor::GetPrototypeTransition(
     452             :     Handle<Object> prototype) {
     453             :   DisallowHeapAllocation no_gc;
     454     2650252 :   FixedArray* cache = GetPrototypeTransitions();
     455     2650252 :   int length = TransitionArray::NumberOfPrototypeTransitions(cache);
     456     2650252 :   for (int i = 0; i < length; i++) {
     457             :     WeakCell* target_cell = WeakCell::cast(
     458     3704644 :         cache->get(TransitionArray::kProtoTransitionHeaderSize + i));
     459     6529408 :     if (!target_cell->cleared() &&
     460             :         Map::cast(target_cell->value())->prototype() == *prototype) {
     461             :       return handle(Map::cast(target_cell->value()));
     462             :     }
     463             :   }
     464      202818 :   return Handle<Map>();
     465             : }
     466             : 
     467     7810044 : FixedArray* TransitionsAccessor::GetPrototypeTransitions() {
     468     5321154 :   if (encoding() != kFullTransitionArray ||
     469             :       !transitions()->HasPrototypeTransitions()) {
     470      670344 :     return map_->GetHeap()->empty_fixed_array();
     471             :   }
     472     2488890 :   return transitions()->GetPrototypeTransitions();
     473             : }
     474             : 
     475             : // static
     476           0 : void TransitionArray::SetNumberOfPrototypeTransitions(
     477             :     FixedArray* proto_transitions, int value) {
     478             :   DCHECK_NE(proto_transitions->length(), 0);
     479             :   proto_transitions->set(kProtoTransitionNumberOfEntriesOffset,
     480             :                          Smi::FromInt(value));
     481           0 : }
     482             : 
     483     1936549 : int TransitionsAccessor::NumberOfTransitions() {
     484     1936028 :   switch (encoding()) {
     485             :     case kPrototypeInfo:
     486             :     case kUninitialized:
     487             :       return 0;
     488             :     case kWeakCell:
     489             :     case kHandler:
     490     1599929 :       return 1;
     491             :     case kFullTransitionArray:
     492         521 :       return transitions()->number_of_transitions();
     493             :   }
     494           0 :   UNREACHABLE();
     495             :   return 0;  // Make GCC happy.
     496             : }
     497             : 
     498      531041 : Handle<TransitionArray> TransitionArray::Allocate(Isolate* isolate,
     499             :                                                   int number_of_transitions,
     500             :                                                   int slack) {
     501             :   Handle<FixedArray> array = isolate->factory()->NewTransitionArray(
     502     1062082 :       LengthFor(number_of_transitions + slack));
     503             :   array->set(kPrototypeTransitionsIndex, Smi::kZero);
     504             :   array->set(kTransitionLengthIndex, Smi::FromInt(number_of_transitions));
     505      531041 :   return Handle<TransitionArray>::cast(array);
     506             : }
     507             : 
     508       74024 : void TransitionArray::Zap() {
     509             :   MemsetPointer(data_start() + kPrototypeTransitionsIndex,
     510             :                 GetHeap()->the_hole_value(),
     511       74024 :                 length() - kPrototypeTransitionsIndex);
     512             :   SetNumberOfTransitions(0);
     513       74024 : }
     514             : 
     515     6464423 : void TransitionsAccessor::ReplaceTransitions(Object* new_transitions) {
     516     6390399 :   if (encoding() == kFullTransitionArray) {
     517             :     TransitionArray* old_transitions = transitions();
     518             : #if DEBUG
     519             :     CheckNewTransitionsAreConsistent(old_transitions, new_transitions);
     520             :     DCHECK(old_transitions != new_transitions);
     521             : #endif
     522             :     // Transition arrays are not shared. When one is replaced, it should not
     523             :     // keep referenced objects alive, so we zap it.
     524             :     // When there is another reference to the array somewhere (e.g. a handle),
     525             :     // not zapping turns from a waste of memory into a source of crashes.
     526       74024 :     old_transitions->Zap();
     527             :   }
     528     6390399 :   map_->set_raw_transitions(new_transitions);
     529             :   MarkNeedsReload();
     530     6390400 : }
     531             : 
     532      154802 : void TransitionsAccessor::SetPrototypeTransitions(
     533      154802 :     Handle<FixedArray> proto_transitions) {
     534      154802 :   EnsureHasFullTransitionArray();
     535             :   transitions()->SetPrototypeTransitions(*proto_transitions);
     536      154802 : }
     537             : 
     538      161387 : void TransitionsAccessor::EnsureHasFullTransitionArray() {
     539      309604 :   if (encoding() == kFullTransitionArray) return;
     540      148981 :   int nof = encoding() == kUninitialized ? 0 : 1;
     541             :   Handle<TransitionArray> result =
     542      297962 :       TransitionArray::Allocate(map_->GetIsolate(), nof);
     543             :   Reload();  // Reload after possible GC.
     544      148981 :   if (nof == 1) {
     545        6585 :     if (encoding() == kUninitialized) {
     546             :       // If allocation caused GC and cleared the target, trim the new array.
     547           0 :       result->Shrink(TransitionArray::ToKeyIndex(0));
     548             :       result->SetNumberOfTransitions(0);
     549             :     } else {
     550             :       // Otherwise populate the new array.
     551        6585 :       Handle<Map> target(GetSimpleTransition());
     552        6585 :       Handle<WeakCell> weak_cell_with_target = Map::WeakCellForMap(target);
     553             :       Reload();  // Reload after possible GC.
     554        6585 :       Name* key = GetSimpleTransitionKey(*target);
     555        6585 :       result->Set(0, key, *weak_cell_with_target);
     556             :     }
     557             :   }
     558      148981 :   ReplaceTransitions(*result);
     559             :   Reload();  // Reload after replacing transitions.
     560             : }
     561             : 
     562      321938 : void TransitionsAccessor::TraverseTransitionTreeInternal(
     563      561272 :     TraverseCallback callback, void* data, DisallowHeapAllocation* no_gc) {
     564             :   Map* simple_target = nullptr;
     565      321938 :   switch (encoding()) {
     566             :     case kPrototypeInfo:
     567             :     case kUninitialized:
     568             :       break;
     569             :     case kWeakCell:
     570             :       simple_target = Map::cast(GetTargetCell<kWeakCell>()->value());
     571       56814 :       break;
     572             :     case kHandler:
     573             :       simple_target = Map::cast(GetTargetCell<kHandler>()->value());
     574      169340 :       break;
     575             :     case kFullTransitionArray: {
     576        2568 :       if (transitions()->HasPrototypeTransitions()) {
     577             :         FixedArray* proto_trans = transitions()->GetPrototypeTransitions();
     578          60 :         int length = TransitionArray::NumberOfPrototypeTransitions(proto_trans);
     579         300 :         for (int i = 0; i < length; ++i) {
     580         180 :           int index = TransitionArray::kProtoTransitionHeaderSize + i;
     581             :           WeakCell* cell = WeakCell::cast(proto_trans->get(index));
     582         180 :           if (cell->cleared()) continue;
     583             :           TransitionsAccessor(Map::cast(cell->value()), no_gc)
     584         180 :               .TraverseTransitionTreeInternal(callback, data, no_gc);
     585             :         }
     586             :       }
     587       10552 :       for (int i = 0; i < transitions()->number_of_transitions(); ++i) {
     588             :         TransitionsAccessor(transitions()->GetTarget(i), no_gc)
     589        3992 :             .TraverseTransitionTreeInternal(callback, data, no_gc);
     590             :       }
     591             :       break;
     592             :     }
     593             :   }
     594      321938 :   if (simple_target != nullptr) {
     595             :     TransitionsAccessor(simple_target, no_gc)
     596      226154 :         .TraverseTransitionTreeInternal(callback, data, no_gc);
     597             :   }
     598      321938 :   callback(map_, data);
     599      321938 : }
     600             : 
     601             : #ifdef DEBUG
     602             : void TransitionsAccessor::CheckNewTransitionsAreConsistent(
     603             :     TransitionArray* old_transitions, Object* transitions) {
     604             :   // This function only handles full transition arrays.
     605             :   DCHECK_EQ(kFullTransitionArray, encoding());
     606             :   TransitionArray* new_transitions = TransitionArray::cast(transitions);
     607             :   for (int i = 0; i < old_transitions->number_of_transitions(); i++) {
     608             :     Map* target = old_transitions->GetTarget(i);
     609             :     if (target->instance_descriptors() == map_->instance_descriptors()) {
     610             :       Name* key = old_transitions->GetKey(i);
     611             :       int new_target_index;
     612             :       if (IsSpecialTransition(key)) {
     613             :         new_target_index = new_transitions->SearchSpecial(Symbol::cast(key));
     614             :       } else {
     615             :         PropertyDetails details = GetTargetDetails(key, target);
     616             :         new_target_index =
     617             :             new_transitions->Search(details.kind(), key, details.attributes());
     618             :       }
     619             :       DCHECK_NE(TransitionArray::kNotFound, new_target_index);
     620             :       DCHECK_EQ(target, new_transitions->GetTarget(new_target_index));
     621             :     }
     622             :   }
     623             : }
     624             : #endif
     625             : 
     626             : // Private non-static helper functions (operating on full transition arrays).
     627             : 
     628    10683076 : int TransitionArray::SearchDetails(int transition, PropertyKind kind,
     629             :                                    PropertyAttributes attributes,
     630             :                                    int* out_insertion_index) {
     631    10683076 :   int nof_transitions = number_of_transitions();
     632             :   DCHECK(transition < nof_transitions);
     633             :   Name* key = GetKey(transition);
     634    21405628 :   for (; transition < nof_transitions && GetKey(transition) == key;
     635             :        transition++) {
     636             :     Map* target = GetTarget(transition);
     637             :     PropertyDetails target_details =
     638             :         TransitionsAccessor::GetTargetDetails(key, target);
     639             : 
     640             :     int cmp = CompareDetails(kind, attributes, target_details.kind(),
     641             :                              target_details.attributes());
     642    10697626 :     if (cmp == 0) {
     643             :       return transition;
     644       24731 :     } else if (cmp < 0) {
     645             :       break;
     646             :     }
     647             :   }
     648       10181 :   if (out_insertion_index != nullptr) *out_insertion_index = transition;
     649             :   return kNotFound;
     650             : }
     651             : 
     652             : 
     653    11158446 : int TransitionArray::Search(PropertyKind kind, Name* name,
     654             :                             PropertyAttributes attributes,
     655             :                             int* out_insertion_index) {
     656    11158446 :   int transition = SearchName(name, out_insertion_index);
     657    11158445 :   if (transition == kNotFound) return kNotFound;
     658    10683076 :   return SearchDetails(transition, kind, attributes, out_insertion_index);
     659             : }
     660             : 
     661           0 : void TransitionArray::Sort() {
     662             :   DisallowHeapAllocation no_gc;
     663             :   // In-place insertion sort.
     664           0 :   int length = number_of_transitions();
     665           0 :   for (int i = 1; i < length; i++) {
     666             :     Name* key = GetKey(i);
     667             :     Map* target = GetTarget(i);
     668             :     PropertyKind kind = kData;
     669             :     PropertyAttributes attributes = NONE;
     670           0 :     if (!TransitionsAccessor::IsSpecialTransition(key)) {
     671             :       PropertyDetails details =
     672             :           TransitionsAccessor::GetTargetDetails(key, target);
     673             :       kind = details.kind();
     674             :       attributes = details.attributes();
     675             :     }
     676             :     int j;
     677           0 :     for (j = i - 1; j >= 0; j--) {
     678             :       Name* temp_key = GetKey(j);
     679             :       Map* temp_target = GetTarget(j);
     680             :       PropertyKind temp_kind = kData;
     681             :       PropertyAttributes temp_attributes = NONE;
     682           0 :       if (!TransitionsAccessor::IsSpecialTransition(temp_key)) {
     683             :         PropertyDetails details =
     684             :             TransitionsAccessor::GetTargetDetails(temp_key, temp_target);
     685             :         temp_kind = details.kind();
     686             :         temp_attributes = details.attributes();
     687             :       }
     688             :       int cmp =
     689             :           CompareKeys(temp_key, temp_key->Hash(), temp_kind, temp_attributes,
     690             :                       key, key->Hash(), kind, attributes);
     691           0 :       if (cmp > 0) {
     692             :         SetKey(j + 1, temp_key);
     693             :         SetTarget(j + 1, temp_target);
     694             :       } else {
     695             :         break;
     696             :       }
     697             :     }
     698             :     SetKey(j + 1, key);
     699             :     SetTarget(j + 1, target);
     700             :   }
     701             :   DCHECK(IsSortedNoDuplicates());
     702           0 : }
     703             : 
     704             : }  // namespace internal
     705             : }  // namespace v8

Generated by: LCOV version 1.10