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/identity-map.h" | |
8 #include "src/zone.h" | |
9 | |
10 #include "test/cctest/cctest.h" | |
11 | |
12 namespace v8 { | |
13 namespace internal { | |
14 | |
15 // Helper for testing. A "friend" of the IdentityMapBase class, it is able to | |
16 // "move" objects to simulate GC for testing the internals of the map. | |
17 class IdentityMapTester : public HandleAndZoneScope { | |
18 public: | |
19 IdentityMap<void*> map; | |
20 | |
21 IdentityMapTester() : map(heap(), main_zone()) {} | |
22 | |
23 Heap* heap() { return isolate()->heap(); } | |
24 Isolate* isolate() { return main_isolate(); } | |
25 | |
26 void TestGetFind(Handle<Object> key1, void* val1, Handle<Object> key2, | |
27 void* val2) { | |
28 CHECK_NULL(map.Find(key1)); | |
29 CHECK_NULL(map.Find(key2)); | |
30 | |
31 // Set {key1} the first time. | |
32 void** entry = map.Get(key1); | |
33 CHECK_NOT_NULL(entry); | |
34 *entry = val1; | |
35 | |
36 for (int i = 0; i < 3; i++) { // Get and find {key1} K times. | |
37 { | |
38 void** nentry = map.Get(key1); | |
39 CHECK_EQ(entry, nentry); | |
40 CHECK_EQ(val1, *nentry); | |
41 CHECK_NULL(map.Find(key2)); | |
42 } | |
43 { | |
44 void** nentry = map.Find(key1); | |
45 CHECK_EQ(entry, nentry); | |
46 CHECK_EQ(val1, *nentry); | |
47 CHECK_NULL(map.Find(key2)); | |
48 } | |
49 } | |
50 | |
51 // Set {key2} the first time. | |
52 void** entry2 = map.Get(key2); | |
53 CHECK_NOT_NULL(entry2); | |
54 *entry2 = val2; | |
55 | |
56 for (int i = 0; i < 3; i++) { // Get and find {key1} and {key2} K times. | |
57 { | |
58 void** nentry = map.Get(key2); | |
59 CHECK_EQ(entry2, nentry); | |
60 CHECK_EQ(val2, *nentry); | |
61 } | |
62 { | |
63 void** nentry = map.Find(key2); | |
64 CHECK_EQ(entry2, nentry); | |
65 CHECK_EQ(val2, *nentry); | |
66 } | |
67 { | |
68 void** nentry = map.Find(key1); | |
69 CHECK_EQ(val1, *nentry); | |
70 } | |
71 } | |
72 } | |
73 | |
74 Handle<Smi> smi(int value) { | |
75 return Handle<Smi>(Smi::FromInt(value), isolate()); | |
76 } | |
77 | |
78 Handle<Object> num(double value) { | |
79 return isolate()->factory()->NewNumber(value); | |
80 } | |
81 | |
82 void SimulateGCByIncrementingSmisBy(int shift) { | |
83 for (int i = 0; i < map.size_; i++) { | |
84 if (map.keys_[i]->IsSmi()) { | |
85 map.keys_[i] = Smi::FromInt(Smi::cast(map.keys_[i])->value() + shift); | |
86 } | |
87 } | |
88 map.gc_counter_ = -1; | |
89 } | |
90 | |
91 void CheckFind(Handle<Object> key, void* value) { | |
92 void** entry = map.Find(key); | |
93 CHECK_NOT_NULL(entry); | |
94 CHECK_EQ(value, *entry); | |
95 } | |
96 | |
97 void CheckGet(Handle<Object> key, void* value) { | |
98 void** entry = map.Get(key); | |
99 CHECK_NOT_NULL(entry); | |
100 CHECK_EQ(value, *entry); | |
101 } | |
102 | |
103 void PrintMap() { | |
104 PrintF("{\n"); | |
105 for (int i = 0; i < map.size_; i++) { | |
106 PrintF(" %3d: %p => %p\n", i, reinterpret_cast<void*>(map.keys_[i]), | |
107 reinterpret_cast<void*>(map.values_[i])); | |
108 } | |
109 PrintF("}\n"); | |
110 } | |
111 | |
112 void Resize() { map.Resize(); } | |
113 | |
114 void Rehash() { map.Rehash(); } | |
115 }; | |
116 | |
117 | |
118 TEST(Find_smi_not_found) { | |
119 IdentityMapTester t; | |
120 for (int i = 0; i < 100; i++) { | |
121 CHECK_NULL(t.map.Find(t.smi(i))); | |
122 } | |
123 } | |
124 | |
125 | |
126 TEST(Find_num_not_found) { | |
127 IdentityMapTester t; | |
128 for (int i = 0; i < 100; i++) { | |
129 CHECK_NULL(t.map.Find(t.num(i + 0.2))); | |
130 } | |
131 } | |
132 | |
133 | |
134 TEST(GetFind_smi_13) { | |
135 IdentityMapTester t; | |
136 t.TestGetFind(t.smi(13), t.isolate(), t.smi(17), t.heap()); | |
137 } | |
138 | |
139 | |
140 TEST(GetFind_num_13) { | |
141 IdentityMapTester t; | |
142 t.TestGetFind(t.num(13.1), t.isolate(), t.num(17.1), t.heap()); | |
143 } | |
144 | |
145 | |
146 TEST(GetFind_smi_17m) { | |
147 const int kInterval = 17; | |
148 const int kShift = 1099; | |
149 IdentityMapTester t; | |
150 | |
151 for (int i = 1; i < 100; i += kInterval) { | |
152 t.map.Set(t.smi(i), reinterpret_cast<void*>(i + kShift)); | |
153 } | |
154 | |
155 for (int i = 1; i < 100; i += kInterval) { | |
156 t.CheckFind(t.smi(i), reinterpret_cast<void*>(i + kShift)); | |
157 } | |
158 | |
159 for (int i = 1; i < 100; i += kInterval) { | |
160 t.CheckGet(t.smi(i), reinterpret_cast<void*>(i + kShift)); | |
161 } | |
162 | |
163 for (int i = 1; i < 100; i++) { | |
164 void** entry = t.map.Find(t.smi(i)); | |
165 if ((i % kInterval) != 1) { | |
166 CHECK_NULL(entry); | |
167 } else { | |
168 CHECK_NOT_NULL(entry); | |
169 CHECK_EQ(reinterpret_cast<void*>(i + kShift), *entry); | |
170 } | |
171 } | |
172 } | |
173 | |
174 | |
175 TEST(GetFind_num_1000) { | |
176 const int kPrime = 137; | |
177 IdentityMapTester t; | |
178 int val1; | |
179 int val2; | |
180 | |
181 for (int i = 1; i < 1000; i++) { | |
182 t.TestGetFind(t.smi(i * kPrime), &val1, t.smi(i * kPrime + 1), &val2); | |
183 } | |
184 } | |
185 | |
186 | |
187 TEST(GetFind_smi_gc) { | |
188 const int kKey = 33; | |
189 const int kShift = 1211; | |
190 IdentityMapTester t; | |
191 | |
192 t.map.Set(t.smi(kKey), &t); | |
193 t.SimulateGCByIncrementingSmisBy(kShift); | |
194 t.CheckFind(t.smi(kKey + kShift), &t); | |
195 t.CheckGet(t.smi(kKey + kShift), &t); | |
196 } | |
197 | |
198 | |
199 TEST(GetFind_smi_gc2) { | |
200 int kKey1 = 1; | |
201 int kKey2 = 33; | |
202 const int kShift = 1211; | |
203 IdentityMapTester t; | |
204 | |
205 t.map.Set(t.smi(kKey1), &kKey1); | |
206 t.map.Set(t.smi(kKey2), &kKey2); | |
207 t.SimulateGCByIncrementingSmisBy(kShift); | |
208 t.CheckFind(t.smi(kKey1 + kShift), &kKey1); | |
209 t.CheckGet(t.smi(kKey1 + kShift), &kKey1); | |
210 t.CheckFind(t.smi(kKey2 + kShift), &kKey2); | |
211 t.CheckGet(t.smi(kKey2 + kShift), &kKey2); | |
212 } | |
213 | |
214 | |
215 TEST(GetFind_smi_gc_n) { | |
216 const int kShift = 12011; | |
217 IdentityMapTester t; | |
218 int keys[12] = {1, 2, 7, 8, 15, 23, | |
219 1 + 32, 2 + 32, 7 + 32, 8 + 32, 15 + 32, 23 + 32}; | |
220 // Initialize the map first. | |
221 for (size_t i = 0; i < arraysize(keys); i += 2) { | |
222 t.TestGetFind(t.smi(keys[i]), &keys[i], t.smi(keys[i + 1]), &keys[i + 1]); | |
223 } | |
224 // Check the above initialization. | |
225 for (size_t i = 0; i < arraysize(keys); i++) { | |
226 t.CheckFind(t.smi(keys[i]), &keys[i]); | |
227 } | |
228 // Simulate a GC by "moving" the smis in the internal keys array. | |
229 t.SimulateGCByIncrementingSmisBy(kShift); | |
230 // Check that searching for the incremented smis finds the same values. | |
231 for (size_t i = 0; i < arraysize(keys); i++) { | |
232 t.CheckFind(t.smi(keys[i] + kShift), &keys[i]); | |
233 } | |
234 // Check that searching for the incremented smis gets the same values. | |
235 for (size_t i = 0; i < arraysize(keys); i++) { | |
236 t.CheckGet(t.smi(keys[i] + kShift), &keys[i]); | |
237 } | |
238 } | |
239 | |
240 | |
241 TEST(GetFind_smi_num_gc_n) { | |
242 const int kShift = 12019; | |
243 IdentityMapTester t; | |
244 int smi_keys[] = {1, 2, 7, 15, 23}; | |
245 Handle<Object> num_keys[] = {t.num(1.1), t.num(2.2), t.num(3.3), t.num(4.4), | |
246 t.num(5.5), t.num(6.6), t.num(7.7), t.num(8.8), | |
247 t.num(9.9), t.num(10.1)}; | |
248 // Initialize the map first. | |
249 for (size_t i = 0; i < arraysize(smi_keys); i++) { | |
250 t.map.Set(t.smi(smi_keys[i]), &smi_keys[i]); | |
251 } | |
252 for (size_t i = 0; i < arraysize(num_keys); i++) { | |
253 t.map.Set(num_keys[i], &num_keys[i]); | |
254 } | |
255 // Check the above initialization. | |
256 for (size_t i = 0; i < arraysize(smi_keys); i++) { | |
257 t.CheckFind(t.smi(smi_keys[i]), &smi_keys[i]); | |
258 } | |
259 for (size_t i = 0; i < arraysize(num_keys); i++) { | |
260 t.CheckFind(num_keys[i], &num_keys[i]); | |
261 } | |
262 | |
263 // Simulate a GC by moving SMIs. | |
264 // Ironically the SMIs "move", but the heap numbers don't! | |
265 t.SimulateGCByIncrementingSmisBy(kShift); | |
266 | |
267 // Check that searching for the incremented smis finds the same values. | |
268 for (size_t i = 0; i < arraysize(smi_keys); i++) { | |
269 t.CheckFind(t.smi(smi_keys[i] + kShift), &smi_keys[i]); | |
270 t.CheckGet(t.smi(smi_keys[i] + kShift), &smi_keys[i]); | |
271 } | |
272 | |
273 // Check that searching for the numbers finds the same values. | |
274 for (size_t i = 0; i < arraysize(num_keys); i++) { | |
275 t.CheckFind(num_keys[i], &num_keys[i]); | |
276 t.CheckGet(num_keys[i], &num_keys[i]); | |
277 } | |
278 } | |
279 | |
280 | |
281 void CollisionTest(int stride, bool rehash = false, bool resize = false) { | |
282 for (int load = 15; load <= 120; load = load * 2) { | |
283 IdentityMapTester t; | |
284 | |
285 { // Add entries to the map. | |
286 HandleScope scope(t.isolate()); | |
287 int next = 1; | |
288 for (int i = 0; i < load; i++) { | |
289 t.map.Set(t.smi(next), reinterpret_cast<void*>(next)); | |
290 t.CheckFind(t.smi(next), reinterpret_cast<void*>(next)); | |
291 next = next + stride; | |
292 } | |
293 } | |
294 if (resize) t.Resize(); // Explicit resize (internal method). | |
295 if (rehash) t.Rehash(); // Explicit rehash (internal method). | |
296 { // Check find and get. | |
297 HandleScope scope(t.isolate()); | |
298 int next = 1; | |
299 for (int i = 0; i < load; i++) { | |
300 t.CheckFind(t.smi(next), reinterpret_cast<void*>(next)); | |
301 t.CheckGet(t.smi(next), reinterpret_cast<void*>(next)); | |
302 next = next + stride; | |
303 } | |
304 } | |
305 } | |
306 } | |
307 | |
308 | |
309 TEST(Collisions_1) { CollisionTest(1); } | |
310 TEST(Collisions_2) { CollisionTest(2); } | |
311 TEST(Collisions_3) { CollisionTest(3); } | |
312 TEST(Collisions_5) { CollisionTest(5); } | |
313 TEST(Collisions_7) { CollisionTest(7); } | |
314 TEST(Resize) { CollisionTest(9, false, true); } | |
315 TEST(Rehash) { CollisionTest(11, true, false); } | |
316 | |
317 | |
318 TEST(ExplicitGC) { | |
319 IdentityMapTester t; | |
320 Handle<Object> num_keys[] = {t.num(2.1), t.num(2.4), t.num(3.3), t.num(4.3), | |
321 t.num(7.5), t.num(6.4), t.num(7.3), t.num(8.3), | |
322 t.num(8.9), t.num(10.4)}; | |
323 | |
324 // Insert some objects that should be in new space. | |
325 for (size_t i = 0; i < arraysize(num_keys); i++) { | |
326 t.map.Set(num_keys[i], &num_keys[i]); | |
327 } | |
328 | |
329 // Do an explicit, real GC. | |
330 t.heap()->CollectGarbage(i::NEW_SPACE); | |
Hannes Payer (out of office)
2015/04/27 15:06:32
Let's also write another test where these objects
| |
331 | |
332 // Check that searching for the numbers finds the same values. | |
333 for (size_t i = 0; i < arraysize(num_keys); i++) { | |
334 t.CheckFind(num_keys[i], &num_keys[i]); | |
335 t.CheckGet(num_keys[i], &num_keys[i]); | |
336 } | |
337 } | |
338 } | |
339 } | |
OLD | NEW |