1 // Copyright 2015 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_UTILS_IDENTITY_MAP_H_ 6 #define V8_UTILS_IDENTITY_MAP_H_ 7 8 #include <type_traits> 9 10 #include "src/base/functional.h" 11 #include "src/handles/handles.h" 12 #include "src/objects/heap-object.h" 13 14 namespace v8 { 15 namespace internal { 16 17 // Forward declarations. 18 class Heap; 19 class StrongRootsEntry; 20 21 template <typename T> 22 struct IdentityMapFindResult { 23 T* entry; 24 bool already_exists; 25 }; 26 27 // Base class of identity maps contains shared code for all template 28 // instantions. 29 class V8_EXPORT_PRIVATE IdentityMapBase { 30 public: empty()31 bool empty() const { return size_ == 0; } size()32 int size() const { return size_; } capacity()33 int capacity() const { return capacity_; } is_iterable()34 bool is_iterable() const { return is_iterable_; } 35 36 protected: 37 // Allow Tester to access internals, including changing the address of objects 38 // within the {keys_} array in order to simulate a moving GC. 39 friend class IdentityMapTester; 40 41 using RawEntry = uintptr_t*; 42 IdentityMapBase(Heap * heap)43 explicit IdentityMapBase(Heap* heap) 44 : heap_(heap), 45 gc_counter_(-1), 46 size_(0), 47 capacity_(0), 48 mask_(0), 49 keys_(nullptr), 50 strong_roots_entry_(nullptr), 51 values_(nullptr), 52 is_iterable_(false) {} 53 virtual ~IdentityMapBase(); 54 55 IdentityMapFindResult<uintptr_t> FindOrInsertEntry(Address key); 56 RawEntry FindEntry(Address key) const; 57 RawEntry InsertEntry(Address key); 58 bool DeleteEntry(Address key, uintptr_t* deleted_value); 59 void Clear(); 60 61 Address KeyAtIndex(int index) const; 62 63 RawEntry EntryAtIndex(int index) const; 64 int NextIndex(int index) const; 65 66 void EnableIteration(); 67 void DisableIteration(); 68 69 virtual uintptr_t* NewPointerArray(size_t length) = 0; 70 virtual void DeletePointerArray(uintptr_t* array, size_t length) = 0; 71 72 private: 73 // Internal implementation should not be called directly by subclasses. 74 int ScanKeysFor(Address address, uint32_t hash) const; 75 std::pair<int, bool> InsertKey(Address address, uint32_t hash); 76 int Lookup(Address key) const; 77 std::pair<int, bool> LookupOrInsert(Address key); 78 bool DeleteIndex(int index, uintptr_t* deleted_value); 79 void Rehash(); 80 void Resize(int new_capacity); 81 uint32_t Hash(Address address) const; 82 83 base::hash<uintptr_t> hasher_; 84 Heap* heap_; 85 int gc_counter_; 86 int size_; 87 int capacity_; 88 int mask_; 89 Address* keys_; 90 StrongRootsEntry* strong_roots_entry_; 91 uintptr_t* values_; 92 bool is_iterable_; 93 94 DISALLOW_COPY_AND_ASSIGN(IdentityMapBase); 95 }; 96 97 // Implements an identity map from object addresses to a given value type {V}. 98 // The map is robust w.r.t. garbage collection by synchronization with the 99 // supplied {heap}. 100 // * Keys are treated as strong roots. 101 // * The value type {V} must be reinterpret_cast'able to {uintptr_t} 102 // * The value type {V} must not be a heap type. 103 template <typename V, class AllocationPolicy> 104 class IdentityMap : public IdentityMapBase { 105 public: 106 STATIC_ASSERT(sizeof(V) <= sizeof(uintptr_t)); 107 STATIC_ASSERT(std::is_trivially_copyable<V>::value); 108 STATIC_ASSERT(std::is_trivially_destructible<V>::value); 109 110 explicit IdentityMap(Heap* heap, 111 AllocationPolicy allocator = AllocationPolicy()) IdentityMapBase(heap)112 : IdentityMapBase(heap), allocator_(allocator) {} ~IdentityMap()113 ~IdentityMap() override { Clear(); } 114 115 // Searches this map for the given key using the object's address 116 // as the identity, returning: 117 // found => a pointer to the storage location for the value, true 118 // not found => a pointer to a new storage location for the value, false FindOrInsert(Handle<Object> key)119 IdentityMapFindResult<V> FindOrInsert(Handle<Object> key) { 120 return FindOrInsert(*key); 121 } FindOrInsert(Object key)122 IdentityMapFindResult<V> FindOrInsert(Object key) { 123 auto raw = FindOrInsertEntry(key.ptr()); 124 return {reinterpret_cast<V*>(raw.entry), raw.already_exists}; 125 } 126 127 // Searches this map for the given key using the object's address 128 // as the identity, returning: 129 // found => a pointer to the storage location for the value 130 // not found => {nullptr} Find(Handle<Object> key)131 V* Find(Handle<Object> key) const { return Find(*key); } Find(Object key)132 V* Find(Object key) const { 133 return reinterpret_cast<V*>(FindEntry(key.ptr())); 134 } 135 136 // Insert the value for the given key. The key must not have previously 137 // existed. Insert(Handle<Object> key,V v)138 void Insert(Handle<Object> key, V v) { Insert(*key, v); } Insert(Object key,V v)139 void Insert(Object key, V v) { 140 *reinterpret_cast<V*>(InsertEntry(key.ptr())) = v; 141 } 142 Delete(Handle<Object> key,V * deleted_value)143 bool Delete(Handle<Object> key, V* deleted_value) { 144 return Delete(*key, deleted_value); 145 } Delete(Object key,V * deleted_value)146 bool Delete(Object key, V* deleted_value) { 147 uintptr_t v; 148 bool deleted_something = DeleteEntry(key.ptr(), &v); 149 if (deleted_value != nullptr && deleted_something) { 150 *deleted_value = *reinterpret_cast<V*>(&v); 151 } 152 return deleted_something; 153 } 154 155 // Removes all elements from the map. Clear()156 void Clear() { IdentityMapBase::Clear(); } 157 158 // Iterator over IdentityMap. The IteratableScope used to create this Iterator 159 // must be live for the duration of the iteration. 160 class Iterator { 161 public: 162 Iterator& operator++() { 163 index_ = map_->NextIndex(index_); 164 return *this; 165 } 166 key()167 Object key() const { return Object(map_->KeyAtIndex(index_)); } entry()168 V* entry() const { 169 return reinterpret_cast<V*>(map_->EntryAtIndex(index_)); 170 } 171 172 V* operator*() { return entry(); } 173 V* operator->() { return entry(); } 174 bool operator!=(const Iterator& other) { return index_ != other.index_; } 175 176 private: Iterator(IdentityMap * map,int index)177 Iterator(IdentityMap* map, int index) : map_(map), index_(index) {} 178 179 IdentityMap* map_; 180 int index_; 181 182 friend class IdentityMap; 183 }; 184 185 class IteratableScope { 186 public: IteratableScope(IdentityMap * map)187 explicit IteratableScope(IdentityMap* map) : map_(map) { 188 CHECK(!map_->is_iterable()); 189 map_->EnableIteration(); 190 } ~IteratableScope()191 ~IteratableScope() { 192 CHECK(map_->is_iterable()); 193 map_->DisableIteration(); 194 } 195 begin()196 Iterator begin() { return Iterator(map_, map_->NextIndex(-1)); } end()197 Iterator end() { return Iterator(map_, map_->capacity()); } 198 199 private: 200 IdentityMap* map_; 201 DISALLOW_COPY_AND_ASSIGN(IteratableScope); 202 }; 203 204 protected: 205 // This struct is just a type tag for Zone::NewArray<T>(size_t) call. 206 struct Buffer {}; 207 208 // TODO(ishell): consider removing virtual methods in favor of combining 209 // IdentityMapBase and IdentityMap into one class. This would also save 210 // space when sizeof(V) is less than sizeof(uintptr_t). NewPointerArray(size_t length)211 uintptr_t* NewPointerArray(size_t length) override { 212 return allocator_.template NewArray<uintptr_t, Buffer>(length); 213 } DeletePointerArray(uintptr_t * array,size_t length)214 void DeletePointerArray(uintptr_t* array, size_t length) override { 215 allocator_.template DeleteArray<uintptr_t, Buffer>(array, length); 216 } 217 218 private: 219 AllocationPolicy allocator_; 220 DISALLOW_COPY_AND_ASSIGN(IdentityMap); 221 }; 222 223 } // namespace internal 224 } // namespace v8 225 226 #endif // V8_UTILS_IDENTITY_MAP_H_ 227