• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
31   IdentityMapBase(const IdentityMapBase&) = delete;
32   IdentityMapBase& operator=(const IdentityMapBase&) = delete;
empty()33   bool empty() const { return size_ == 0; }
size()34   int size() const { return size_; }
capacity()35   int capacity() const { return capacity_; }
is_iterable()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 
IdentityMapBase(Heap * heap)45   explicit IdentityMapBase(Heap* heap)
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) = 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   int ScanKeysFor(Address address, uint32_t hash) const;
77   std::pair<int, bool> InsertKey(Address address, uint32_t hash);
78   int Lookup(Address key) const;
79   std::pair<int, bool> LookupOrInsert(Address key);
80   bool DeleteIndex(int index, uintptr_t* deleted_value);
81   void Rehash();
82   void Resize(int new_capacity);
83   uint32_t Hash(Address address) const;
84 
85   base::hash<uintptr_t> hasher_;
86   Heap* heap_;
87   int gc_counter_;
88   int size_;
89   int capacity_;
90   int mask_;
91   Address* keys_;
92   StrongRootsEntry* strong_roots_entry_;
93   uintptr_t* values_;
94   bool is_iterable_;
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) {}
113   IdentityMap(const IdentityMap&) = delete;
114   IdentityMap& operator=(const IdentityMap&) = delete;
~IdentityMap()115   ~IdentityMap() override { Clear(); }
116 
117   // Searches this map for the given key using the object's address
118   // as the identity, returning:
119   //    found => a pointer to the storage location for the value, true
120   //    not found => a pointer to a new storage location for the value, false
FindOrInsert(Handle<Object> key)121   IdentityMapFindResult<V> FindOrInsert(Handle<Object> key) {
122     return FindOrInsert(*key);
123   }
FindOrInsert(Object key)124   IdentityMapFindResult<V> FindOrInsert(Object key) {
125     auto raw = FindOrInsertEntry(key.ptr());
126     return {reinterpret_cast<V*>(raw.entry), raw.already_exists};
127   }
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
132   //    not found => {nullptr}
Find(Handle<Object> key)133   V* Find(Handle<Object> key) const { return Find(*key); }
Find(Object key)134   V* Find(Object key) const {
135     return reinterpret_cast<V*>(FindEntry(key.ptr()));
136   }
137 
138   // Insert the value for the given key. The key must not have previously
139   // existed.
Insert(Handle<Object> key,V v)140   void Insert(Handle<Object> key, V v) { Insert(*key, v); }
Insert(Object key,V v)141   void Insert(Object key, V v) {
142     *reinterpret_cast<V*>(InsertEntry(key.ptr())) = v;
143   }
144 
Delete(Handle<Object> key,V * deleted_value)145   bool Delete(Handle<Object> key, V* deleted_value) {
146     return Delete(*key, deleted_value);
147   }
Delete(Object key,V * deleted_value)148   bool Delete(Object key, V* deleted_value) {
149     uintptr_t v;
150     bool deleted_something = DeleteEntry(key.ptr(), &v);
151     if (deleted_value != nullptr && deleted_something) {
152       *deleted_value = *reinterpret_cast<V*>(&v);
153     }
154     return deleted_something;
155   }
156 
157   // Removes all elements from the map.
Clear()158   void Clear() { IdentityMapBase::Clear(); }
159 
160   // Iterator over IdentityMap. The IteratableScope used to create this Iterator
161   // must be live for the duration of the iteration.
162   class Iterator {
163    public:
164     Iterator& operator++() {
165       index_ = map_->NextIndex(index_);
166       return *this;
167     }
168 
key()169     Object key() const { return Object(map_->KeyAtIndex(index_)); }
entry()170     V* entry() const {
171       return reinterpret_cast<V*>(map_->EntryAtIndex(index_));
172     }
173 
174     V* operator*() { return entry(); }
175     V* operator->() { return entry(); }
176     bool operator!=(const Iterator& other) { return index_ != other.index_; }
177     bool operator==(const Iterator& other) { return index_ == other.index_; }
178 
179    private:
Iterator(IdentityMap * map,int index)180     Iterator(IdentityMap* map, int index) : map_(map), index_(index) {}
181 
182     IdentityMap* map_;
183     int index_;
184 
185     friend class IdentityMap;
186   };
187 
188   class V8_NODISCARD IteratableScope {
189    public:
IteratableScope(IdentityMap * map)190     explicit IteratableScope(IdentityMap* map) : map_(map) {
191       CHECK(!map_->is_iterable());
192       map_->EnableIteration();
193     }
194     IteratableScope(const IteratableScope&) = delete;
195     IteratableScope& operator=(const IteratableScope&) = delete;
~IteratableScope()196     ~IteratableScope() {
197       CHECK(map_->is_iterable());
198       map_->DisableIteration();
199     }
200 
begin()201     Iterator begin() { return Iterator(map_, map_->NextIndex(-1)); }
end()202     Iterator end() { return Iterator(map_, map_->capacity()); }
203 
204    private:
205     IdentityMap* map_;
206   };
207 
208  protected:
209   // This struct is just a type tag for Zone::NewArray<T>(size_t) call.
210   struct Buffer {};
211 
212   // TODO(ishell): consider removing virtual methods in favor of combining
213   // IdentityMapBase and IdentityMap into one class. This would also save
214   // space when sizeof(V) is less than sizeof(uintptr_t).
NewPointerArray(size_t length)215   uintptr_t* NewPointerArray(size_t length) override {
216     return allocator_.template NewArray<uintptr_t, Buffer>(length);
217   }
DeletePointerArray(uintptr_t * array,size_t length)218   void DeletePointerArray(uintptr_t* array, size_t length) override {
219     allocator_.template DeleteArray<uintptr_t, Buffer>(array, length);
220   }
221 
222  private:
223   AllocationPolicy allocator_;
224 };
225 
226 }  // namespace internal
227 }  // namespace v8
228 
229 #endif  // V8_UTILS_IDENTITY_MAP_H_
230