text: // Copyright 2017 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_H_
  #define V8_OBJECTS_DESCRIPTOR_ARRAY_H_
  
  #include "src/objects.h"
  
  // Has to be the last include (doesn't have include guards):
  #include "src/objects/object-macros.h"
  
  namespace v8 {
  namespace internal {
  
  template <typename T>
  class Handle;
  
  class Isolate;
  
  // A DescriptorArray is a fixed array used to hold instance descriptors.
  // The format of the these objects is:
  //   [0]: Number of descriptors
  //   [1]: Either Smi(0) if uninitialized,
  //        or enum cache bridge (FixedArray[2]):
  //          [0]: enum cache: FixedArray containing all own enumerable keys
  //          [1]: either Smi(0) or pointer to fixed array with indices
  //   [2]: first key (and internalized String)
  //   [3]: first descriptor details (see PropertyDetails)
  //   [4]: first value for constants | Smi(1) when not usedA
  //
  //   [2 + number of descriptors * 3]: start of slack
  class DescriptorArray : public FixedArray {
   public:
    // Returns true for both shared empty_descriptor_array and for smis, which the
    // map uses to encode additional bit fields when the descriptor array is not
    // yet used.
    inline bool IsEmpty();
  
    // Returns the number of descriptors in the array.
    inline int number_of_descriptors();
    inline int number_of_descriptors_storage();
    inline int NumberOfSlackDescriptors();
  
    inline void SetNumberOfDescriptors(int number_of_descriptors);
    inline int number_of_entries();
  
    inline bool HasEnumCache();
    inline bool HasEnumIndicesCache();
    inline FixedArray* GetEnumCache();
    inline FixedArray* GetEnumIndicesCache();
  
    void ClearEnumCache();
    inline void CopyEnumCacheFrom(DescriptorArray* array);
    // Initialize or change the enum cache,
    // using the supplied storage for the small "bridge".
    static void SetEnumCache(Handle<DescriptorArray> descriptors,
                             Isolate* isolate, Handle<FixedArray> new_cache,
                             Handle<FixedArray> new_index_cache);
  
    // Accessors for fetching instance descriptor at descriptor number.
    inline Name* GetKey(int descriptor_number);
    inline Object** GetKeySlot(int descriptor_number);
    inline Object* GetValue(int descriptor_number);
    inline void SetValue(int descriptor_number, Object* value);
    inline Object** GetValueSlot(int descriptor_number);
    static inline int GetValueOffset(int descriptor_number);
    inline Object** GetDescriptorStartSlot(int descriptor_number);
    inline Object** GetDescriptorEndSlot(int descriptor_number);
    inline PropertyDetails GetDetails(int descriptor_number);
    inline int GetFieldIndex(int descriptor_number);
    inline FieldType* GetFieldType(int descriptor_number);
  
    inline Name* GetSortedKey(int descriptor_number);
    inline int GetSortedKeyIndex(int descriptor_number);
    inline void SetSortedKey(int pointer, int descriptor_number);
  
    // Accessor for complete descriptor.
    inline void Get(int descriptor_number, Descriptor* desc);
    inline void Set(int descriptor_number, Descriptor* desc);
    inline void Set(int descriptor_number, Name* key, Object* value,
                    PropertyDetails details);
    void Replace(int descriptor_number, Descriptor* descriptor);
  
    // Generalizes constness, representation and field type of all field
    // descriptors.
    void GeneralizeAllFields();
  
    // Append automatically sets the enumeration index. This should only be used
    // to add descriptors in bulk at the end, followed by sorting the descriptor
    // array.
    inline void Append(Descriptor* desc);
  
    static Handle<DescriptorArray> CopyUpTo(Handle<DescriptorArray> desc,
                                            int enumeration_index, int slack = 0);
  
    static Handle<DescriptorArray> CopyUpToAddAttributes(
        Handle<DescriptorArray> desc, int enumeration_index,
        PropertyAttributes attributes, int slack = 0);
  
    // Sort the instance descriptors by the hash codes of their keys.
    void Sort();
  
    // Search the instance descriptors for given name.
    INLINE(int Search(Name* name, int number_of_own_descriptors));
  
    // As the above, but uses DescriptorLookupCache and updates it when
    // necessary.
    INLINE(int SearchWithCache(Isolate* isolate, Name* name, Map* map));
  
    bool IsEqualUpTo(DescriptorArray* desc, int nof_descriptors);
  
    // Allocates a DescriptorArray, but returns the singleton
    // empty descriptor array object if number_of_descriptors is 0.
    static Handle<DescriptorArray> Allocate(
        Isolate* isolate, int number_of_descriptors, int slack,
        PretenureFlag pretenure = NOT_TENURED);
  
    DECL_CAST(DescriptorArray)
  
    // Constant for denoting key was not found.
    static const int kNotFound = -1;
  
    static const int kDescriptorLengthIndex = 0;
    static const int kEnumCacheBridgeIndex = 1;
    static const int kFirstIndex = 2;
  
    // The length of the "bridge" to the enum cache.
    static const int kEnumCacheBridgeLength = 2;
    static const int kEnumCacheBridgeCacheIndex = 0;
    static const int kEnumCacheBridgeIndicesCacheIndex = 1;
  
    // Layout description.
    static const int kDescriptorLengthOffset = FixedArray::kHeaderSize;
    static const int kEnumCacheBridgeOffset =
        kDescriptorLengthOffset + kPointerSize;
    static const int kFirstOffset = kEnumCacheBridgeOffset + kPointerSize;
  
    // Layout description for the bridge array.
    static const int kEnumCacheBridgeCacheOffset = FixedArray::kHeaderSize;
  
    // Layout of descriptor.
    // Naming is consistent with Dictionary classes for easy templating.
    static const int kEntryKeyIndex = 0;
    static const int kEntryDetailsIndex = 1;
    static const int kEntryValueIndex = 2;
    static const int kEntrySize = 3;
  
  #if defined(DEBUG) || defined(OBJECT_PRINT)
    // For our gdb macros, we should perhaps change these in the future.
    void Print();
  
    // Print all the descriptors.
    void PrintDescriptors(std::ostream& os);  // NOLINT
  
    void PrintDescriptorDetails(std::ostream& os, int descriptor,
                                PropertyDetails::PrintMode mode);
  #endif
  
  #ifdef DEBUG
    // Is the descriptor array sorted and without duplicates?
    bool IsSortedNoDuplicates(int valid_descriptors = -1);
  
    // Are two DescriptorArrays equal?
    bool IsEqualTo(DescriptorArray* other);
  #endif
  
    // Returns the fixed array length required to hold number_of_descriptors
    // descriptors.
    static int LengthFor(int number_of_descriptors) {
      return ToKeyIndex(number_of_descriptors);
    }
  
    static int ToDetailsIndex(int descriptor_number) {
      return kFirstIndex + (descriptor_number * kEntrySize) + kEntryDetailsIndex;
    }
  
    // Conversion from descriptor number to array indices.
    static int ToKeyIndex(int descriptor_number) {
      return kFirstIndex + (descriptor_number * kEntrySize) + kEntryKeyIndex;
    }
  
    static int ToValueIndex(int descriptor_number) {
      return kFirstIndex + (descriptor_number * kEntrySize) + kEntryValueIndex;
    }
  
   private:
    // Transfer a complete descriptor from the src descriptor array to this
    // descriptor array.
    void CopyFrom(int index, DescriptorArray* src);
  
    // Swap first and second descriptor.
    inline void SwapSortedKeys(int first, int second);
  
    DISALLOW_IMPLICIT_CONSTRUCTORS(DescriptorArray);
  };
  
  }  // namespace internal
  }  // namespace v8
  
  #include "src/objects/object-macros-undef.h"
  
  #endif  // V8_OBJECTS_DESCRIPTOR_ARRAY_H_
  