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