OLD | NEW |
---|---|
(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 if (concurrent_) heap_->relocation_mutex()->Lock(); | |
Benedikt Meurer
2015/04/27 04:04:17
How about a simple helper class like this:
namesp
titzer
2015/04/27 10:43:03
Done.
I've made one in the Heap called OptionalRe
| |
18 heap_->UnregisterStrongRoots(keys_); | |
19 if (concurrent_) heap_->relocation_mutex()->Unlock(); | |
20 } | |
21 } | |
22 | |
23 | |
24 int IdentityMapBase::LookupIndex(Object* address) { | |
25 int start = Hash(address) & mask_; | |
26 for (int index = start; index < size_; index++) { | |
27 if (keys_[index] == address) return index; // found | |
28 if (keys_[index] == nullptr) return -1; // not found | |
29 } | |
30 for (int index = 0; index < start; index++) { | |
31 if (keys_[index] == address) return index; // found | |
32 if (keys_[index] == nullptr) return -1; // not found | |
33 } | |
34 return -1; | |
35 } | |
36 | |
37 | |
38 int IdentityMapBase::InsertIndex(Object* address) { | |
39 while (true) { | |
40 int start = Hash(address) & mask_; | |
41 int limit = size_ / 2; | |
42 for (int index = start; index < size_; index++) { | |
43 if (keys_[index] == address) return index; // found | |
44 if (keys_[index] == nullptr) { // free entry | |
45 keys_[index] = address; | |
46 return index; | |
47 } | |
48 if (--limit == 0) break; // searched too far; resize to insert. | |
49 } | |
50 Resize(); // Should only have to resize once, since we grow 4x. | |
Hannes Payer (out of office)
2015/04/27 15:06:32
Let's assert that we just resize once.
titzer
2015/04/27 16:32:50
Resize() will fail if it gets too big. Should I co
| |
51 } | |
52 UNREACHABLE(); | |
53 return -1; | |
54 } | |
55 | |
56 | |
57 // Searches this map for the given key using the object's address | |
58 // as the identity, returning: | |
59 // found => a pointer to the storage location for the value | |
60 // not found => a pointer to a new storage location for the value | |
61 IdentityMapBase::RawEntry IdentityMapBase::GetEntry(Handle<Object> handle) { | |
62 if (concurrent_) heap_->relocation_mutex()->Lock(); | |
63 RawEntry result; | |
64 if (size_ == 0) { | |
65 // Allocate the initial storage for keys and values. | |
66 size_ = kInitialIdentityMapSize; | |
67 mask_ = kInitialIdentityMapSize - 1; | |
68 gc_counter_ = heap_->gc_count(); | |
69 | |
70 keys_ = zone_->NewArray<Object*>(size_); | |
71 memset(keys_, 0, sizeof(Object*) * size_); | |
72 values_ = zone_->NewArray<void*>(size_); | |
73 memset(values_, 0, sizeof(void*) * size_); | |
74 | |
75 heap_->RegisterStrongRoots(keys_, keys_ + size_); | |
76 result = Insert(handle); | |
77 } else { | |
78 // Perform an optimistic lookup. | |
79 result = Lookup(handle); | |
80 if (result == nullptr) { | |
81 // Miss; rehash if there was a GC, then insert. | |
82 if (gc_counter_ != heap_->gc_count()) Rehash(); | |
83 result = Insert(handle); | |
84 } | |
85 } | |
86 if (concurrent_) heap_->relocation_mutex()->Unlock(); | |
87 return result; | |
88 } | |
89 | |
90 | |
91 // Searches this map for the given key using the object's address | |
92 // as the identity, returning: | |
93 // found => a pointer to the storage location for the value | |
94 // not found => {nullptr} | |
95 IdentityMapBase::RawEntry IdentityMapBase::FindEntry(Handle<Object> handle) { | |
96 if (size_ == 0) return nullptr; | |
97 | |
98 if (concurrent_) heap_->relocation_mutex()->Lock(); | |
99 RawEntry result = Lookup(handle); | |
100 if (result == nullptr && gc_counter_ != heap_->gc_count()) { | |
101 Rehash(); // Rehash is expensive, so only do it in case of a miss. | |
102 result = Lookup(handle); | |
103 } | |
104 if (concurrent_) heap_->relocation_mutex()->Unlock(); | |
105 return result; | |
106 } | |
107 | |
108 | |
109 void IdentityMapBase::Rehash() { | |
110 // Record the current GC counter. | |
111 gc_counter_ = heap_->gc_count(); | |
112 // Assume that most objects won't be moved. | |
113 ZoneVector<std::pair<Object*, void*>> reinsert(zone_); | |
114 // Search the table looking for keys that wouldn't be found with their | |
115 // current hashcode and evacuate them. | |
116 int last_empty = -1; | |
117 for (int i = 0; i < size_; i++) { | |
118 if (keys_[i] == nullptr) { | |
119 last_empty = i; | |
120 } else { | |
121 int pos = Hash(keys_[i]) & mask_; | |
122 if (pos <= last_empty || pos > i) { | |
123 // Evacuate an entry that is in the wrong place. | |
124 reinsert.push_back(std::pair<Object*, void*>(keys_[i], values_[i])); | |
125 keys_[i] = nullptr; | |
126 values_[i] = nullptr; | |
127 last_empty = i; | |
128 } | |
129 } | |
130 } | |
131 // Reinsert all the key/value pairs that were in the wrong place. | |
132 for (auto pair : reinsert) { | |
133 int index = InsertIndex(pair.first); | |
134 DCHECK_GE(index, 0); | |
135 DCHECK_NULL(values_[index]); | |
136 values_[index] = pair.second; | |
137 } | |
138 } | |
139 | |
140 | |
141 void IdentityMapBase::Resize() { | |
142 // Grow the internal storage and reinsert all the key/value pairs. | |
143 int old_size = size_; | |
144 Object** old_keys = keys_; | |
145 void** old_values = values_; | |
146 | |
147 size_ = size_ * 4; | |
148 mask_ = size_ - 1; | |
149 gc_counter_ = heap_->gc_count(); | |
150 | |
151 CHECK_LE(size_, (1024 * 1024 * 16)); // that would be extreme... | |
152 | |
153 keys_ = zone_->NewArray<Object*>(size_); | |
154 memset(keys_, 0, sizeof(Object*) * size_); | |
155 values_ = zone_->NewArray<void*>(size_); | |
156 memset(values_, 0, sizeof(void*) * size_); | |
157 | |
158 for (int i = 0; i < old_size; i++) { | |
159 if (old_keys[i] == nullptr) continue; | |
160 int index = InsertIndex(old_keys[i]); | |
161 DCHECK_GE(index, 0); | |
162 values_[index] = old_values[i]; | |
163 } | |
164 | |
165 // Unregister old keys and register new keys. | |
166 heap_->UnregisterStrongRoots(old_keys); | |
167 heap_->RegisterStrongRoots(keys_, keys_ + size_); | |
168 } | |
169 } | |
170 } // namespace v8::internal | |
OLD | NEW |