11cb0ef41Sopenharmony_ci// Copyright 2012 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/objects/transitions.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/base/small-vector.h" 81cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 91cb0ef41Sopenharmony_ci#include "src/objects/transitions-inl.h" 101cb0ef41Sopenharmony_ci#include "src/utils/utils.h" 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_cinamespace v8 { 131cb0ef41Sopenharmony_cinamespace internal { 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci// static 161cb0ef41Sopenharmony_ciMap TransitionsAccessor::GetSimpleTransition(Isolate* isolate, 171cb0ef41Sopenharmony_ci Handle<Map> map) { 181cb0ef41Sopenharmony_ci MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad); 191cb0ef41Sopenharmony_ci switch (GetEncoding(isolate, raw_transitions)) { 201cb0ef41Sopenharmony_ci case kWeakRef: 211cb0ef41Sopenharmony_ci return Map::cast(raw_transitions->GetHeapObjectAssumeWeak()); 221cb0ef41Sopenharmony_ci default: 231cb0ef41Sopenharmony_ci return Map(); 241cb0ef41Sopenharmony_ci } 251cb0ef41Sopenharmony_ci} 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_cibool TransitionsAccessor::HasSimpleTransitionTo(Map map) { 281cb0ef41Sopenharmony_ci switch (encoding()) { 291cb0ef41Sopenharmony_ci case kWeakRef: 301cb0ef41Sopenharmony_ci return raw_transitions_->GetHeapObjectAssumeWeak() == map; 311cb0ef41Sopenharmony_ci case kPrototypeInfo: 321cb0ef41Sopenharmony_ci case kUninitialized: 331cb0ef41Sopenharmony_ci case kMigrationTarget: 341cb0ef41Sopenharmony_ci case kFullTransitionArray: 351cb0ef41Sopenharmony_ci return false; 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci UNREACHABLE(); 381cb0ef41Sopenharmony_ci} 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci// static 411cb0ef41Sopenharmony_civoid TransitionsAccessor::Insert(Isolate* isolate, Handle<Map> map, 421cb0ef41Sopenharmony_ci Handle<Name> name, Handle<Map> target, 431cb0ef41Sopenharmony_ci SimpleTransitionFlag flag) { 441cb0ef41Sopenharmony_ci Encoding encoding = GetEncoding(isolate, map); 451cb0ef41Sopenharmony_ci DCHECK_NE(kPrototypeInfo, encoding); 461cb0ef41Sopenharmony_ci target->SetBackPointer(*map); 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci // If the map doesn't have any transitions at all yet, install the new one. 491cb0ef41Sopenharmony_ci if (encoding == kUninitialized || encoding == kMigrationTarget) { 501cb0ef41Sopenharmony_ci if (flag == SIMPLE_PROPERTY_TRANSITION) { 511cb0ef41Sopenharmony_ci ReplaceTransitions(isolate, map, HeapObjectReference::Weak(*target)); 521cb0ef41Sopenharmony_ci return; 531cb0ef41Sopenharmony_ci } 541cb0ef41Sopenharmony_ci // If the flag requires a full TransitionArray, allocate one. 551cb0ef41Sopenharmony_ci Handle<TransitionArray> result = 561cb0ef41Sopenharmony_ci isolate->factory()->NewTransitionArray(1, 0); 571cb0ef41Sopenharmony_ci result->Set(0, *name, HeapObjectReference::Weak(*target)); 581cb0ef41Sopenharmony_ci ReplaceTransitions(isolate, map, result); 591cb0ef41Sopenharmony_ci DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, *result)); 601cb0ef41Sopenharmony_ci return; 611cb0ef41Sopenharmony_ci } 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci if (encoding == kWeakRef) { 641cb0ef41Sopenharmony_ci Map simple_transition = GetSimpleTransition(isolate, map); 651cb0ef41Sopenharmony_ci DCHECK(!simple_transition.is_null()); 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci if (flag == SIMPLE_PROPERTY_TRANSITION) { 681cb0ef41Sopenharmony_ci Name key = GetSimpleTransitionKey(simple_transition); 691cb0ef41Sopenharmony_ci PropertyDetails old_details = 701cb0ef41Sopenharmony_ci simple_transition.GetLastDescriptorDetails(isolate); 711cb0ef41Sopenharmony_ci PropertyDetails new_details = GetTargetDetails(*name, *target); 721cb0ef41Sopenharmony_ci if (key.Equals(*name) && old_details.kind() == new_details.kind() && 731cb0ef41Sopenharmony_ci old_details.attributes() == new_details.attributes()) { 741cb0ef41Sopenharmony_ci ReplaceTransitions(isolate, map, HeapObjectReference::Weak(*target)); 751cb0ef41Sopenharmony_ci return; 761cb0ef41Sopenharmony_ci } 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci // Otherwise allocate a full TransitionArray with slack for a new entry. 801cb0ef41Sopenharmony_ci Handle<TransitionArray> result = 811cb0ef41Sopenharmony_ci isolate->factory()->NewTransitionArray(1, 1); 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci // Reload `simple_transition`. Allocations might have caused it to be 841cb0ef41Sopenharmony_ci // cleared. 851cb0ef41Sopenharmony_ci simple_transition = GetSimpleTransition(isolate, map); 861cb0ef41Sopenharmony_ci if (simple_transition.is_null()) { 871cb0ef41Sopenharmony_ci result->Set(0, *name, HeapObjectReference::Weak(*target)); 881cb0ef41Sopenharmony_ci ReplaceTransitions(isolate, map, result); 891cb0ef41Sopenharmony_ci DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, *result)); 901cb0ef41Sopenharmony_ci return; 911cb0ef41Sopenharmony_ci } 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci // Insert the original transition in index 0. 941cb0ef41Sopenharmony_ci result->Set(0, GetSimpleTransitionKey(simple_transition), 951cb0ef41Sopenharmony_ci HeapObjectReference::Weak(simple_transition)); 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci // Search for the correct index to insert the new transition. 981cb0ef41Sopenharmony_ci int insertion_index; 991cb0ef41Sopenharmony_ci int index; 1001cb0ef41Sopenharmony_ci if (flag == SPECIAL_TRANSITION) { 1011cb0ef41Sopenharmony_ci index = 1021cb0ef41Sopenharmony_ci result->SearchSpecial(Symbol::cast(*name), false, &insertion_index); 1031cb0ef41Sopenharmony_ci } else { 1041cb0ef41Sopenharmony_ci PropertyDetails details = GetTargetDetails(*name, *target); 1051cb0ef41Sopenharmony_ci index = result->Search(details.kind(), *name, details.attributes(), 1061cb0ef41Sopenharmony_ci &insertion_index); 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci DCHECK_EQ(index, kNotFound); 1091cb0ef41Sopenharmony_ci USE(index); 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci result->SetNumberOfTransitions(2); 1121cb0ef41Sopenharmony_ci if (insertion_index == 0) { 1131cb0ef41Sopenharmony_ci // If the new transition will be inserted in index 0, move the original 1141cb0ef41Sopenharmony_ci // transition to index 1. 1151cb0ef41Sopenharmony_ci result->Set(1, GetSimpleTransitionKey(simple_transition), 1161cb0ef41Sopenharmony_ci HeapObjectReference::Weak(simple_transition)); 1171cb0ef41Sopenharmony_ci } 1181cb0ef41Sopenharmony_ci result->SetKey(insertion_index, *name); 1191cb0ef41Sopenharmony_ci result->SetRawTarget(insertion_index, HeapObjectReference::Weak(*target)); 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_ci SLOW_DCHECK(result->IsSortedNoDuplicates()); 1221cb0ef41Sopenharmony_ci ReplaceTransitions(isolate, map, result); 1231cb0ef41Sopenharmony_ci DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, *result)); 1241cb0ef41Sopenharmony_ci return; 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci // At this point, we know that the map has a full TransitionArray. 1281cb0ef41Sopenharmony_ci DCHECK_EQ(kFullTransitionArray, encoding); 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci int number_of_transitions = 0; 1311cb0ef41Sopenharmony_ci int new_nof = 0; 1321cb0ef41Sopenharmony_ci int insertion_index = kNotFound; 1331cb0ef41Sopenharmony_ci const bool is_special_transition = flag == SPECIAL_TRANSITION; 1341cb0ef41Sopenharmony_ci DCHECK_EQ(is_special_transition, 1351cb0ef41Sopenharmony_ci IsSpecialTransition(ReadOnlyRoots(isolate), *name)); 1361cb0ef41Sopenharmony_ci PropertyDetails details = is_special_transition 1371cb0ef41Sopenharmony_ci ? PropertyDetails::Empty() 1381cb0ef41Sopenharmony_ci : GetTargetDetails(*name, *target); 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci { 1411cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 1421cb0ef41Sopenharmony_ci TransitionArray array = GetTransitionArray(isolate, map); 1431cb0ef41Sopenharmony_ci number_of_transitions = array.number_of_transitions(); 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci int index = 1461cb0ef41Sopenharmony_ci is_special_transition 1471cb0ef41Sopenharmony_ci ? array.SearchSpecial(Symbol::cast(*name), false, &insertion_index) 1481cb0ef41Sopenharmony_ci : array.Search(details.kind(), *name, details.attributes(), 1491cb0ef41Sopenharmony_ci &insertion_index); 1501cb0ef41Sopenharmony_ci // If an existing entry was found, overwrite it and return. 1511cb0ef41Sopenharmony_ci if (index != kNotFound) { 1521cb0ef41Sopenharmony_ci base::SharedMutexGuard<base::kExclusive> shared_mutex_guard( 1531cb0ef41Sopenharmony_ci isolate->full_transition_array_access()); 1541cb0ef41Sopenharmony_ci array.SetRawTarget(index, HeapObjectReference::Weak(*target)); 1551cb0ef41Sopenharmony_ci return; 1561cb0ef41Sopenharmony_ci } 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci new_nof = number_of_transitions + 1; 1591cb0ef41Sopenharmony_ci CHECK_LE(new_nof, kMaxNumberOfTransitions); 1601cb0ef41Sopenharmony_ci DCHECK_GE(insertion_index, 0); 1611cb0ef41Sopenharmony_ci DCHECK_LE(insertion_index, number_of_transitions); 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci // If there is enough capacity, insert new entry into the existing array. 1641cb0ef41Sopenharmony_ci if (new_nof <= array.Capacity()) { 1651cb0ef41Sopenharmony_ci base::SharedMutexGuard<base::kExclusive> shared_mutex_guard( 1661cb0ef41Sopenharmony_ci isolate->full_transition_array_access()); 1671cb0ef41Sopenharmony_ci array.SetNumberOfTransitions(new_nof); 1681cb0ef41Sopenharmony_ci for (int i = number_of_transitions; i > insertion_index; --i) { 1691cb0ef41Sopenharmony_ci array.SetKey(i, array.GetKey(i - 1)); 1701cb0ef41Sopenharmony_ci array.SetRawTarget(i, array.GetRawTarget(i - 1)); 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci array.SetKey(insertion_index, *name); 1731cb0ef41Sopenharmony_ci array.SetRawTarget(insertion_index, HeapObjectReference::Weak(*target)); 1741cb0ef41Sopenharmony_ci SLOW_DCHECK(array.IsSortedNoDuplicates()); 1751cb0ef41Sopenharmony_ci return; 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci // We're gonna need a bigger TransitionArray. 1801cb0ef41Sopenharmony_ci Handle<TransitionArray> result = isolate->factory()->NewTransitionArray( 1811cb0ef41Sopenharmony_ci new_nof, 1821cb0ef41Sopenharmony_ci Map::SlackForArraySize(number_of_transitions, kMaxNumberOfTransitions)); 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci // The map's transition array may have shrunk during the allocation above as 1851cb0ef41Sopenharmony_ci // it was weakly traversed, though it is guaranteed not to disappear. Trim the 1861cb0ef41Sopenharmony_ci // result copy if needed, and recompute variables. 1871cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 1881cb0ef41Sopenharmony_ci TransitionArray array = GetTransitionArray(isolate, map); 1891cb0ef41Sopenharmony_ci if (array.number_of_transitions() != number_of_transitions) { 1901cb0ef41Sopenharmony_ci DCHECK_LT(array.number_of_transitions(), number_of_transitions); 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci int index = 1931cb0ef41Sopenharmony_ci is_special_transition 1941cb0ef41Sopenharmony_ci ? array.SearchSpecial(Symbol::cast(*name), false, &insertion_index) 1951cb0ef41Sopenharmony_ci : array.Search(details.kind(), *name, details.attributes(), 1961cb0ef41Sopenharmony_ci &insertion_index); 1971cb0ef41Sopenharmony_ci CHECK_EQ(index, kNotFound); 1981cb0ef41Sopenharmony_ci USE(index); 1991cb0ef41Sopenharmony_ci DCHECK_GE(insertion_index, 0); 2001cb0ef41Sopenharmony_ci DCHECK_LE(insertion_index, number_of_transitions); 2011cb0ef41Sopenharmony_ci 2021cb0ef41Sopenharmony_ci number_of_transitions = array.number_of_transitions(); 2031cb0ef41Sopenharmony_ci new_nof = number_of_transitions + 1; 2041cb0ef41Sopenharmony_ci result->SetNumberOfTransitions(new_nof); 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci if (array.HasPrototypeTransitions()) { 2081cb0ef41Sopenharmony_ci result->SetPrototypeTransitions(array.GetPrototypeTransitions()); 2091cb0ef41Sopenharmony_ci } 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci DCHECK_NE(kNotFound, insertion_index); 2121cb0ef41Sopenharmony_ci for (int i = 0; i < insertion_index; ++i) { 2131cb0ef41Sopenharmony_ci result->Set(i, array.GetKey(i), array.GetRawTarget(i)); 2141cb0ef41Sopenharmony_ci } 2151cb0ef41Sopenharmony_ci result->Set(insertion_index, *name, HeapObjectReference::Weak(*target)); 2161cb0ef41Sopenharmony_ci for (int i = insertion_index; i < number_of_transitions; ++i) { 2171cb0ef41Sopenharmony_ci result->Set(i + 1, array.GetKey(i), array.GetRawTarget(i)); 2181cb0ef41Sopenharmony_ci } 2191cb0ef41Sopenharmony_ci 2201cb0ef41Sopenharmony_ci SLOW_DCHECK(result->IsSortedNoDuplicates()); 2211cb0ef41Sopenharmony_ci ReplaceTransitions(isolate, map, result); 2221cb0ef41Sopenharmony_ci} 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ciMap TransitionsAccessor::SearchTransition(Name name, PropertyKind kind, 2251cb0ef41Sopenharmony_ci PropertyAttributes attributes) { 2261cb0ef41Sopenharmony_ci DCHECK(name.IsUniqueName()); 2271cb0ef41Sopenharmony_ci switch (encoding()) { 2281cb0ef41Sopenharmony_ci case kPrototypeInfo: 2291cb0ef41Sopenharmony_ci case kUninitialized: 2301cb0ef41Sopenharmony_ci case kMigrationTarget: 2311cb0ef41Sopenharmony_ci return Map(); 2321cb0ef41Sopenharmony_ci case kWeakRef: { 2331cb0ef41Sopenharmony_ci Map map = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak()); 2341cb0ef41Sopenharmony_ci if (!IsMatchingMap(map, name, kind, attributes)) return Map(); 2351cb0ef41Sopenharmony_ci return map; 2361cb0ef41Sopenharmony_ci } 2371cb0ef41Sopenharmony_ci case kFullTransitionArray: { 2381cb0ef41Sopenharmony_ci base::SharedMutexGuardIf<base::kShared> scope( 2391cb0ef41Sopenharmony_ci isolate_->full_transition_array_access(), concurrent_access_); 2401cb0ef41Sopenharmony_ci return transitions().SearchAndGetTarget(kind, name, attributes); 2411cb0ef41Sopenharmony_ci } 2421cb0ef41Sopenharmony_ci } 2431cb0ef41Sopenharmony_ci UNREACHABLE(); 2441cb0ef41Sopenharmony_ci} 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ciMap TransitionsAccessor::SearchSpecial(Symbol name) { 2471cb0ef41Sopenharmony_ci if (encoding() != kFullTransitionArray) return Map(); 2481cb0ef41Sopenharmony_ci base::SharedMutexGuardIf<base::kShared> scope( 2491cb0ef41Sopenharmony_ci isolate_->full_transition_array_access(), concurrent_access_); 2501cb0ef41Sopenharmony_ci int transition = transitions().SearchSpecial(name, concurrent_access_); 2511cb0ef41Sopenharmony_ci if (transition == kNotFound) return Map(); 2521cb0ef41Sopenharmony_ci return transitions().GetTarget(transition); 2531cb0ef41Sopenharmony_ci} 2541cb0ef41Sopenharmony_ci 2551cb0ef41Sopenharmony_ci// static 2561cb0ef41Sopenharmony_cibool TransitionsAccessor::IsSpecialTransition(ReadOnlyRoots roots, Name name) { 2571cb0ef41Sopenharmony_ci if (!name.IsSymbol()) return false; 2581cb0ef41Sopenharmony_ci return name == roots.nonextensible_symbol() || 2591cb0ef41Sopenharmony_ci name == roots.sealed_symbol() || name == roots.frozen_symbol() || 2601cb0ef41Sopenharmony_ci name == roots.elements_transition_symbol() || 2611cb0ef41Sopenharmony_ci name == roots.strict_function_transition_symbol(); 2621cb0ef41Sopenharmony_ci} 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ciMaybeHandle<Map> TransitionsAccessor::FindTransitionToDataProperty( 2651cb0ef41Sopenharmony_ci Handle<Name> name, RequestedLocation requested_location) { 2661cb0ef41Sopenharmony_ci DCHECK(name->IsUniqueName()); 2671cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 2681cb0ef41Sopenharmony_ci PropertyAttributes attributes = name->IsPrivate() ? DONT_ENUM : NONE; 2691cb0ef41Sopenharmony_ci Map target = SearchTransition(*name, PropertyKind::kData, attributes); 2701cb0ef41Sopenharmony_ci if (target.is_null()) return MaybeHandle<Map>(); 2711cb0ef41Sopenharmony_ci PropertyDetails details = target.GetLastDescriptorDetails(isolate_); 2721cb0ef41Sopenharmony_ci DCHECK_EQ(attributes, details.attributes()); 2731cb0ef41Sopenharmony_ci DCHECK_EQ(PropertyKind::kData, details.kind()); 2741cb0ef41Sopenharmony_ci if (requested_location == kFieldOnly && 2751cb0ef41Sopenharmony_ci details.location() != PropertyLocation::kField) { 2761cb0ef41Sopenharmony_ci return MaybeHandle<Map>(); 2771cb0ef41Sopenharmony_ci } 2781cb0ef41Sopenharmony_ci return Handle<Map>(target, isolate_); 2791cb0ef41Sopenharmony_ci} 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_civoid TransitionsAccessor::ForEachTransitionTo( 2821cb0ef41Sopenharmony_ci Name name, const ForEachTransitionCallback& callback, 2831cb0ef41Sopenharmony_ci DisallowGarbageCollection* no_gc) { 2841cb0ef41Sopenharmony_ci DCHECK(name.IsUniqueName()); 2851cb0ef41Sopenharmony_ci switch (encoding()) { 2861cb0ef41Sopenharmony_ci case kPrototypeInfo: 2871cb0ef41Sopenharmony_ci case kUninitialized: 2881cb0ef41Sopenharmony_ci case kMigrationTarget: 2891cb0ef41Sopenharmony_ci return; 2901cb0ef41Sopenharmony_ci case kWeakRef: { 2911cb0ef41Sopenharmony_ci Map target = Map::cast(raw_transitions_->GetHeapObjectAssumeWeak()); 2921cb0ef41Sopenharmony_ci InternalIndex descriptor = target.LastAdded(); 2931cb0ef41Sopenharmony_ci DescriptorArray descriptors = target.instance_descriptors(kRelaxedLoad); 2941cb0ef41Sopenharmony_ci Name key = descriptors.GetKey(descriptor); 2951cb0ef41Sopenharmony_ci if (key == name) { 2961cb0ef41Sopenharmony_ci callback(target); 2971cb0ef41Sopenharmony_ci } 2981cb0ef41Sopenharmony_ci return; 2991cb0ef41Sopenharmony_ci } 3001cb0ef41Sopenharmony_ci case kFullTransitionArray: { 3011cb0ef41Sopenharmony_ci base::SharedMutexGuardIf<base::kShared> scope( 3021cb0ef41Sopenharmony_ci isolate_->full_transition_array_access(), concurrent_access_); 3031cb0ef41Sopenharmony_ci return transitions().ForEachTransitionTo(name, callback); 3041cb0ef41Sopenharmony_ci } 3051cb0ef41Sopenharmony_ci } 3061cb0ef41Sopenharmony_ci UNREACHABLE(); 3071cb0ef41Sopenharmony_ci} 3081cb0ef41Sopenharmony_ci 3091cb0ef41Sopenharmony_ci// static 3101cb0ef41Sopenharmony_cibool TransitionsAccessor::CanHaveMoreTransitions(Isolate* isolate, 3111cb0ef41Sopenharmony_ci Handle<Map> map) { 3121cb0ef41Sopenharmony_ci if (map->is_dictionary_map()) return false; 3131cb0ef41Sopenharmony_ci MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad); 3141cb0ef41Sopenharmony_ci if (GetEncoding(isolate, raw_transitions) == kFullTransitionArray) { 3151cb0ef41Sopenharmony_ci return GetTransitionArray(isolate, raw_transitions) 3161cb0ef41Sopenharmony_ci .number_of_transitions() < kMaxNumberOfTransitions; 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci return true; 3191cb0ef41Sopenharmony_ci} 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ci// static 3221cb0ef41Sopenharmony_cibool TransitionsAccessor::IsMatchingMap(Map target, Name name, 3231cb0ef41Sopenharmony_ci PropertyKind kind, 3241cb0ef41Sopenharmony_ci PropertyAttributes attributes) { 3251cb0ef41Sopenharmony_ci InternalIndex descriptor = target.LastAdded(); 3261cb0ef41Sopenharmony_ci DescriptorArray descriptors = target.instance_descriptors(kRelaxedLoad); 3271cb0ef41Sopenharmony_ci Name key = descriptors.GetKey(descriptor); 3281cb0ef41Sopenharmony_ci if (key != name) return false; 3291cb0ef41Sopenharmony_ci return descriptors.GetDetails(descriptor) 3301cb0ef41Sopenharmony_ci .HasKindAndAttributes(kind, attributes); 3311cb0ef41Sopenharmony_ci} 3321cb0ef41Sopenharmony_ci 3331cb0ef41Sopenharmony_ci// static 3341cb0ef41Sopenharmony_cibool TransitionArray::CompactPrototypeTransitionArray(Isolate* isolate, 3351cb0ef41Sopenharmony_ci WeakFixedArray array) { 3361cb0ef41Sopenharmony_ci const int header = kProtoTransitionHeaderSize; 3371cb0ef41Sopenharmony_ci int number_of_transitions = NumberOfPrototypeTransitions(array); 3381cb0ef41Sopenharmony_ci if (number_of_transitions == 0) { 3391cb0ef41Sopenharmony_ci // Empty array cannot be compacted. 3401cb0ef41Sopenharmony_ci return false; 3411cb0ef41Sopenharmony_ci } 3421cb0ef41Sopenharmony_ci int new_number_of_transitions = 0; 3431cb0ef41Sopenharmony_ci for (int i = 0; i < number_of_transitions; i++) { 3441cb0ef41Sopenharmony_ci MaybeObject target = array.Get(header + i); 3451cb0ef41Sopenharmony_ci DCHECK(target->IsCleared() || 3461cb0ef41Sopenharmony_ci (target->IsWeak() && target->GetHeapObject().IsMap())); 3471cb0ef41Sopenharmony_ci if (!target->IsCleared()) { 3481cb0ef41Sopenharmony_ci if (new_number_of_transitions != i) { 3491cb0ef41Sopenharmony_ci array.Set(header + new_number_of_transitions, target); 3501cb0ef41Sopenharmony_ci } 3511cb0ef41Sopenharmony_ci new_number_of_transitions++; 3521cb0ef41Sopenharmony_ci } 3531cb0ef41Sopenharmony_ci } 3541cb0ef41Sopenharmony_ci // Fill slots that became free with undefined value. 3551cb0ef41Sopenharmony_ci MaybeObject undefined = 3561cb0ef41Sopenharmony_ci MaybeObject::FromObject(*isolate->factory()->undefined_value()); 3571cb0ef41Sopenharmony_ci for (int i = new_number_of_transitions; i < number_of_transitions; i++) { 3581cb0ef41Sopenharmony_ci array.Set(header + i, undefined); 3591cb0ef41Sopenharmony_ci } 3601cb0ef41Sopenharmony_ci if (number_of_transitions != new_number_of_transitions) { 3611cb0ef41Sopenharmony_ci SetNumberOfPrototypeTransitions(array, new_number_of_transitions); 3621cb0ef41Sopenharmony_ci } 3631cb0ef41Sopenharmony_ci return new_number_of_transitions < number_of_transitions; 3641cb0ef41Sopenharmony_ci} 3651cb0ef41Sopenharmony_ci 3661cb0ef41Sopenharmony_ci// static 3671cb0ef41Sopenharmony_ciHandle<WeakFixedArray> TransitionArray::GrowPrototypeTransitionArray( 3681cb0ef41Sopenharmony_ci Handle<WeakFixedArray> array, int new_capacity, Isolate* isolate) { 3691cb0ef41Sopenharmony_ci // Grow array by factor 2 up to MaxCachedPrototypeTransitions. 3701cb0ef41Sopenharmony_ci int capacity = array->length() - kProtoTransitionHeaderSize; 3711cb0ef41Sopenharmony_ci new_capacity = std::min({kMaxCachedPrototypeTransitions, new_capacity}); 3721cb0ef41Sopenharmony_ci DCHECK_GT(new_capacity, capacity); 3731cb0ef41Sopenharmony_ci int grow_by = new_capacity - capacity; 3741cb0ef41Sopenharmony_ci array = isolate->factory()->CopyWeakFixedArrayAndGrow(array, grow_by); 3751cb0ef41Sopenharmony_ci if (capacity < 0) { 3761cb0ef41Sopenharmony_ci // There was no prototype transitions array before, so the size 3771cb0ef41Sopenharmony_ci // couldn't be copied. Initialize it explicitly. 3781cb0ef41Sopenharmony_ci SetNumberOfPrototypeTransitions(*array, 0); 3791cb0ef41Sopenharmony_ci } 3801cb0ef41Sopenharmony_ci return array; 3811cb0ef41Sopenharmony_ci} 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_ci// static 3841cb0ef41Sopenharmony_civoid TransitionsAccessor::PutPrototypeTransition(Isolate* isolate, 3851cb0ef41Sopenharmony_ci Handle<Map> map, 3861cb0ef41Sopenharmony_ci Handle<Object> prototype, 3871cb0ef41Sopenharmony_ci Handle<Map> target_map) { 3881cb0ef41Sopenharmony_ci DCHECK(HeapObject::cast(*prototype).map().IsMap()); 3891cb0ef41Sopenharmony_ci // Don't cache prototype transition if this map is either shared, or a map of 3901cb0ef41Sopenharmony_ci // a prototype. 3911cb0ef41Sopenharmony_ci if (map->is_prototype_map()) return; 3921cb0ef41Sopenharmony_ci if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return; 3931cb0ef41Sopenharmony_ci 3941cb0ef41Sopenharmony_ci const int header = TransitionArray::kProtoTransitionHeaderSize; 3951cb0ef41Sopenharmony_ci 3961cb0ef41Sopenharmony_ci Handle<WeakFixedArray> cache(GetPrototypeTransitions(isolate, map), isolate); 3971cb0ef41Sopenharmony_ci int capacity = cache->length() - header; 3981cb0ef41Sopenharmony_ci int transitions = TransitionArray::NumberOfPrototypeTransitions(*cache) + 1; 3991cb0ef41Sopenharmony_ci 4001cb0ef41Sopenharmony_ci base::SharedMutexGuard<base::kExclusive> scope( 4011cb0ef41Sopenharmony_ci isolate->full_transition_array_access()); 4021cb0ef41Sopenharmony_ci 4031cb0ef41Sopenharmony_ci if (transitions > capacity) { 4041cb0ef41Sopenharmony_ci // Grow the array if compacting it doesn't free space. 4051cb0ef41Sopenharmony_ci if (!TransitionArray::CompactPrototypeTransitionArray(isolate, *cache)) { 4061cb0ef41Sopenharmony_ci if (capacity == TransitionArray::kMaxCachedPrototypeTransitions) return; 4071cb0ef41Sopenharmony_ci cache = TransitionArray::GrowPrototypeTransitionArray( 4081cb0ef41Sopenharmony_ci cache, 2 * transitions, isolate); 4091cb0ef41Sopenharmony_ci SetPrototypeTransitions(isolate, map, cache); 4101cb0ef41Sopenharmony_ci } 4111cb0ef41Sopenharmony_ci } 4121cb0ef41Sopenharmony_ci 4131cb0ef41Sopenharmony_ci // Reload number of transitions as they might have been compacted. 4141cb0ef41Sopenharmony_ci int last = TransitionArray::NumberOfPrototypeTransitions(*cache); 4151cb0ef41Sopenharmony_ci int entry = header + last; 4161cb0ef41Sopenharmony_ci 4171cb0ef41Sopenharmony_ci cache->Set(entry, HeapObjectReference::Weak(*target_map)); 4181cb0ef41Sopenharmony_ci TransitionArray::SetNumberOfPrototypeTransitions(*cache, last + 1); 4191cb0ef41Sopenharmony_ci} 4201cb0ef41Sopenharmony_ci 4211cb0ef41Sopenharmony_ci// static 4221cb0ef41Sopenharmony_ciHandle<Map> TransitionsAccessor::GetPrototypeTransition( 4231cb0ef41Sopenharmony_ci Isolate* isolate, Handle<Map> map, Handle<Object> prototype) { 4241cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 4251cb0ef41Sopenharmony_ci WeakFixedArray cache = GetPrototypeTransitions(isolate, map); 4261cb0ef41Sopenharmony_ci int length = TransitionArray::NumberOfPrototypeTransitions(cache); 4271cb0ef41Sopenharmony_ci for (int i = 0; i < length; i++) { 4281cb0ef41Sopenharmony_ci MaybeObject target = 4291cb0ef41Sopenharmony_ci cache.Get(TransitionArray::kProtoTransitionHeaderSize + i); 4301cb0ef41Sopenharmony_ci DCHECK(target->IsWeakOrCleared()); 4311cb0ef41Sopenharmony_ci HeapObject heap_object; 4321cb0ef41Sopenharmony_ci if (target->GetHeapObjectIfWeak(&heap_object)) { 4331cb0ef41Sopenharmony_ci Map target_map = Map::cast(heap_object); 4341cb0ef41Sopenharmony_ci if (target_map.prototype() == *prototype) { 4351cb0ef41Sopenharmony_ci return handle(target_map, isolate); 4361cb0ef41Sopenharmony_ci } 4371cb0ef41Sopenharmony_ci } 4381cb0ef41Sopenharmony_ci } 4391cb0ef41Sopenharmony_ci return Handle<Map>(); 4401cb0ef41Sopenharmony_ci} 4411cb0ef41Sopenharmony_ci 4421cb0ef41Sopenharmony_ci// static 4431cb0ef41Sopenharmony_ciWeakFixedArray TransitionsAccessor::GetPrototypeTransitions(Isolate* isolate, 4441cb0ef41Sopenharmony_ci Handle<Map> map) { 4451cb0ef41Sopenharmony_ci MaybeObject raw_transitions = map->raw_transitions(isolate, kAcquireLoad); 4461cb0ef41Sopenharmony_ci if (GetEncoding(isolate, raw_transitions) != kFullTransitionArray) { 4471cb0ef41Sopenharmony_ci return ReadOnlyRoots(isolate).empty_weak_fixed_array(); 4481cb0ef41Sopenharmony_ci } 4491cb0ef41Sopenharmony_ci TransitionArray transition_array = 4501cb0ef41Sopenharmony_ci GetTransitionArray(isolate, raw_transitions); 4511cb0ef41Sopenharmony_ci if (!transition_array.HasPrototypeTransitions()) { 4521cb0ef41Sopenharmony_ci return ReadOnlyRoots(isolate).empty_weak_fixed_array(); 4531cb0ef41Sopenharmony_ci } 4541cb0ef41Sopenharmony_ci return transition_array.GetPrototypeTransitions(); 4551cb0ef41Sopenharmony_ci} 4561cb0ef41Sopenharmony_ci 4571cb0ef41Sopenharmony_ci// static 4581cb0ef41Sopenharmony_civoid TransitionArray::SetNumberOfPrototypeTransitions( 4591cb0ef41Sopenharmony_ci WeakFixedArray proto_transitions, int value) { 4601cb0ef41Sopenharmony_ci DCHECK_NE(proto_transitions.length(), 0); 4611cb0ef41Sopenharmony_ci proto_transitions.Set(kProtoTransitionNumberOfEntriesOffset, 4621cb0ef41Sopenharmony_ci MaybeObject::FromSmi(Smi::FromInt(value))); 4631cb0ef41Sopenharmony_ci} 4641cb0ef41Sopenharmony_ci 4651cb0ef41Sopenharmony_ciint TransitionsAccessor::NumberOfTransitions() { 4661cb0ef41Sopenharmony_ci switch (encoding()) { 4671cb0ef41Sopenharmony_ci case kPrototypeInfo: 4681cb0ef41Sopenharmony_ci case kUninitialized: 4691cb0ef41Sopenharmony_ci case kMigrationTarget: 4701cb0ef41Sopenharmony_ci return 0; 4711cb0ef41Sopenharmony_ci case kWeakRef: 4721cb0ef41Sopenharmony_ci return 1; 4731cb0ef41Sopenharmony_ci case kFullTransitionArray: 4741cb0ef41Sopenharmony_ci return transitions().number_of_transitions(); 4751cb0ef41Sopenharmony_ci } 4761cb0ef41Sopenharmony_ci UNREACHABLE(); 4771cb0ef41Sopenharmony_ci} 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ci// static 4801cb0ef41Sopenharmony_civoid TransitionsAccessor::SetMigrationTarget(Isolate* isolate, Handle<Map> map, 4811cb0ef41Sopenharmony_ci Map migration_target) { 4821cb0ef41Sopenharmony_ci // We only cache the migration target for maps with empty transitions for GC's 4831cb0ef41Sopenharmony_ci // sake. 4841cb0ef41Sopenharmony_ci if (GetEncoding(isolate, map) != kUninitialized) return; 4851cb0ef41Sopenharmony_ci DCHECK(map->is_deprecated()); 4861cb0ef41Sopenharmony_ci map->set_raw_transitions(MaybeObject::FromObject(migration_target), 4871cb0ef41Sopenharmony_ci kReleaseStore); 4881cb0ef41Sopenharmony_ci} 4891cb0ef41Sopenharmony_ci 4901cb0ef41Sopenharmony_ciMap TransitionsAccessor::GetMigrationTarget() { 4911cb0ef41Sopenharmony_ci if (encoding() == kMigrationTarget) { 4921cb0ef41Sopenharmony_ci return map_.raw_transitions(kAcquireLoad)->cast<Map>(); 4931cb0ef41Sopenharmony_ci } 4941cb0ef41Sopenharmony_ci return Map(); 4951cb0ef41Sopenharmony_ci} 4961cb0ef41Sopenharmony_ci 4971cb0ef41Sopenharmony_ci// static 4981cb0ef41Sopenharmony_civoid TransitionsAccessor::ReplaceTransitions(Isolate* isolate, Handle<Map> map, 4991cb0ef41Sopenharmony_ci MaybeObject new_transitions) { 5001cb0ef41Sopenharmony_ci#if DEBUG 5011cb0ef41Sopenharmony_ci if (GetEncoding(isolate, map) == kFullTransitionArray) { 5021cb0ef41Sopenharmony_ci CheckNewTransitionsAreConsistent( 5031cb0ef41Sopenharmony_ci isolate, map, new_transitions->GetHeapObjectAssumeStrong()); 5041cb0ef41Sopenharmony_ci DCHECK_NE(GetTransitionArray(isolate, map), 5051cb0ef41Sopenharmony_ci new_transitions->GetHeapObjectAssumeStrong()); 5061cb0ef41Sopenharmony_ci } 5071cb0ef41Sopenharmony_ci#endif 5081cb0ef41Sopenharmony_ci map->set_raw_transitions(new_transitions, kReleaseStore); 5091cb0ef41Sopenharmony_ci USE(isolate); 5101cb0ef41Sopenharmony_ci} 5111cb0ef41Sopenharmony_ci 5121cb0ef41Sopenharmony_ci// static 5131cb0ef41Sopenharmony_civoid TransitionsAccessor::ReplaceTransitions( 5141cb0ef41Sopenharmony_ci Isolate* isolate, Handle<Map> map, 5151cb0ef41Sopenharmony_ci Handle<TransitionArray> new_transitions) { 5161cb0ef41Sopenharmony_ci ReplaceTransitions(isolate, map, MaybeObject::FromObject(*new_transitions)); 5171cb0ef41Sopenharmony_ci} 5181cb0ef41Sopenharmony_ci 5191cb0ef41Sopenharmony_ci// static 5201cb0ef41Sopenharmony_civoid TransitionsAccessor::SetPrototypeTransitions( 5211cb0ef41Sopenharmony_ci Isolate* isolate, Handle<Map> map, 5221cb0ef41Sopenharmony_ci Handle<WeakFixedArray> proto_transitions) { 5231cb0ef41Sopenharmony_ci EnsureHasFullTransitionArray(isolate, map); 5241cb0ef41Sopenharmony_ci GetTransitionArray(isolate, map->raw_transitions(isolate, kAcquireLoad)) 5251cb0ef41Sopenharmony_ci .SetPrototypeTransitions(*proto_transitions); 5261cb0ef41Sopenharmony_ci} 5271cb0ef41Sopenharmony_ci 5281cb0ef41Sopenharmony_ci// static 5291cb0ef41Sopenharmony_civoid TransitionsAccessor::EnsureHasFullTransitionArray(Isolate* isolate, 5301cb0ef41Sopenharmony_ci Handle<Map> map) { 5311cb0ef41Sopenharmony_ci Encoding encoding = 5321cb0ef41Sopenharmony_ci GetEncoding(isolate, map->raw_transitions(isolate, kAcquireLoad)); 5331cb0ef41Sopenharmony_ci if (encoding == kFullTransitionArray) return; 5341cb0ef41Sopenharmony_ci int nof = 5351cb0ef41Sopenharmony_ci (encoding == kUninitialized || encoding == kMigrationTarget) ? 0 : 1; 5361cb0ef41Sopenharmony_ci Handle<TransitionArray> result = isolate->factory()->NewTransitionArray(nof); 5371cb0ef41Sopenharmony_ci // Reload encoding after possible GC. 5381cb0ef41Sopenharmony_ci encoding = GetEncoding(isolate, map->raw_transitions(isolate, kAcquireLoad)); 5391cb0ef41Sopenharmony_ci if (nof == 1) { 5401cb0ef41Sopenharmony_ci if (encoding == kUninitialized) { 5411cb0ef41Sopenharmony_ci // If allocation caused GC and cleared the target, trim the new array. 5421cb0ef41Sopenharmony_ci result->SetNumberOfTransitions(0); 5431cb0ef41Sopenharmony_ci } else { 5441cb0ef41Sopenharmony_ci // Otherwise populate the new array. 5451cb0ef41Sopenharmony_ci Map target = GetSimpleTransition(isolate, map); 5461cb0ef41Sopenharmony_ci Name key = GetSimpleTransitionKey(target); 5471cb0ef41Sopenharmony_ci result->Set(0, key, HeapObjectReference::Weak(target)); 5481cb0ef41Sopenharmony_ci } 5491cb0ef41Sopenharmony_ci } 5501cb0ef41Sopenharmony_ci ReplaceTransitions(isolate, map, result); 5511cb0ef41Sopenharmony_ci} 5521cb0ef41Sopenharmony_ci 5531cb0ef41Sopenharmony_civoid TransitionsAccessor::TraverseTransitionTreeInternal( 5541cb0ef41Sopenharmony_ci const TraverseCallback& callback, DisallowGarbageCollection* no_gc) { 5551cb0ef41Sopenharmony_ci // Mostly arbitrary but more than enough to run the test suite in static 5561cb0ef41Sopenharmony_ci // memory. 5571cb0ef41Sopenharmony_ci static constexpr int kStaticStackSize = 16; 5581cb0ef41Sopenharmony_ci base::SmallVector<Map, kStaticStackSize> stack; 5591cb0ef41Sopenharmony_ci stack.emplace_back(map_); 5601cb0ef41Sopenharmony_ci 5611cb0ef41Sopenharmony_ci // Pre-order iterative depth-first-search. 5621cb0ef41Sopenharmony_ci while (!stack.empty()) { 5631cb0ef41Sopenharmony_ci Map current_map = stack.back(); 5641cb0ef41Sopenharmony_ci stack.pop_back(); 5651cb0ef41Sopenharmony_ci 5661cb0ef41Sopenharmony_ci callback(current_map); 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_ci MaybeObject raw_transitions = 5691cb0ef41Sopenharmony_ci current_map.raw_transitions(isolate_, kAcquireLoad); 5701cb0ef41Sopenharmony_ci Encoding encoding = GetEncoding(isolate_, raw_transitions); 5711cb0ef41Sopenharmony_ci 5721cb0ef41Sopenharmony_ci switch (encoding) { 5731cb0ef41Sopenharmony_ci case kPrototypeInfo: 5741cb0ef41Sopenharmony_ci case kUninitialized: 5751cb0ef41Sopenharmony_ci case kMigrationTarget: 5761cb0ef41Sopenharmony_ci break; 5771cb0ef41Sopenharmony_ci case kWeakRef: { 5781cb0ef41Sopenharmony_ci stack.emplace_back( 5791cb0ef41Sopenharmony_ci Map::cast(raw_transitions->GetHeapObjectAssumeWeak())); 5801cb0ef41Sopenharmony_ci break; 5811cb0ef41Sopenharmony_ci } 5821cb0ef41Sopenharmony_ci case kFullTransitionArray: { 5831cb0ef41Sopenharmony_ci TransitionArray transitions = 5841cb0ef41Sopenharmony_ci TransitionArray::cast(raw_transitions->GetHeapObjectAssumeStrong()); 5851cb0ef41Sopenharmony_ci if (transitions.HasPrototypeTransitions()) { 5861cb0ef41Sopenharmony_ci WeakFixedArray proto_trans = transitions.GetPrototypeTransitions(); 5871cb0ef41Sopenharmony_ci int length = 5881cb0ef41Sopenharmony_ci TransitionArray::NumberOfPrototypeTransitions(proto_trans); 5891cb0ef41Sopenharmony_ci for (int i = 0; i < length; ++i) { 5901cb0ef41Sopenharmony_ci int index = TransitionArray::kProtoTransitionHeaderSize + i; 5911cb0ef41Sopenharmony_ci MaybeObject target = proto_trans.Get(index); 5921cb0ef41Sopenharmony_ci HeapObject heap_object; 5931cb0ef41Sopenharmony_ci if (target->GetHeapObjectIfWeak(&heap_object)) { 5941cb0ef41Sopenharmony_ci stack.emplace_back(Map::cast(heap_object)); 5951cb0ef41Sopenharmony_ci } else { 5961cb0ef41Sopenharmony_ci DCHECK(target->IsCleared()); 5971cb0ef41Sopenharmony_ci } 5981cb0ef41Sopenharmony_ci } 5991cb0ef41Sopenharmony_ci } 6001cb0ef41Sopenharmony_ci for (int i = 0; i < transitions.number_of_transitions(); ++i) { 6011cb0ef41Sopenharmony_ci stack.emplace_back(transitions.GetTarget(i)); 6021cb0ef41Sopenharmony_ci } 6031cb0ef41Sopenharmony_ci break; 6041cb0ef41Sopenharmony_ci } 6051cb0ef41Sopenharmony_ci } 6061cb0ef41Sopenharmony_ci } 6071cb0ef41Sopenharmony_ci} 6081cb0ef41Sopenharmony_ci 6091cb0ef41Sopenharmony_ci#ifdef DEBUG 6101cb0ef41Sopenharmony_ci// static 6111cb0ef41Sopenharmony_civoid TransitionsAccessor::CheckNewTransitionsAreConsistent(Isolate* isolate, 6121cb0ef41Sopenharmony_ci Handle<Map> map, 6131cb0ef41Sopenharmony_ci Object transitions) { 6141cb0ef41Sopenharmony_ci // This function only handles full transition arrays. 6151cb0ef41Sopenharmony_ci TransitionArray old_transitions = GetTransitionArray(isolate, map); 6161cb0ef41Sopenharmony_ci DCHECK_EQ(kFullTransitionArray, GetEncoding(isolate, old_transitions)); 6171cb0ef41Sopenharmony_ci TransitionArray new_transitions = TransitionArray::cast(transitions); 6181cb0ef41Sopenharmony_ci for (int i = 0; i < old_transitions.number_of_transitions(); i++) { 6191cb0ef41Sopenharmony_ci Map target = old_transitions.GetTarget(i); 6201cb0ef41Sopenharmony_ci if (target.instance_descriptors(isolate) == 6211cb0ef41Sopenharmony_ci map->instance_descriptors(isolate)) { 6221cb0ef41Sopenharmony_ci Name key = old_transitions.GetKey(i); 6231cb0ef41Sopenharmony_ci int new_target_index; 6241cb0ef41Sopenharmony_ci if (IsSpecialTransition(ReadOnlyRoots(isolate), key)) { 6251cb0ef41Sopenharmony_ci new_target_index = new_transitions.SearchSpecial(Symbol::cast(key)); 6261cb0ef41Sopenharmony_ci } else { 6271cb0ef41Sopenharmony_ci PropertyDetails details = GetTargetDetails(key, target); 6281cb0ef41Sopenharmony_ci new_target_index = 6291cb0ef41Sopenharmony_ci new_transitions.Search(details.kind(), key, details.attributes()); 6301cb0ef41Sopenharmony_ci } 6311cb0ef41Sopenharmony_ci DCHECK_NE(TransitionArray::kNotFound, new_target_index); 6321cb0ef41Sopenharmony_ci DCHECK_EQ(target, new_transitions.GetTarget(new_target_index)); 6331cb0ef41Sopenharmony_ci } 6341cb0ef41Sopenharmony_ci } 6351cb0ef41Sopenharmony_ci} 6361cb0ef41Sopenharmony_ci#endif 6371cb0ef41Sopenharmony_ci 6381cb0ef41Sopenharmony_ci// Private non-static helper functions (operating on full transition arrays). 6391cb0ef41Sopenharmony_ci 6401cb0ef41Sopenharmony_ciint TransitionArray::SearchDetails(int transition, PropertyKind kind, 6411cb0ef41Sopenharmony_ci PropertyAttributes attributes, 6421cb0ef41Sopenharmony_ci int* out_insertion_index) { 6431cb0ef41Sopenharmony_ci int nof_transitions = number_of_transitions(); 6441cb0ef41Sopenharmony_ci DCHECK(transition < nof_transitions); 6451cb0ef41Sopenharmony_ci Name key = GetKey(transition); 6461cb0ef41Sopenharmony_ci for (; transition < nof_transitions && GetKey(transition) == key; 6471cb0ef41Sopenharmony_ci transition++) { 6481cb0ef41Sopenharmony_ci Map target = GetTarget(transition); 6491cb0ef41Sopenharmony_ci PropertyDetails target_details = 6501cb0ef41Sopenharmony_ci TransitionsAccessor::GetTargetDetails(key, target); 6511cb0ef41Sopenharmony_ci 6521cb0ef41Sopenharmony_ci int cmp = CompareDetails(kind, attributes, target_details.kind(), 6531cb0ef41Sopenharmony_ci target_details.attributes()); 6541cb0ef41Sopenharmony_ci if (cmp == 0) { 6551cb0ef41Sopenharmony_ci return transition; 6561cb0ef41Sopenharmony_ci } else if (cmp < 0) { 6571cb0ef41Sopenharmony_ci break; 6581cb0ef41Sopenharmony_ci } 6591cb0ef41Sopenharmony_ci } 6601cb0ef41Sopenharmony_ci if (out_insertion_index != nullptr) *out_insertion_index = transition; 6611cb0ef41Sopenharmony_ci return kNotFound; 6621cb0ef41Sopenharmony_ci} 6631cb0ef41Sopenharmony_ci 6641cb0ef41Sopenharmony_ciMap TransitionArray::SearchDetailsAndGetTarget(int transition, 6651cb0ef41Sopenharmony_ci PropertyKind kind, 6661cb0ef41Sopenharmony_ci PropertyAttributes attributes) { 6671cb0ef41Sopenharmony_ci int nof_transitions = number_of_transitions(); 6681cb0ef41Sopenharmony_ci DCHECK(transition < nof_transitions); 6691cb0ef41Sopenharmony_ci Name key = GetKey(transition); 6701cb0ef41Sopenharmony_ci for (; transition < nof_transitions && GetKey(transition) == key; 6711cb0ef41Sopenharmony_ci transition++) { 6721cb0ef41Sopenharmony_ci Map target = GetTarget(transition); 6731cb0ef41Sopenharmony_ci PropertyDetails target_details = 6741cb0ef41Sopenharmony_ci TransitionsAccessor::GetTargetDetails(key, target); 6751cb0ef41Sopenharmony_ci 6761cb0ef41Sopenharmony_ci int cmp = CompareDetails(kind, attributes, target_details.kind(), 6771cb0ef41Sopenharmony_ci target_details.attributes()); 6781cb0ef41Sopenharmony_ci if (cmp == 0) { 6791cb0ef41Sopenharmony_ci return target; 6801cb0ef41Sopenharmony_ci } else if (cmp < 0) { 6811cb0ef41Sopenharmony_ci break; 6821cb0ef41Sopenharmony_ci } 6831cb0ef41Sopenharmony_ci } 6841cb0ef41Sopenharmony_ci return Map(); 6851cb0ef41Sopenharmony_ci} 6861cb0ef41Sopenharmony_ci 6871cb0ef41Sopenharmony_ciint TransitionArray::Search(PropertyKind kind, Name name, 6881cb0ef41Sopenharmony_ci PropertyAttributes attributes, 6891cb0ef41Sopenharmony_ci int* out_insertion_index) { 6901cb0ef41Sopenharmony_ci int transition = SearchName(name, false, out_insertion_index); 6911cb0ef41Sopenharmony_ci if (transition == kNotFound) return kNotFound; 6921cb0ef41Sopenharmony_ci return SearchDetails(transition, kind, attributes, out_insertion_index); 6931cb0ef41Sopenharmony_ci} 6941cb0ef41Sopenharmony_ci 6951cb0ef41Sopenharmony_ciMap TransitionArray::SearchAndGetTarget(PropertyKind kind, Name name, 6961cb0ef41Sopenharmony_ci PropertyAttributes attributes) { 6971cb0ef41Sopenharmony_ci int transition = SearchName(name); 6981cb0ef41Sopenharmony_ci if (transition == kNotFound) { 6991cb0ef41Sopenharmony_ci return Map(); 7001cb0ef41Sopenharmony_ci } 7011cb0ef41Sopenharmony_ci return SearchDetailsAndGetTarget(transition, kind, attributes); 7021cb0ef41Sopenharmony_ci} 7031cb0ef41Sopenharmony_ci 7041cb0ef41Sopenharmony_civoid TransitionArray::ForEachTransitionTo( 7051cb0ef41Sopenharmony_ci Name name, const ForEachTransitionCallback& callback) { 7061cb0ef41Sopenharmony_ci int transition = SearchName(name); 7071cb0ef41Sopenharmony_ci if (transition == kNotFound) return; 7081cb0ef41Sopenharmony_ci 7091cb0ef41Sopenharmony_ci int nof_transitions = number_of_transitions(); 7101cb0ef41Sopenharmony_ci DCHECK(transition < nof_transitions); 7111cb0ef41Sopenharmony_ci Name key = GetKey(transition); 7121cb0ef41Sopenharmony_ci for (; transition < nof_transitions && GetKey(transition) == key; 7131cb0ef41Sopenharmony_ci transition++) { 7141cb0ef41Sopenharmony_ci Map target = GetTarget(transition); 7151cb0ef41Sopenharmony_ci callback(target); 7161cb0ef41Sopenharmony_ci } 7171cb0ef41Sopenharmony_ci} 7181cb0ef41Sopenharmony_ci 7191cb0ef41Sopenharmony_civoid TransitionArray::Sort() { 7201cb0ef41Sopenharmony_ci DisallowGarbageCollection no_gc; 7211cb0ef41Sopenharmony_ci // In-place insertion sort. 7221cb0ef41Sopenharmony_ci int length = number_of_transitions(); 7231cb0ef41Sopenharmony_ci ReadOnlyRoots roots = GetReadOnlyRoots(); 7241cb0ef41Sopenharmony_ci for (int i = 1; i < length; i++) { 7251cb0ef41Sopenharmony_ci Name key = GetKey(i); 7261cb0ef41Sopenharmony_ci MaybeObject target = GetRawTarget(i); 7271cb0ef41Sopenharmony_ci PropertyKind kind = PropertyKind::kData; 7281cb0ef41Sopenharmony_ci PropertyAttributes attributes = NONE; 7291cb0ef41Sopenharmony_ci if (!TransitionsAccessor::IsSpecialTransition(roots, key)) { 7301cb0ef41Sopenharmony_ci Map target_map = TransitionsAccessor::GetTargetFromRaw(target); 7311cb0ef41Sopenharmony_ci PropertyDetails details = 7321cb0ef41Sopenharmony_ci TransitionsAccessor::GetTargetDetails(key, target_map); 7331cb0ef41Sopenharmony_ci kind = details.kind(); 7341cb0ef41Sopenharmony_ci attributes = details.attributes(); 7351cb0ef41Sopenharmony_ci } 7361cb0ef41Sopenharmony_ci int j; 7371cb0ef41Sopenharmony_ci for (j = i - 1; j >= 0; j--) { 7381cb0ef41Sopenharmony_ci Name temp_key = GetKey(j); 7391cb0ef41Sopenharmony_ci MaybeObject temp_target = GetRawTarget(j); 7401cb0ef41Sopenharmony_ci PropertyKind temp_kind = PropertyKind::kData; 7411cb0ef41Sopenharmony_ci PropertyAttributes temp_attributes = NONE; 7421cb0ef41Sopenharmony_ci if (!TransitionsAccessor::IsSpecialTransition(roots, temp_key)) { 7431cb0ef41Sopenharmony_ci Map temp_target_map = 7441cb0ef41Sopenharmony_ci TransitionsAccessor::GetTargetFromRaw(temp_target); 7451cb0ef41Sopenharmony_ci PropertyDetails details = 7461cb0ef41Sopenharmony_ci TransitionsAccessor::GetTargetDetails(temp_key, temp_target_map); 7471cb0ef41Sopenharmony_ci temp_kind = details.kind(); 7481cb0ef41Sopenharmony_ci temp_attributes = details.attributes(); 7491cb0ef41Sopenharmony_ci } 7501cb0ef41Sopenharmony_ci int cmp = CompareKeys(temp_key, temp_key.hash(), temp_kind, 7511cb0ef41Sopenharmony_ci temp_attributes, key, key.hash(), kind, attributes); 7521cb0ef41Sopenharmony_ci if (cmp > 0) { 7531cb0ef41Sopenharmony_ci SetKey(j + 1, temp_key); 7541cb0ef41Sopenharmony_ci SetRawTarget(j + 1, temp_target); 7551cb0ef41Sopenharmony_ci } else { 7561cb0ef41Sopenharmony_ci break; 7571cb0ef41Sopenharmony_ci } 7581cb0ef41Sopenharmony_ci } 7591cb0ef41Sopenharmony_ci SetKey(j + 1, key); 7601cb0ef41Sopenharmony_ci SetRawTarget(j + 1, target); 7611cb0ef41Sopenharmony_ci } 7621cb0ef41Sopenharmony_ci DCHECK(IsSortedNoDuplicates()); 7631cb0ef41Sopenharmony_ci} 7641cb0ef41Sopenharmony_ci 7651cb0ef41Sopenharmony_cibool TransitionsAccessor::HasIntegrityLevelTransitionTo( 7661cb0ef41Sopenharmony_ci Map to, Symbol* out_symbol, PropertyAttributes* out_integrity_level) { 7671cb0ef41Sopenharmony_ci ReadOnlyRoots roots(isolate_); 7681cb0ef41Sopenharmony_ci if (SearchSpecial(roots.frozen_symbol()) == to) { 7691cb0ef41Sopenharmony_ci if (out_integrity_level) *out_integrity_level = FROZEN; 7701cb0ef41Sopenharmony_ci if (out_symbol) *out_symbol = roots.frozen_symbol(); 7711cb0ef41Sopenharmony_ci } else if (SearchSpecial(roots.sealed_symbol()) == to) { 7721cb0ef41Sopenharmony_ci if (out_integrity_level) *out_integrity_level = SEALED; 7731cb0ef41Sopenharmony_ci if (out_symbol) *out_symbol = roots.sealed_symbol(); 7741cb0ef41Sopenharmony_ci } else if (SearchSpecial(roots.nonextensible_symbol()) == to) { 7751cb0ef41Sopenharmony_ci if (out_integrity_level) *out_integrity_level = NONE; 7761cb0ef41Sopenharmony_ci if (out_symbol) *out_symbol = roots.nonextensible_symbol(); 7771cb0ef41Sopenharmony_ci } else { 7781cb0ef41Sopenharmony_ci return false; 7791cb0ef41Sopenharmony_ci } 7801cb0ef41Sopenharmony_ci return true; 7811cb0ef41Sopenharmony_ci} 7821cb0ef41Sopenharmony_ci 7831cb0ef41Sopenharmony_ci} // namespace internal 7841cb0ef41Sopenharmony_ci} // namespace v8 785