• 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:
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