#ifndef V8_OBJECTS_DICTIONARY_H_
#define V8_OBJECTS_DICTIONARY_H_
#include <optional>
#include "src/base/export-template.h"
#include "src/common/globals.h"
#include "src/objects/hash-table.h"
#include "src/objects/property-array.h"
#include "src/objects/smi.h"
#include "src/roots/roots.h"
#include "src/objects/object-macros.h"
namespace v8::internal {
#ifdef V8_ENABLE_SWISS_NAME_DICTIONARY
class SwissNameDictionary;
using PropertyDictionary = SwissNameDictionary;
#else
using PropertyDictionary = NameDictionary;
#endif
template <typename Derived, typename Shape>
class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) Dictionary
: public HashTable<Derived, Shape> {
using DerivedHashTable = HashTable<Derived, Shape>;
public:
using TodoShape = Shape;
using Key = typename TodoShape::Key;
inline Tagged<Object> ValueAt(InternalIndex entry);
inline Tagged<Object> ValueAt(PtrComprCageBase cage_base,
InternalIndex entry);
inline Tagged<Object> ValueAt(InternalIndex entry, SeqCstAccessTag);
inline Tagged<Object> ValueAt(PtrComprCageBase cage_base, InternalIndex entry,
SeqCstAccessTag);
inline std::optional<Tagged<Object>> TryValueAt(InternalIndex entry);
inline void ValueAtPut(InternalIndex entry, Tagged<Object> value);
inline void ValueAtPut(InternalIndex entry, Tagged<Object> value,
SeqCstAccessTag);
inline Tagged<Object> ValueAtSwap(InternalIndex entry, Tagged<Object> value,
SeqCstAccessTag);
inline Tagged<Object> ValueAtCompareAndSwap(InternalIndex entry,
Tagged<Object> expected,
Tagged<Object> value,
SeqCstAccessTag);
inline PropertyDetails DetailsAt(InternalIndex entry);
inline void DetailsAtPut(InternalIndex entry, PropertyDetails value);
static const bool kIsOrderedDictionaryType = false;
template <template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
V8_WARN_UNUSED_RESULT static HandleType<Derived> DeleteEntry(
Isolate* isolate, HandleType<Derived> dictionary, InternalIndex entry);
template <template <typename> typename HandleType>
V8_WARN_UNUSED_RESULT static inline HandleType<Derived> Shrink(
Isolate* isolate, HandleType<Derived> dictionary)
requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
{
return DerivedHashTable::Shrink(isolate, dictionary);
}
int NumberOfEnumerableProperties();
Tagged<Object> SlowReverseLookup(Tagged<Object> value);
inline void ClearEntry(InternalIndex entry);
inline void SetEntry(InternalIndex entry, Tagged<Object> key,
Tagged<Object> value, PropertyDetails details);
inline ObjectSlot RawFieldOfValueAt(InternalIndex entry);
template <typename IsolateT, template <typename> typename HandleType,
AllocationType key_allocation = std::is_same_v<IsolateT, Isolate>
? AllocationType::kYoung
: AllocationType::kOld>
requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
V8_WARN_UNUSED_RESULT static HandleType<Derived> Add(
IsolateT* isolate, HandleType<Derived> dictionary, Key key,
DirectHandle<Object> value, PropertyDetails details,
InternalIndex* entry_out = nullptr);
template <typename IsolateT, template <typename> typename HandleType,
AllocationType key_allocation = std::is_same_v<IsolateT, Isolate>
? AllocationType::kYoung
: AllocationType::kOld>
requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
static void UncheckedAdd(IsolateT* isolate, HandleType<Derived> dictionary,
Key key, DirectHandle<Object> value,
PropertyDetails details);
static Handle<Derived> ShallowCopy(
Isolate* isolate, DirectHandle<Derived> dictionary,
AllocationType allocation = AllocationType::kYoung);
protected:
template <template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
V8_WARN_UNUSED_RESULT static auto AtPut(Isolate* isolate,
HandleType<Derived> dictionary,
Key key, DirectHandle<Object> value,
PropertyDetails details);
static void UncheckedAtPut(Isolate* isolate, DirectHandle<Derived> dictionary,
Key key, DirectHandle<Object> value,
PropertyDetails details);
};
#define EXTERN_DECLARE_DICTIONARY(DERIVED, SHAPE) \
EXTERN_DECLARE_HASH_TABLE(DERIVED, SHAPE) \
extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) \
Dictionary<DERIVED, SHAPE>;
template <typename Key>
class BaseDictionaryShape : public BaseShape<Key> {
public:
static const bool kHasDetails = true;
template <typename Dictionary>
static inline PropertyDetails DetailsAt(Tagged<Dictionary> dict,
InternalIndex entry);
template <typename Dictionary>
static inline void DetailsAtPut(Tagged<Dictionary> dict, InternalIndex entry,
PropertyDetails value);
static const bool kDoHashSpreading = false;
static const uint32_t kHashBits = 0;
};
class BaseNameDictionaryShape : public BaseDictionaryShape<DirectHandle<Name>> {
public:
static inline bool IsMatch(DirectHandle<Name> key, Tagged<Object> other);
static inline uint32_t Hash(ReadOnlyRoots roots, DirectHandle<Name> key);
static inline uint32_t HashForObject(ReadOnlyRoots roots,
Tagged<Object> object);
template <AllocationType allocation = AllocationType::kYoung>
static inline DirectHandle<Object> AsHandle(Isolate* isolate,
DirectHandle<Name> key);
template <AllocationType allocation = AllocationType::kOld>
static inline DirectHandle<Object> AsHandle(LocalIsolate* isolate,
DirectHandle<Name> key);
static const int kEntryValueIndex = 1;
};
class NameDictionaryShape : public BaseNameDictionaryShape {
public:
static const int kPrefixSize = 3;
static const int kEntrySize = 3;
static const bool kMatchNeedsHoleCheck = false;
};
template <typename Derived, typename Shape>
class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) BaseNameDictionary
: public Dictionary<Derived, Shape> {
using Key = typename Shape::Key;
public:
static const int kNextEnumerationIndexIndex =
HashTableBase::kPrefixStartIndex;
static const int kObjectHashIndex = kNextEnumerationIndexIndex + 1;
static const int kEntryValueIndex = 1;
inline void SetHash(int hash);
inline int Hash() const;
template <typename IsolateT>
V8_WARN_UNUSED_RESULT static Handle<Derived> New(
IsolateT* isolate, int at_least_space_for,
AllocationType allocation = AllocationType::kYoung,
MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY);
static int NextEnumerationIndex(Isolate* isolate,
DirectHandle<Derived> dictionary);
inline int next_enumeration_index();
inline void set_next_enumeration_index(int index);
static DirectHandle<FixedArray> IterationIndices(
Isolate* isolate, DirectHandle<Derived> dictionary);
template <typename IsolateT, template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
V8_WARN_UNUSED_RESULT static HandleType<Derived>
AddNoUpdateNextEnumerationIndex(IsolateT* isolate,
HandleType<Derived> dictionary, Key key,
DirectHandle<Object> value,
PropertyDetails details,
InternalIndex* entry_out = nullptr);
template <template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
V8_WARN_UNUSED_RESULT static HandleType<Derived>::MaybeType Add(
Isolate* isolate, HandleType<Derived> dictionary, Key key,
DirectHandle<Object> value, PropertyDetails details,
InternalIndex* entry_out = nullptr);
using Dictionary<Derived, Shape>::FindInsertionEntry;
};
class SimpleNameDictionaryShape : public BaseNameDictionaryShape {
public:
static const bool kHasDetails = false;
static const bool kMatchNeedsHoleCheck = false;
static const int kPrefixSize = 0;
static const int kEntrySize = 2;
template <typename Dictionary>
static inline PropertyDetails DetailsAt(Tagged<Dictionary> dict,
InternalIndex entry) {
UNREACHABLE();
}
template <typename Dictionary>
static inline void DetailsAtPut(Tagged<Dictionary> dict, InternalIndex entry,
PropertyDetails value) {
UNREACHABLE();
}
};
EXTERN_DECLARE_DICTIONARY(SimpleNameDictionary, SimpleNameDictionaryShape)
class SimpleNameDictionary
: public Dictionary<SimpleNameDictionary, SimpleNameDictionaryShape> {
public:
static inline DirectHandle<Map> GetMap(RootsTable& roots);
V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Handle<SimpleNameDictionary>
Set(Isolate* isolate, Handle<SimpleNameDictionary> dictionary,
DirectHandle<Name> key, DirectHandle<Object> value);
using HashTable<SimpleNameDictionary,
SimpleNameDictionaryShape>::FindInsertionEntry;
static const int kEntryValueIndex = 1;
};
#define EXTERN_DECLARE_BASE_NAME_DICTIONARY(DERIVED, SHAPE) \
EXTERN_DECLARE_DICTIONARY(DERIVED, SHAPE) \
extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) \
BaseNameDictionary<DERIVED, SHAPE>;
EXTERN_DECLARE_BASE_NAME_DICTIONARY(NameDictionary, NameDictionaryShape)
class V8_EXPORT_PRIVATE NameDictionary
: public BaseNameDictionary<NameDictionary, NameDictionaryShape> {
public:
static inline DirectHandle<Map> GetMap(RootsTable& roots);
DECL_PRINTER(NameDictionary)
static const int kFlagsIndex = kObjectHashIndex + 1;
static const int kEntryValueIndex = 1;
static const int kEntryDetailsIndex = 2;
static const int kInitialCapacity = 2;
inline Tagged<Name> NameAt(InternalIndex entry);
inline Tagged<Name> NameAt(PtrComprCageBase cage_base, InternalIndex entry);
inline void set_hash(int hash);
inline int hash() const;
using MayHaveInterestingPropertiesBit = base::BitField<bool, 0, 1, uint32_t>;
DECL_BOOLEAN_ACCESSORS(may_have_interesting_properties)
static constexpr int kFlagsDefault = 0;
inline uint32_t flags() const;
inline void set_flags(uint32_t flags);
template <typename IsolateT>
V8_WARN_UNUSED_RESULT static Handle<NameDictionary> New(
IsolateT* isolate, int at_least_space_for,
AllocationType allocation = AllocationType::kYoung,
MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY);
};
class V8_EXPORT_PRIVATE GlobalDictionaryShape : public BaseNameDictionaryShape {
public:
static inline bool IsMatch(DirectHandle<Name> key, Tagged<Object> other);
static inline uint32_t HashForObject(ReadOnlyRoots roots,
Tagged<Object> object);
static const bool kMatchNeedsHoleCheck = true;
static const int kPrefixSize = 2;
static const int kEntrySize = 1;
template <typename Dictionary>
static inline PropertyDetails DetailsAt(Tagged<Dictionary> dict,
InternalIndex entry);
template <typename Dictionary>
static inline void DetailsAtPut(Tagged<Dictionary> dict, InternalIndex entry,
PropertyDetails value);
static inline Tagged<Object> Unwrap(Tagged<Object> key);
};
EXTERN_DECLARE_BASE_NAME_DICTIONARY(GlobalDictionary, GlobalDictionaryShape)
class V8_EXPORT_PRIVATE GlobalDictionary
: public BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape> {
public:
static inline DirectHandle<Map> GetMap(RootsTable& roots);
DECL_PRINTER(GlobalDictionary)
inline Tagged<Object> ValueAt(InternalIndex entry);
inline Tagged<Object> ValueAt(PtrComprCageBase cage_base,
InternalIndex entry);
inline Tagged<PropertyCell> CellAt(InternalIndex entry);
inline Tagged<PropertyCell> CellAt(PtrComprCageBase cage_base,
InternalIndex entry);
inline void SetEntry(InternalIndex entry, Tagged<Object> key,
Tagged<Object> value, PropertyDetails details);
inline void ClearEntry(InternalIndex entry);
inline Tagged<Name> NameAt(InternalIndex entry);
inline Tagged<Name> NameAt(PtrComprCageBase cage_base, InternalIndex entry);
inline void ValueAtPut(InternalIndex entry, Tagged<Object> value);
std::optional<Tagged<PropertyCell>>
TryFindPropertyCellForConcurrentLookupIterator(Isolate* isolate,
DirectHandle<Name> name,
RelaxedLoadTag tag);
};
class NumberDictionaryBaseShape : public BaseDictionaryShape<uint32_t> {
public:
static inline bool IsMatch(uint32_t key, Tagged<Object> other);
template <AllocationType allocation = AllocationType::kYoung>
static inline DirectHandle<Object> AsHandle(Isolate* isolate, uint32_t key);
template <AllocationType allocation = AllocationType::kOld>
static inline DirectHandle<Object> AsHandle(LocalIsolate* isolate,
uint32_t key);
static inline uint32_t Hash(ReadOnlyRoots roots, uint32_t key);
static inline uint32_t HashForObject(ReadOnlyRoots roots,
Tagged<Object> object);
static const bool kMatchNeedsHoleCheck = true;
};
class NumberDictionaryShape : public NumberDictionaryBaseShape {
public:
static const int kPrefixSize = 1;
static const int kEntrySize = 3;
};
class SimpleNumberDictionaryShape : public NumberDictionaryBaseShape {
public:
static const bool kHasDetails = false;
static const int kPrefixSize = 0;
static const int kEntrySize = 2;
template <typename Dictionary>
static inline PropertyDetails DetailsAt(Tagged<Dictionary> dict,
InternalIndex entry) {
UNREACHABLE();
}
template <typename Dictionary>
static inline void DetailsAtPut(Tagged<Dictionary> dict, InternalIndex entry,
PropertyDetails value) {
UNREACHABLE();
}
};
EXTERN_DECLARE_DICTIONARY(SimpleNumberDictionary, SimpleNumberDictionaryShape)
class SimpleNumberDictionary
: public Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape> {
public:
static inline DirectHandle<Map> GetMap(RootsTable& roots);
V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static Handle<SimpleNumberDictionary>
Set(Isolate* isolate, Handle<SimpleNumberDictionary> dictionary, uint32_t key,
DirectHandle<Object> value);
static const int kEntryValueIndex = 1;
};
EXTERN_DECLARE_DICTIONARY(NumberDictionary, NumberDictionaryShape)
class NumberDictionary
: public Dictionary<NumberDictionary, NumberDictionaryShape> {
public:
static inline DirectHandle<Map> GetMap(RootsTable& roots);
DECL_PRINTER(NumberDictionary)
template <template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<NumberDictionary>,
DirectHandle<NumberDictionary>>)
V8_WARN_UNUSED_RESULT static HandleType<NumberDictionary> Set(
Isolate* isolate, HandleType<NumberDictionary> dictionary, uint32_t key,
DirectHandle<Object> value,
DirectHandle<JSObject> dictionary_holder = DirectHandle<JSObject>::null(),
PropertyDetails details = PropertyDetails::Empty());
static void UncheckedSet(Isolate* isolate,
DirectHandle<NumberDictionary> dictionary,
uint32_t key, DirectHandle<Object> value);
static const int kMaxNumberKeyIndex = kPrefixStartIndex;
void UpdateMaxNumberKey(uint32_t key,
DirectHandle<JSObject> dictionary_holder);
void CopyValuesTo(Tagged<FixedArray> elements);
inline bool requires_slow_elements();
inline void set_requires_slow_elements();
inline uint32_t max_number_key();
static const int kEntryValueIndex = 1;
static const int kEntryDetailsIndex = 2;
static const int kRequiresSlowElementsMask = 1;
static const int kRequiresSlowElementsTagSize = 1;
static const uint32_t kRequiresSlowElementsLimit = (1 << 29) - 1;
static const uint32_t kPreferFastElementsSizeFactor = 3;
};
template <typename Dictionary>
struct EnumIndexComparator {
explicit EnumIndexComparator(Tagged<Dictionary> dict) : dict(dict) {}
bool operator()(Tagged_t a, Tagged_t b) {
PropertyDetails details_a(dict->DetailsAt(
InternalIndex(Tagged<Smi>(static_cast<Address>(a)).value())));
PropertyDetails details_b(dict->DetailsAt(
InternalIndex(Tagged<Smi>(static_cast<Address>(b)).value())));
return details_a.dictionary_index() < details_b.dictionary_index();
}
Tagged<Dictionary> dict;
};
}
#include "src/objects/object-macros-undef.h"
#endif