Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(598)

Side by Side Diff: src/heap/identity-map.cc

Issue 1105693002: Implement IdentityMap<V>, a robust, GC-safe object-identity HashMap. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 #include "src/v8.h"
6
7 #include "src/heap/heap.h"
8 #include "src/heap/identity-map.h"
9
10 namespace v8 {
11 namespace internal {
12
13 static const int kInitialIdentityMapSize = 32;
14
15 IdentityMapBase::~IdentityMapBase() {
16 if (keys_) {
17 Heap::OptionalRelocationLock lock(heap_, concurrent_);
18 heap_->UnregisterStrongRoots(keys_);
19 }
20 }
21
22
23 IdentityMapBase::RawEntry IdentityMapBase::Lookup(Handle<Object> handle) {
24 AllowHandleDereference for_lookup;
25 int index = LookupIndex(*handle);
26 return index >= 0 ? &values_[index] : nullptr;
27 }
28
29
30 IdentityMapBase::RawEntry IdentityMapBase::Insert(Handle<Object> handle) {
31 AllowHandleDereference for_lookup;
32 int index = InsertIndex(*handle);
33 DCHECK_GE(index, 0);
34 return &values_[index];
35 }
36
37
38 int IdentityMapBase::Hash(Object* address) {
39 uintptr_t raw_address = reinterpret_cast<uintptr_t>(address);
40 CHECK_NE(0, raw_address); // cannot store Smi 0 as a key here, sorry.
Hannes Payer (out of office) 2015/04/27 15:06:32 Cannot
titzer 2015/04/27 16:32:50 Done.
41 // xor some of the upper bits, since the lower 2 or 3 are usually aligned.
Erik Corry 2015/04/27 15:39:13 Xor Also see comments below with missing caps and
titzer 2015/04/27 16:32:50 Done.
42 return static_cast<int>((raw_address >> 11) ^ raw_address);
43 }
44
45
46 int IdentityMapBase::LookupIndex(Object* address) {
47 int start = Hash(address) & mask_;
48 for (int index = start; index < size_; index++) {
49 if (keys_[index] == address) return index; // found
50 if (keys_[index] == nullptr) return -1; // not found
51 }
52 for (int index = 0; index < start; index++) {
53 if (keys_[index] == address) return index; // found
54 if (keys_[index] == nullptr) return -1; // not found
55 }
56 return -1;
57 }
58
59
60 int IdentityMapBase::InsertIndex(Object* address) {
61 while (true) {
62 int start = Hash(address) & mask_;
63 int limit = size_ / 2;
64 for (int index = start; index < size_; index++) {
Erik Corry 2015/04/27 15:39:13 For hashes that are near the end of the array we w
titzer 2015/04/27 16:32:51 Good catch. I wrap the search now.
65 if (keys_[index] == address) return index; // found
66 if (keys_[index] == nullptr) { // free entry
67 keys_[index] = address;
68 return index;
69 }
70 if (--limit == 0) break; // searched too far; resize to insert.
Hannes Payer (out of office) 2015/04/27 15:06:32 Searched
titzer 2015/04/27 16:32:51 Done.
71 }
72 Resize(); // Should only have to resize once, since we grow 4x.
Hannes Payer (out of office) 2015/04/27 15:06:32 4 = kResizeFactor
Erik Corry 2015/04/27 15:39:13 That's very aggressive. Was 2x too slow? Also thi
titzer 2015/04/27 16:32:50 4x guarantees that there are no chains that size_
Erik Corry 2015/04/28 09:32:34 Rather than cuckoo I would go with Robin Hood hash
73 }
74 UNREACHABLE();
75 return -1;
76 }
77
78
79 // Searches this map for the given key using the object's address
80 // as the identity, returning:
81 // found => a pointer to the storage location for the value
82 // not found => a pointer to a new storage location for the value
83 IdentityMapBase::RawEntry IdentityMapBase::GetEntry(Handle<Object> handle) {
84 Heap::OptionalRelocationLock lock(heap_, concurrent_);
85 RawEntry result;
86 if (size_ == 0) {
87 // Allocate the initial storage for keys and values.
88 size_ = kInitialIdentityMapSize;
89 mask_ = kInitialIdentityMapSize - 1;
90 gc_counter_ = heap_->gc_count();
91
92 keys_ = zone_->NewArray<Object*>(size_);
93 memset(keys_, 0, sizeof(Object*) * size_);
94 values_ = zone_->NewArray<void*>(size_);
95 memset(values_, 0, sizeof(void*) * size_);
96
97 heap_->RegisterStrongRoots(keys_, keys_ + size_);
98 result = Insert(handle);
99 } else {
100 // Perform an optimistic lookup.
101 result = Lookup(handle);
102 if (result == nullptr) {
103 // Miss; rehash if there was a GC, then insert.
104 if (gc_counter_ != heap_->gc_count()) Rehash();
105 result = Insert(handle);
106 }
107 }
108 return result;
109 }
110
111
112 // Searches this map for the given key using the object's address
113 // as the identity, returning:
114 // found => a pointer to the storage location for the value
115 // not found => {nullptr}
116 IdentityMapBase::RawEntry IdentityMapBase::FindEntry(Handle<Object> handle) {
117 if (size_ == 0) return nullptr;
118
119 Heap::OptionalRelocationLock lock(heap_, concurrent_);
120 RawEntry result = Lookup(handle);
121 if (result == nullptr && gc_counter_ != heap_->gc_count()) {
122 Rehash(); // Rehash is expensive, so only do it in case of a miss.
123 result = Lookup(handle);
124 }
125 return result;
126 }
127
128
129 void IdentityMapBase::Rehash() {
Hannes Payer (out of office) 2015/04/27 15:06:32 Can we assert here that we have the relocation loc
titzer 2015/04/27 16:32:50 Unfortunately that API appears to have been refact
130 // Record the current GC counter.
131 gc_counter_ = heap_->gc_count();
132 // Assume that most objects won't be moved.
133 ZoneVector<std::pair<Object*, void*>> reinsert(zone_);
134 // Search the table looking for keys that wouldn't be found with their
135 // current hashcode and evacuate them.
136 int last_empty = -1;
137 for (int i = 0; i < size_; i++) {
138 if (keys_[i] == nullptr) {
139 last_empty = i;
140 } else {
141 int pos = Hash(keys_[i]) & mask_;
142 if (pos <= last_empty || pos > i) {
143 // Evacuate an entry that is in the wrong place.
144 reinsert.push_back(std::pair<Object*, void*>(keys_[i], values_[i]));
145 keys_[i] = nullptr;
146 values_[i] = nullptr;
147 last_empty = i;
148 }
149 }
150 }
151 // Reinsert all the key/value pairs that were in the wrong place.
152 for (auto pair : reinsert) {
153 int index = InsertIndex(pair.first);
154 DCHECK_GE(index, 0);
155 DCHECK_NULL(values_[index]);
156 values_[index] = pair.second;
157 }
158 }
159
160
161 void IdentityMapBase::Resize() {
162 // Grow the internal storage and reinsert all the key/value pairs.
163 int old_size = size_;
164 Object** old_keys = keys_;
165 void** old_values = values_;
166
167 size_ = size_ * 4;
Hannes Payer (out of office) 2015/04/27 15:06:32 4 = kResizeFactor; make this a constant
titzer 2015/04/27 16:32:50 Done.
168 mask_ = size_ - 1;
169 gc_counter_ = heap_->gc_count();
170
171 CHECK_LE(size_, (1024 * 1024 * 16)); // that would be extreme...
172
173 keys_ = zone_->NewArray<Object*>(size_);
174 memset(keys_, 0, sizeof(Object*) * size_);
175 values_ = zone_->NewArray<void*>(size_);
176 memset(values_, 0, sizeof(void*) * size_);
177
178 for (int i = 0; i < old_size; i++) {
179 if (old_keys[i] == nullptr) continue;
180 int index = InsertIndex(old_keys[i]);
181 DCHECK_GE(index, 0);
182 values_[index] = old_values[i];
183 }
184
185 // Unregister old keys and register new keys.
186 heap_->UnregisterStrongRoots(old_keys);
187 heap_->RegisterStrongRoots(keys_, keys_ + size_);
188 }
189 }
190 } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698