v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
identity-map.h
Go to the documentation of this file.
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/hashing.h"
11#include "src/handles/handles.h"
12#include "src/objects/tagged.h"
13
14namespace v8 {
15namespace internal {
16
17// Forward declarations.
18class Heap;
19class StrongRootsEntry;
20
21template <typename T>
26
27// Base class of identity maps contains shared code for all template
28// instantiations.
30 public:
33 bool empty() const { return size_ == 0; }
34 int size() const { return size_; }
35 int capacity() const { return capacity_; }
36 bool is_iterable() const { return is_iterable_; }
37
38 protected:
39 // Allow Tester to access internals, including changing the address of objects
40 // within the {keys_} array in order to simulate a moving GC.
41 friend class IdentityMapTester;
42
43 using RawEntry = uintptr_t*;
44
46 : heap_(heap),
47 gc_counter_(-1),
48 size_(0),
49 capacity_(0),
50 mask_(0),
51 keys_(nullptr),
52 strong_roots_entry_(nullptr),
53 values_(nullptr),
54 is_iterable_(false) {}
55 virtual ~IdentityMapBase();
56
57 IdentityMapFindResult<uintptr_t> FindOrInsertEntry(Address key);
58 RawEntry FindEntry(Address key) const;
59 RawEntry InsertEntry(Address key);
60 bool DeleteEntry(Address key, uintptr_t* deleted_value);
61 void Clear();
62
63 Address KeyAtIndex(int index) const;
64
65 RawEntry EntryAtIndex(int index) const;
66 int NextIndex(int index) const;
67
68 void EnableIteration();
69 void DisableIteration();
70
71 virtual uintptr_t* NewPointerArray(size_t length, uintptr_t value) = 0;
72 virtual void DeletePointerArray(uintptr_t* array, size_t length) = 0;
73
74 private:
75 // Internal implementation should not be called directly by subclasses.
76 // The result is {index, found}. The index is either:
77 // * The index where the key was found (found=true)
78 // * The index of the first empty space encountered (found=false)
79 // * -1 if the table is full and the key was not found (found=false)
80 std::pair<int, bool> ScanKeysFor(Address address, uint32_t hash) const;
81 std::pair<int, bool> InsertKey(Address address, uint32_t hash);
82 int Lookup(Address key) const;
83 std::pair<int, bool> LookupOrInsert(Address key);
84 bool DeleteIndex(int index, uintptr_t* deleted_value);
85 void Rehash();
86 void Resize(int new_capacity);
87 uint32_t Hash(Address address) const;
88 bool ShouldGrow() const;
89
93 int size_;
95 int mask_;
96 Address* keys_;
98 uintptr_t* values_;
100};
101
102// Implements an identity map from object addresses to a given value type {V}.
103// The map is robust w.r.t. garbage collection by synchronization with the
104// supplied {heap}.
105//
106// * Keys are treated as strong roots.
107// * The value type {V} must be reinterpret_cast'able to {uintptr_t}
108// * The value type {V} must not be a heap type.
109//
110// Note: IdentityMap methods must not be called during the mark-compact phase
111// since rehashing there may lead to incorrect results.
112// Note: When using IdentityMap in concurrent settings, be aware that reads
113// (e.g. `Find`) may trigger lazy rehashing and thus must be treated as write
114// operations wrt synchronization.
115template <typename V, class AllocationPolicy>
117 public:
118 static_assert(sizeof(V) <= sizeof(uintptr_t));
119 static_assert(std::is_trivially_copyable<V>::value);
120 static_assert(std::is_trivially_destructible<V>::value);
121
124 : IdentityMapBase(heap), allocator_(allocator) {}
125 IdentityMap(const IdentityMap&) = delete;
127 ~IdentityMap() override { Clear(); }
128
129 // Searches this map for the given key using the object's address
130 // as the identity, returning:
131 // found => a pointer to the storage location for the value, true
132 // not found => a pointer to a new storage location for the value, false
137 auto raw = FindOrInsertEntry(key.ptr());
138 return {reinterpret_cast<V*>(raw.entry), raw.already_exists};
139 }
140
141 // Searches this map for the given key using the object's address
142 // as the identity, returning:
143 // found => a pointer to the storage location for the value
144 // not found => {nullptr}
145 V* Find(DirectHandle<Object> key) const { return Find(*key); }
147 return reinterpret_cast<V*>(FindEntry(key.ptr()));
148 }
149
150 // Insert the value for the given key. The key must not have previously
151 // existed.
154 *reinterpret_cast<V*>(InsertEntry(key.ptr())) = v;
155 }
156
157 bool Delete(DirectHandle<Object> key, V* deleted_value) {
158 return Delete(*key, deleted_value);
159 }
160 bool Delete(Tagged<Object> key, V* deleted_value) {
161 uintptr_t v;
162 bool deleted_something = DeleteEntry(key.ptr(), &v);
163 if (deleted_value != nullptr && deleted_something) {
164 *deleted_value = *reinterpret_cast<V*>(&v);
165 }
166 return deleted_something;
167 }
168
169 // Removes all elements from the map.
171
172 // Iterator over IdentityMap. The IteratableScope used to create this Iterator
173 // must be live for the duration of the iteration.
174 class Iterator {
175 public:
178 return *this;
179 }
180
183 }
184 V* entry() const {
185 return reinterpret_cast<V*>(map_->EntryAtIndex(index_));
186 }
187
188 V* operator*() { return entry(); }
189 V* operator->() { return entry(); }
190 bool operator!=(const Iterator& other) const {
191 return index_ != other.index_;
192 }
193 bool operator==(const Iterator& other) const {
194 return index_ == other.index_;
195 }
196
197 private:
198 Iterator(IdentityMap* map, int index) : map_(map), index_(index) {}
199
202
203 friend class IdentityMap;
204 };
205
207 public:
208 explicit IteratableScope(IdentityMap* map) : map_(map) {
209 CHECK(!map_->is_iterable());
210 map_->EnableIteration();
211 }
215 CHECK(map_->is_iterable());
216 map_->DisableIteration();
217 }
218
219 Iterator begin() { return Iterator(map_, map_->NextIndex(-1)); }
220 Iterator end() { return Iterator(map_, map_->capacity()); }
221
222 private:
224 };
225
226 protected:
227 // This struct is just a type tag for Zone::NewArray<T>(size_t) call.
228 struct Buffer {};
229
230 // TODO(ishell): consider removing virtual methods in favor of combining
231 // IdentityMapBase and IdentityMap into one class. This would also save
232 // space when sizeof(V) is less than sizeof(uintptr_t).
233 uintptr_t* NewPointerArray(size_t length, uintptr_t value) override {
234 uintptr_t* result =
235 allocator_.template AllocateArray<uintptr_t, Buffer>(length);
236 std::uninitialized_fill_n(result, length, value);
237 return result;
238 }
239 void DeletePointerArray(uintptr_t* array, size_t length) override {
240 allocator_.template DeleteArray<uintptr_t, Buffer>(array, length);
241 }
242
243 private:
245};
246
247} // namespace internal
248} // namespace v8
249
250#endif // V8_UTILS_IDENTITY_MAP_H_
bool DeleteEntry(Address key, uintptr_t *deleted_value)
virtual void DeletePointerArray(uintptr_t *array, size_t length)=0
IdentityMapBase & operator=(const IdentityMapBase &)=delete
virtual uintptr_t * NewPointerArray(size_t length, uintptr_t value)=0
RawEntry FindEntry(Address key) const
IdentityMapBase(const IdentityMapBase &)=delete
IdentityMapFindResult< uintptr_t > FindOrInsertEntry(Address key)
int NextIndex(int index) const
Address KeyAtIndex(int index) const
RawEntry EntryAtIndex(int index) const
base::hash< uintptr_t > hasher_
StrongRootsEntry * strong_roots_entry_
RawEntry InsertEntry(Address key)
IteratableScope & operator=(const IteratableScope &)=delete
IteratableScope(const IteratableScope &)=delete
bool operator==(const Iterator &other) const
bool operator!=(const Iterator &other) const
Iterator(IdentityMap *map, int index)
Tagged< Object > key() const
IdentityMap(const IdentityMap &)=delete
bool Delete(Tagged< Object > key, V *deleted_value)
void Insert(DirectHandle< Object > key, V v)
uintptr_t * NewPointerArray(size_t length, uintptr_t value) override
bool Delete(DirectHandle< Object > key, V *deleted_value)
V * Find(DirectHandle< Object > key) const
IdentityMap(Heap *heap, AllocationPolicy allocator=AllocationPolicy())
void DeletePointerArray(uintptr_t *array, size_t length) override
V * Find(Tagged< Object > key) const
AllocationPolicy allocator_
IdentityMapFindResult< V > FindOrInsert(Tagged< Object > key)
IdentityMap & operator=(const IdentityMap &)=delete
void Insert(Tagged< Object > key, V v)
IdentityMapFindResult< V > FindOrInsert(DirectHandle< Object > key)
const int size_
Definition assembler.cc:132
const MapRef map_
ZoneVector< RpoNumber > & result
void DeleteArray(T *array)
Definition allocation.h:63
#define CHECK(condition)
Definition logging.h:124
#define V8_EXPORT_PRIVATE
Definition macros.h:460
Heap * heap_
#define V8_NODISCARD
Definition v8config.h:693
std::unique_ptr< ValueMirror > key