text: // Copyright 2018 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef V8_OBJECTS_DESCRIPTOR_ARRAY_INL_H_
  #define V8_OBJECTS_DESCRIPTOR_ARRAY_INL_H_
  
  #include "src/objects/descriptor-array.h"
  
  #include "src/execution/isolate.h"
  #include "src/handles/maybe-handles-inl.h"
  #include "src/heap/heap-write-barrier.h"
  #include "src/heap/heap.h"
  #include "src/objects/field-type.h"
  #include "src/objects/heap-object-inl.h"
  #include "src/objects/lookup-cache-inl.h"
  #include "src/objects/maybe-object-inl.h"
  #include "src/objects/property.h"
  #include "src/objects/struct-inl.h"
  
  // Has to be the last include (doesn't have include guards):
  #include "src/objects/object-macros.h"
  
  namespace v8 {
  namespace internal {
  
  TQ_OBJECT_CONSTRUCTORS_IMPL(DescriptorArray)
  TQ_OBJECT_CONSTRUCTORS_IMPL(EnumCache)
  
  RELAXED_INT16_ACCESSORS(DescriptorArray, number_of_all_descriptors,
                          kNumberOfAllDescriptorsOffset)
  RELAXED_INT16_ACCESSORS(DescriptorArray, number_of_descriptors,
                          kNumberOfDescriptorsOffset)
  RELAXED_INT16_ACCESSORS(DescriptorArray, raw_number_of_marked_descriptors,
                          kRawNumberOfMarkedDescriptorsOffset)
  RELAXED_INT16_ACCESSORS(DescriptorArray, filler16bits, kFiller16BitsOffset)
  
  inline int16_t DescriptorArray::number_of_slack_descriptors() const {
    return number_of_all_descriptors() - number_of_descriptors();
  }
  
  inline int DescriptorArray::number_of_entries() const {
    return number_of_descriptors();
  }
  
  inline int16_t DescriptorArray::CompareAndSwapRawNumberOfMarkedDescriptors(
      int16_t expected, int16_t value) {
    return base::Relaxed_CompareAndSwap(
        reinterpret_cast<base::Atomic16*>(
            FIELD_ADDR(*this, kRawNumberOfMarkedDescriptorsOffset)),
        expected, value);
  }
  
  void DescriptorArray::CopyEnumCacheFrom(DescriptorArray array) {
    set_enum_cache(array.enum_cache());
  }
  
  InternalIndex DescriptorArray::Search(Name name, int valid_descriptors) {
    DCHECK(name.IsUniqueName());
    return InternalIndex(
        internal::Search<VALID_ENTRIES>(this, name, valid_descriptors, nullptr));
  }
  
  InternalIndex DescriptorArray::Search(Name name, Map map) {
    DCHECK(name.IsUniqueName());
    int number_of_own_descriptors = map.NumberOfOwnDescriptors();
    if (number_of_own_descriptors == 0) return InternalIndex::NotFound();
    return Search(name, number_of_own_descriptors);
  }
  
  InternalIndex DescriptorArray::SearchWithCache(Isolate* isolate, Name name,
                                                 Map map) {
    DCHECK(name.IsUniqueName());
    int number_of_own_descriptors = map.NumberOfOwnDescriptors();
    if (number_of_own_descriptors == 0) return InternalIndex::NotFound();
  
    DescriptorLookupCache* cache = isolate->descriptor_lookup_cache();
    int number = cache->Lookup(map, name);
  
    if (number == DescriptorLookupCache::kAbsent) {
      InternalIndex result = Search(name, number_of_own_descriptors);
      number = result.is_found() ? result.as_int() : DescriptorArray::kNotFound;
      cache->Update(map, name, number);
    }
    if (number == DescriptorArray::kNotFound) return InternalIndex::NotFound();
    return InternalIndex(number);
  }
  
  ObjectSlot DescriptorArray::GetFirstPointerSlot() {
    static_assert(kEndOfStrongFieldsOffset == kStartOfWeakFieldsOffset,
                  "Weak and strong fields are continuous.");
    static_assert(kEndOfWeakFieldsOffset == kHeaderSize,
                  "Weak fields extend up to the end of the header.");
    return RawField(DescriptorArray::kStartOfStrongFieldsOffset);
  }
  
  ObjectSlot DescriptorArray::GetDescriptorSlot(int descriptor) {
    // Allow descriptor == number_of_all_descriptors() for computing the slot
    // address that comes after the last descriptor (for iterating).
    DCHECK_LE(descriptor, number_of_all_descriptors());
    return RawField(OffsetOfDescriptorAt(descriptor));
  }
  
  Name DescriptorArray::GetKey(InternalIndex descriptor_number) const {
    const Isolate* isolate = GetIsolateForPtrCompr(*this);
    return GetKey(isolate, descriptor_number);
  }
  
  Name DescriptorArray::GetKey(const Isolate* isolate,
                               InternalIndex descriptor_number) const {
    DCHECK_LT(descriptor_number.as_int(), number_of_descriptors());
    int entry_offset = OffsetOfDescriptorAt(descriptor_number.as_int());
    return Name::cast(EntryKeyField::Relaxed_Load(isolate, *this, entry_offset));
  }
  
  void DescriptorArray::SetKey(InternalIndex descriptor_number, Name key) {
    DCHECK_LT(descriptor_number.as_int(), number_of_descriptors());
    int entry_offset = OffsetOfDescriptorAt(descriptor_number.as_int());
    EntryKeyField::Relaxed_Store(*this, entry_offset, key);
    WRITE_BARRIER(*this, entry_offset + kEntryKeyOffset, key);
  }
  
  int DescriptorArray::GetSortedKeyIndex(int descriptor_number) {
    return GetDetails(InternalIndex(descriptor_number)).pointer();
  }
  
  Name DescriptorArray::GetSortedKey(int descriptor_number) {
    const Isolate* isolate = GetIsolateForPtrCompr(*this);
    return GetSortedKey(isolate, descriptor_number);
  }
  
  Name DescriptorArray::GetSortedKey(const Isolate* isolate,
                                     int descriptor_number) {
    return GetKey(isolate, InternalIndex(GetSortedKeyIndex(descriptor_number)));
  }
  
  void DescriptorArray::SetSortedKey(int descriptor_number, int pointer) {
    PropertyDetails details = GetDetails(InternalIndex(descriptor_number));
    SetDetails(InternalIndex(descriptor_number), details.set_pointer(pointer));
  }
  
  Object DescriptorArray::GetStrongValue(InternalIndex descriptor_number) {
    const Isolate* isolate = GetIsolateForPtrCompr(*this);
    return GetStrongValue(isolate, descriptor_number);
  }
  
  Object DescriptorArray::GetStrongValue(const Isolate* isolate,
                                         InternalIndex descriptor_number) {
    return GetValue(isolate, descriptor_number).cast<Object>();
  }
  
  void DescriptorArray::SetValue(InternalIndex descriptor_number,
                                 MaybeObject value) {
    DCHECK_LT(descriptor_number.as_int(), number_of_descriptors());
    int entry_offset = OffsetOfDescriptorAt(descriptor_number.as_int());
    EntryValueField::Relaxed_Store(*this, entry_offset, value);
    WEAK_WRITE_BARRIER(*this, entry_offset + kEntryValueOffset, value);
  }
  
  MaybeObject DescriptorArray::GetValue(InternalIndex descriptor_number) {
    const Isolate* isolate = GetIsolateForPtrCompr(*this);
    return GetValue(isolate, descriptor_number);
  }
  
  MaybeObject DescriptorArray::GetValue(const Isolate* isolate,
                                        InternalIndex descriptor_number) {
    DCHECK_LT(descriptor_number.as_int(), number_of_descriptors());
    int entry_offset = OffsetOfDescriptorAt(descriptor_number.as_int());
    return EntryValueField::Relaxed_Load(isolate, *this, entry_offset);
  }
  
  PropertyDetails DescriptorArray::GetDetails(InternalIndex descriptor_number) {
    DCHECK_LT(descriptor_number.as_int(), number_of_descriptors());
    int entry_offset = OffsetOfDescriptorAt(descriptor_number.as_int());
    Smi details = EntryDetailsField::Relaxed_Load(*this, entry_offset);
    return PropertyDetails(details);
  }
  
  void DescriptorArray::SetDetails(InternalIndex descriptor_number,
                                   PropertyDetails details) {
    DCHECK_LT(descriptor_number.as_int(), number_of_descriptors());
    int entry_offset = OffsetOfDescriptorAt(descriptor_number.as_int());
    EntryDetailsField::Relaxed_Store(*this, entry_offset, details.AsSmi());
  }
  
  int DescriptorArray::GetFieldIndex(InternalIndex descriptor_number) {
    DCHECK_EQ(GetDetails(descriptor_number).location(), kField);
    return GetDetails(descriptor_number).field_index();
  }
  
  FieldType DescriptorArray::GetFieldType(InternalIndex descriptor_number) {
    const Isolate* isolate = GetIsolateForPtrCompr(*this);
    return GetFieldType(isolate, descriptor_number);
  }
  
  FieldType DescriptorArray::GetFieldType(const Isolate* isolate,
                                          InternalIndex descriptor_number) {
    DCHECK_EQ(GetDetails(descriptor_number).location(), kField);
    MaybeObject wrapped_type = GetValue(isolate, descriptor_number);
    return Map::UnwrapFieldType(wrapped_type);
  }
  
  void DescriptorArray::Set(InternalIndex descriptor_number, Name key,
                            MaybeObject value, PropertyDetails details) {
    SetKey(descriptor_number, key);
    SetDetails(descriptor_number, details);
    SetValue(descriptor_number, value);
  }
  
  void DescriptorArray::Set(InternalIndex descriptor_number, Descriptor* desc) {
    Name key = *desc->GetKey();
    MaybeObject value = *desc->GetValue();
    Set(descriptor_number, key, value, desc->GetDetails());
  }
  
  void DescriptorArray::Append(Descriptor* desc) {
    DisallowHeapAllocation no_gc;
    int descriptor_number = number_of_descriptors();
    DCHECK_LE(descriptor_number + 1, number_of_all_descriptors());
    set_number_of_descriptors(descriptor_number + 1);
    Set(InternalIndex(descriptor_number), desc);
  
    uint32_t hash = desc->GetKey()->Hash();
  
    int insertion;
  
    for (insertion = descriptor_number; insertion > 0; --insertion) {
      Name key = GetSortedKey(insertion - 1);
      if (key.Hash() <= hash) break;
      SetSortedKey(insertion, GetSortedKeyIndex(insertion - 1));
    }
  
    SetSortedKey(insertion, descriptor_number);
  }
  
  void DescriptorArray::SwapSortedKeys(int first, int second) {
    int first_key = GetSortedKeyIndex(first);
    SetSortedKey(first, GetSortedKeyIndex(second));
    SetSortedKey(second, first_key);
  }
  
  }  // namespace internal
  }  // namespace v8
  
  #include "src/objects/object-macros-undef.h"
  
  #endif  // V8_OBJECTS_DESCRIPTOR_ARRAY_INL_H_
  