| Index: src/collection.js
|
| diff --git a/src/collection.js b/src/collection.js
|
| index 70a88fb873cb18956514122aba63a1e115af01f0..6b468f5fc0ee8b2de8cd61ca1a27e4c78c8dcfb5 100644
|
| --- a/src/collection.js
|
| +++ b/src/collection.js
|
| @@ -2,8 +2,10 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -(function(global, utils) {
|
| +var $getHash;
|
| +var $getExistingHash;
|
|
|
| +(function(global, utils) {
|
| "use strict";
|
|
|
| %CheckIsBootstrapping();
|
| @@ -14,6 +16,11 @@
|
| var GlobalMap = global.Map;
|
| var GlobalObject = global.Object;
|
| var GlobalSet = global.Set;
|
| +var IntRandom;
|
| +
|
| +utils.Import(function(from) {
|
| + IntRandom = from.IntRandom;
|
| +});
|
|
|
| var NumberIsNaN;
|
|
|
| @@ -31,17 +38,19 @@ function HashToEntry(table, hash, numBuckets) {
|
|
|
|
|
| function SetFindEntry(table, numBuckets, key, hash) {
|
| + var entry = HashToEntry(table, hash, numBuckets);
|
| + if (entry === NOT_FOUND) return entry;
|
| + var candidate = ORDERED_HASH_SET_KEY_AT(table, entry, numBuckets);
|
| + if (key === candidate) return entry;
|
| var keyIsNaN = NumberIsNaN(key);
|
| - for (var entry = HashToEntry(table, hash, numBuckets);
|
| - entry !== NOT_FOUND;
|
| - entry = ORDERED_HASH_SET_CHAIN_AT(table, entry, numBuckets)) {
|
| - var candidate = ORDERED_HASH_SET_KEY_AT(table, entry, numBuckets);
|
| - if (key === candidate) {
|
| - return entry;
|
| - }
|
| + while (true) {
|
| if (keyIsNaN && NumberIsNaN(candidate)) {
|
| return entry;
|
| }
|
| + entry = ORDERED_HASH_SET_CHAIN_AT(table, entry, numBuckets);
|
| + if (entry === NOT_FOUND) return entry;
|
| + candidate = ORDERED_HASH_SET_KEY_AT(table, entry, numBuckets);
|
| + if (key === candidate) return entry;
|
| }
|
| return NOT_FOUND;
|
| }
|
| @@ -49,17 +58,19 @@ function SetFindEntry(table, numBuckets, key, hash) {
|
|
|
|
|
| function MapFindEntry(table, numBuckets, key, hash) {
|
| + var entry = HashToEntry(table, hash, numBuckets);
|
| + if (entry === NOT_FOUND) return entry;
|
| + var candidate = ORDERED_HASH_MAP_KEY_AT(table, entry, numBuckets);
|
| + if (key === candidate) return entry;
|
| var keyIsNaN = NumberIsNaN(key);
|
| - for (var entry = HashToEntry(table, hash, numBuckets);
|
| - entry !== NOT_FOUND;
|
| - entry = ORDERED_HASH_MAP_CHAIN_AT(table, entry, numBuckets)) {
|
| - var candidate = ORDERED_HASH_MAP_KEY_AT(table, entry, numBuckets);
|
| - if (key === candidate) {
|
| - return entry;
|
| - }
|
| + while (true) {
|
| if (keyIsNaN && NumberIsNaN(candidate)) {
|
| return entry;
|
| }
|
| + entry = ORDERED_HASH_MAP_CHAIN_AT(table, entry, numBuckets);
|
| + if (entry === NOT_FOUND) return entry;
|
| + candidate = ORDERED_HASH_MAP_KEY_AT(table, entry, numBuckets);
|
| + if (key === candidate) return entry;
|
| }
|
| return NOT_FOUND;
|
| }
|
| @@ -75,12 +86,13 @@ function ComputeIntegerHash(key, seed) {
|
| hash = hash ^ (hash >>> 4);
|
| hash = (hash * 2057) | 0; // hash = (hash + (hash << 3)) + (hash << 11);
|
| hash = hash ^ (hash >>> 16);
|
| - return hash;
|
| + return hash & 0x3fffffff;
|
| }
|
| %SetForceInlineFlag(ComputeIntegerHash);
|
|
|
| +var hashCodeSymbol = GLOBAL_PRIVATE("hash_code_symbol");
|
|
|
| -function GetHash(key) {
|
| +function GetExistingHash(key) {
|
| if (%_IsSmi(key)) {
|
| return ComputeIntegerHash(key, 0);
|
| }
|
| @@ -89,9 +101,24 @@ function GetHash(key) {
|
| if ((field & 1 /* Name::kHashNotComputedMask */) === 0) {
|
| return field >>> 2 /* Name::kHashShift */;
|
| }
|
| + } else if (IS_SPEC_OBJECT(key) && !%_IsJSProxy(key) && !IS_GLOBAL(key)) {
|
| + var hash = GET_PRIVATE(key, hashCodeSymbol);
|
| + return hash;
|
| }
|
| return %GenericHash(key);
|
| }
|
| +%SetForceInlineFlag(GetExistingHash);
|
| +
|
| +
|
| +function GetHash(key) {
|
| + var hash = GetExistingHash(key);
|
| + if (IS_UNDEFINED(hash)) {
|
| + hash = IntRandom() | 0;
|
| + if (hash === 0) hash = 1;
|
| + SET_PRIVATE(key, hashCodeSymbol, hash);
|
| + }
|
| + return hash;
|
| +}
|
| %SetForceInlineFlag(GetHash);
|
|
|
|
|
| @@ -164,7 +191,8 @@ function SetHas(key) {
|
| }
|
| var table = %_JSCollectionGetTable(this);
|
| var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT(table);
|
| - var hash = GetHash(key);
|
| + var hash = GetExistingHash(key);
|
| + if (IS_UNDEFINED(hash)) return false;
|
| return SetFindEntry(table, numBuckets, key, hash) !== NOT_FOUND;
|
| }
|
|
|
| @@ -176,7 +204,8 @@ function SetDelete(key) {
|
| }
|
| var table = %_JSCollectionGetTable(this);
|
| var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT(table);
|
| - var hash = GetHash(key);
|
| + var hash = GetExistingHash(key);
|
| + if (IS_UNDEFINED(hash)) return false;
|
| var entry = SetFindEntry(table, numBuckets, key, hash);
|
| if (entry === NOT_FOUND) return false;
|
|
|
| @@ -291,7 +320,8 @@ function MapGet(key) {
|
| }
|
| var table = %_JSCollectionGetTable(this);
|
| var numBuckets = ORDERED_HASH_TABLE_BUCKET_COUNT(table);
|
| - var hash = GetHash(key);
|
| + var hash = GetExistingHash(key);
|
| + if (IS_UNDEFINED(hash)) return UNDEFINED;
|
| var entry = MapFindEntry(table, numBuckets, key, hash);
|
| if (entry === NOT_FOUND) return UNDEFINED;
|
| return ORDERED_HASH_MAP_VALUE_AT(table, entry, numBuckets);
|
| @@ -446,4 +476,8 @@ utils.InstallFunctions(GlobalMap.prototype, DONT_ENUM, [
|
| "forEach", MapForEach
|
| ]);
|
|
|
| +// Expose to the global scope.
|
| +$getHash = GetHash;
|
| +$getExistingHash = GetExistingHash;
|
| +
|
| })
|
|
|