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

Side by Side Diff: src/collection.js

Issue 1149863005: Move hash code from hidden string to a private symbol (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix global object hash code. This eated about 5% of weak collection performance Created 5 years, 7 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
« no previous file with comments | « src/api.cc ('k') | src/factory.h » ('j') | src/math.js » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 var $gethash;
adamk 2015/05/21 19:11:32 Rename to $getHash
Erik Corry 2015/05/22 06:20:24 Done.
6 var $getexistinghash;
adamk 2015/05/21 19:11:32 and $getExistingHash
Erik Corry 2015/05/22 06:20:24 Done.
7
5 (function(global, shared, exports) { 8 (function(global, shared, exports) {
6 9
7 "use strict"; 10 "use strict";
8 11
9 %CheckIsBootstrapping(); 12 %CheckIsBootstrapping();
10 13
11 var GlobalMap = global.Map; 14 var GlobalMap = global.Map;
12 var GlobalObject = global.Object; 15 var GlobalObject = global.Object;
13 var GlobalSet = global.Set; 16 var GlobalSet = global.Set;
14 17
15 // ------------------------------------------------------------------- 18 // -------------------------------------------------------------------
16 19
17 function HashToEntry(table, hash, numBuckets) { 20 function HashToEntry(table, hash, numBuckets) {
18 var bucket = ORDERED_HASH_TABLE_HASH_TO_BUCKET(hash, numBuckets); 21 var bucket = ORDERED_HASH_TABLE_HASH_TO_BUCKET(hash, numBuckets);
19 return ORDERED_HASH_TABLE_BUCKET_AT(table, bucket); 22 return ORDERED_HASH_TABLE_BUCKET_AT(table, bucket);
20 } 23 }
21 %SetInlineBuiltinFlag(HashToEntry); 24 %SetInlineBuiltinFlag(HashToEntry);
22 25
23 26
24 function SetFindEntry(table, numBuckets, key, hash) { 27 function SetFindEntry(table, numBuckets, key, hash) {
28 var entry = HashToEntry(table, hash, numBuckets);
29 if (entry === NOT_FOUND) return entry;
30 var candidate = ORDERED_HASH_SET_KEY_AT(table, entry, numBuckets);
31 if (key === candidate) return entry;
25 var keyIsNaN = $numberIsNaN(key); 32 var keyIsNaN = $numberIsNaN(key);
26 for (var entry = HashToEntry(table, hash, numBuckets); 33 while (true) {
adamk 2015/05/21 19:11:32 Why did this get rewritten as a while loop? From m
Erik Corry 2015/05/21 20:19:01 The idea is to avoid testing the key for Nan-ness
27 entry !== NOT_FOUND;
28 entry = ORDERED_HASH_SET_CHAIN_AT(table, entry, numBuckets)) {
29 var candidate = ORDERED_HASH_SET_KEY_AT(table, entry, numBuckets);
30 if (key === candidate) {
31 return entry;
32 }
33 if (keyIsNaN && $numberIsNaN(candidate)) { 34 if (keyIsNaN && $numberIsNaN(candidate)) {
34 return entry; 35 return entry;
35 } 36 }
37 entry = ORDERED_HASH_SET_CHAIN_AT(table, entry, numBuckets);
38 if (entry === NOT_FOUND) return entry;
39 candidate = ORDERED_HASH_SET_KEY_AT(table, entry, numBuckets);
40 if (key === candidate) return entry;
36 } 41 }
37 return NOT_FOUND; 42 return NOT_FOUND;
38 } 43 }
39 %SetInlineBuiltinFlag(SetFindEntry); 44 %SetInlineBuiltinFlag(SetFindEntry);
40 45
41 46
42 function MapFindEntry(table, numBuckets, key, hash) { 47 function MapFindEntry(table, numBuckets, key, hash) {
48 var entry = HashToEntry(table, hash, numBuckets);
49 if (entry === NOT_FOUND) return entry;
50 var candidate = ORDERED_HASH_MAP_KEY_AT(table, entry, numBuckets);
51 if (key === candidate) return entry;
43 var keyIsNaN = $numberIsNaN(key); 52 var keyIsNaN = $numberIsNaN(key);
44 for (var entry = HashToEntry(table, hash, numBuckets); 53 while (true) {
adamk 2015/05/21 19:11:32 Same question down here.
Erik Corry 2015/05/21 20:19:01 Same answer :-)
45 entry !== NOT_FOUND;
46 entry = ORDERED_HASH_MAP_CHAIN_AT(table, entry, numBuckets)) {
47 var candidate = ORDERED_HASH_MAP_KEY_AT(table, entry, numBuckets);
48 if (key === candidate) {
49 return entry;
50 }
51 if (keyIsNaN && $numberIsNaN(candidate)) { 54 if (keyIsNaN && $numberIsNaN(candidate)) {
52 return entry; 55 return entry;
53 } 56 }
57 entry = ORDERED_HASH_MAP_CHAIN_AT(table, entry, numBuckets);
58 if (entry === NOT_FOUND) return entry;
59 candidate = ORDERED_HASH_MAP_KEY_AT(table, entry, numBuckets);
60 if (key === candidate) return entry;
54 } 61 }
55 return NOT_FOUND; 62 return NOT_FOUND;
56 } 63 }
57 %SetInlineBuiltinFlag(MapFindEntry); 64 %SetInlineBuiltinFlag(MapFindEntry);
58 65
59 66
60 function ComputeIntegerHash(key, seed) { 67 function ComputeIntegerHash(key, seed) {
61 var hash = key; 68 var hash = key;
62 hash = hash ^ seed; 69 hash = hash ^ seed;
63 hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1; 70 hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1;
64 hash = hash ^ (hash >>> 12); 71 hash = hash ^ (hash >>> 12);
65 hash = hash + (hash << 2); 72 hash = hash + (hash << 2);
66 hash = hash ^ (hash >>> 4); 73 hash = hash ^ (hash >>> 4);
67 hash = (hash * 2057) | 0; // hash = (hash + (hash << 3)) + (hash << 11); 74 hash = (hash * 2057) | 0; // hash = (hash + (hash << 3)) + (hash << 11);
68 hash = hash ^ (hash >>> 16); 75 hash = hash ^ (hash >>> 16);
69 return hash; 76 return hash & 0x3fffffff;
adamk 2015/05/21 19:11:32 Why the extra &? This used to be equivalent to Com
Erik Corry 2015/05/22 06:20:24 To make sure it's always a Smi. I changed Compute
70 } 77 }
71 %SetInlineBuiltinFlag(ComputeIntegerHash); 78 %SetInlineBuiltinFlag(ComputeIntegerHash);
72 79
80 var hash_code_symbol = GLOBAL_PRIVATE("hash_code_symbol");
adamk 2015/05/21 19:11:32 Please use JS style here ("hashCodeSymbol").
Erik Corry 2015/05/22 06:20:24 Done.
73 81
74 function GetHash(key) { 82 function GetExistingHash(key) {
75 if (%_IsSmi(key)) { 83 if (%_IsSmi(key)) {
76 return ComputeIntegerHash(key, 0); 84 return ComputeIntegerHash(key, 0);
77 } 85 }
78 if (IS_STRING(key)) { 86 if (IS_STRING(key)) {
79 var field = %_StringGetRawHashField(key); 87 var field = %_StringGetRawHashField(key);
80 if ((field & 1 /* Name::kHashNotComputedMask */) === 0) { 88 if ((field & 1 /* Name::kHashNotComputedMask */) === 0) {
81 return field >>> 2 /* Name::kHashShift */; 89 return field >>> 2 /* Name::kHashShift */;
82 } 90 }
91 } else if (IS_SPEC_OBJECT(key) && !%_IsJSProxy(key) && !IS_GLOBAL(key)) {
92 var hash = GET_PRIVATE(key, hash_code_symbol);
93 return hash;
83 } 94 }
84 return %GenericHash(key); 95 return %GenericHash(key);
adamk 2015/05/21 19:11:32 %GenericHash calls GetOrCreateHash, which seems wr
Erik Corry 2015/05/21 20:19:02 I think we don't care much about this case, it's o
85 } 96 }
97 %SetInlineBuiltinFlag(GetExistingHash);
98
99
100 function GetHash(key) {
101 var hash = GetExistingHash(key);
102 if (IS_UNDEFINED(hash)) {
103 if (IS_GLOBAL(key)) {
adamk 2015/05/21 19:11:32 I think this branch is currently unreachable due t
Erik Corry 2015/05/21 20:19:02 Good point. I think a better solution would be fo
104 return %GenericHash(key);
105 }
106 hash = $intrandom() | 0;
107 if (hash === 0) hash = 1;
108 SET_PRIVATE(key, hash_code_symbol, hash);
109 }
110 return hash;
111 }
86 %SetInlineBuiltinFlag(GetHash); 112 %SetInlineBuiltinFlag(GetHash);
87 113
88 114
89 // ------------------------------------------------------------------- 115 // -------------------------------------------------------------------
90 // Harmony Set 116 // Harmony Set
91 117
92 function SetConstructor(iterable) { 118 function SetConstructor(iterable) {
93 if (!%_IsConstructCall()) { 119 if (!%_IsConstructCall()) {
94 throw MakeTypeError(kConstructorNotFunction, "Set"); 120 throw MakeTypeError(kConstructorNotFunction, "Set");
95 } 121 }
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 return this; 174 return this;
149 } 175 }
150 176
151 177
152 function SetHas(key) { 178 function SetHas(key) {
153 if (!IS_SET(this)) { 179 if (!IS_SET(this)) {
154 throw MakeTypeError(kIncompatibleMethodReceiver, 'Set.prototype.has', this); 180 throw MakeTypeError(kIncompatibleMethodReceiver, 'Set.prototype.has', this);
155 } 181 }
156 var table = %_JSCollectionGetTable(this); 182 var table = %_JSCollectionGetTable(this);
157 var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT(table); 183 var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT(table);
158 var hash = GetHash(key); 184 var hash = GetExistingHash(key);
185 if (IS_UNDEFINED(hash)) return false;
159 return SetFindEntry(table, numBuckets, key, hash) !== NOT_FOUND; 186 return SetFindEntry(table, numBuckets, key, hash) !== NOT_FOUND;
160 } 187 }
161 188
162 189
163 function SetDelete(key) { 190 function SetDelete(key) {
164 if (!IS_SET(this)) { 191 if (!IS_SET(this)) {
165 throw MakeTypeError(kIncompatibleMethodReceiver, 192 throw MakeTypeError(kIncompatibleMethodReceiver,
166 'Set.prototype.delete', this); 193 'Set.prototype.delete', this);
167 } 194 }
168 var table = %_JSCollectionGetTable(this); 195 var table = %_JSCollectionGetTable(this);
169 var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT(table); 196 var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT(table);
170 var hash = GetHash(key); 197 var hash = GetExistingHash(key);
198 if (IS_UNDEFINED(hash)) return false;
171 var entry = SetFindEntry(table, numBuckets, key, hash); 199 var entry = SetFindEntry(table, numBuckets, key, hash);
172 if (entry === NOT_FOUND) return false; 200 if (entry === NOT_FOUND) return false;
173 201
174 var nof = ORDERED_HASH_TABLE_ELEMENT_COUNT(table) - 1; 202 var nof = ORDERED_HASH_TABLE_ELEMENT_COUNT(table) - 1;
175 var nod = ORDERED_HASH_TABLE_DELETED_COUNT(table) + 1; 203 var nod = ORDERED_HASH_TABLE_DELETED_COUNT(table) + 1;
176 var index = ORDERED_HASH_SET_ENTRY_TO_INDEX(entry, numBuckets); 204 var index = ORDERED_HASH_SET_ENTRY_TO_INDEX(entry, numBuckets);
177 FIXED_ARRAY_SET(table, index, %_TheHole()); 205 FIXED_ARRAY_SET(table, index, %_TheHole());
178 ORDERED_HASH_TABLE_SET_ELEMENT_COUNT(table, nof); 206 ORDERED_HASH_TABLE_SET_ELEMENT_COUNT(table, nof);
179 ORDERED_HASH_TABLE_SET_DELETED_COUNT(table, nod); 207 ORDERED_HASH_TABLE_SET_DELETED_COUNT(table, nod);
180 if (nof < (numBuckets >>> 1)) %SetShrink(this); 208 if (nof < (numBuckets >>> 1)) %SetShrink(this);
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 } 303 }
276 304
277 305
278 function MapGet(key) { 306 function MapGet(key) {
279 if (!IS_MAP(this)) { 307 if (!IS_MAP(this)) {
280 throw MakeTypeError(kIncompatibleMethodReceiver, 308 throw MakeTypeError(kIncompatibleMethodReceiver,
281 'Map.prototype.get', this); 309 'Map.prototype.get', this);
282 } 310 }
283 var table = %_JSCollectionGetTable(this); 311 var table = %_JSCollectionGetTable(this);
284 var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT(table); 312 var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT(table);
285 var hash = GetHash(key); 313 var hash = GetExistingHash(key);
314 if (IS_UNDEFINED(hash)) return UNDEFINED;
286 var entry = MapFindEntry(table, numBuckets, key, hash); 315 var entry = MapFindEntry(table, numBuckets, key, hash);
287 if (entry === NOT_FOUND) return UNDEFINED; 316 if (entry === NOT_FOUND) return UNDEFINED;
288 return ORDERED_HASH_MAP_VALUE_AT(table, entry, numBuckets); 317 return ORDERED_HASH_MAP_VALUE_AT(table, entry, numBuckets);
289 } 318 }
290 319
291 320
292 function MapSet(key, value) { 321 function MapSet(key, value) {
293 if (!IS_MAP(this)) { 322 if (!IS_MAP(this)) {
294 throw MakeTypeError(kIncompatibleMethodReceiver, 323 throw MakeTypeError(kIncompatibleMethodReceiver,
295 'Map.prototype.set', this); 324 'Map.prototype.set', this);
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 $installGetter(GlobalMap.prototype, "size", MapGetSize); 459 $installGetter(GlobalMap.prototype, "size", MapGetSize);
431 $installFunctions(GlobalMap.prototype, DONT_ENUM, [ 460 $installFunctions(GlobalMap.prototype, DONT_ENUM, [
432 "get", MapGet, 461 "get", MapGet,
433 "set", MapSet, 462 "set", MapSet,
434 "has", MapHas, 463 "has", MapHas,
435 "delete", MapDelete, 464 "delete", MapDelete,
436 "clear", MapClearJS, 465 "clear", MapClearJS,
437 "forEach", MapForEach 466 "forEach", MapForEach
438 ]); 467 ]);
439 468
469 // Expose to the global scope.
470 $gethash = GetHash;
471 $getexistinghash = GetExistingHash;
472
440 }) 473 })
OLDNEW
« no previous file with comments | « src/api.cc ('k') | src/factory.h » ('j') | src/math.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698