diff options
author | Ruben Bridgewater <ruben@bridgewater.de> | 2018-08-07 01:21:09 +0200 |
---|---|---|
committer | Ruben Bridgewater <ruben@bridgewater.de> | 2018-08-20 02:11:46 +0200 |
commit | 3479b1ca8206c88bac1f1ee8925a2d30759747d7 (patch) | |
tree | 1e64f365138d989e9a526fc195c0278adb7b2e34 /lib | |
parent | 0bdb95f4cffa7d672c23c60cdb6b779451d2ea33 (diff) | |
download | android-node-v8-3479b1ca8206c88bac1f1ee8925a2d30759747d7.tar.gz android-node-v8-3479b1ca8206c88bac1f1ee8925a2d30759747d7.tar.bz2 android-node-v8-3479b1ca8206c88bac1f1ee8925a2d30759747d7.zip |
util,assert: improve performance
This significantly improves regular and typed array performance by
not checking the indices keys anymore. This can be done with a V8
API that allows to only retrieve the non indices property keys.
PR-URL: https://github.com/nodejs/node/pull/22197
Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/internal/util/comparisons.js | 81 |
1 files changed, 37 insertions, 44 deletions
diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js index 9f636f31a3..729bd1c31e 100644 --- a/lib/internal/util/comparisons.js +++ b/lib/internal/util/comparisons.js @@ -4,6 +4,7 @@ const { compare } = process.binding('buffer'); const { isArrayBufferView } = require('internal/util/types'); const { internalBinding } = require('internal/bootstrap/loaders'); const { isDate, isMap, isRegExp, isSet } = internalBinding('types'); +const { getOwnNonIndexProperties } = process.binding('util'); const ReflectApply = Reflect.apply; @@ -106,24 +107,11 @@ function strictDeepEqual(val1, val2, memos) { if (val1.length !== val2.length) { return false; } - const keys = objectKeys(val1); - if (keys.length !== objectKeys(val2).length) { + const keys1 = getOwnNonIndexProperties(val1); + if (keys1.length !== getOwnNonIndexProperties(val2).length) { return false; } - // Fast path for non sparse arrays (no key comparison for indices - // properties). - // See https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys - if (val1.length === keys.length) { - if (keys.length === 0 || keys[val1.length - 1] === `${val1.length - 1}`) { - return keyCheck(val1, val2, kStrict, memos, kIsArray, []); - } - } else if (keys.length > val1.length && - keys[val1.length - 1] === `${val1.length - 1}`) { - const minimalKeys = keys.slice(val1.length); - return keyCheck(val1, val2, kStrict, memos, kIsArray, minimalKeys); - } - // Only set this to kIsArray in case the array is not sparse! - return keyCheck(val1, val2, kStrict, memos, kNoIterator, keys); + return keyCheck(val1, val2, kStrict, memos, kIsArray, keys1); } if (val1Tag === '[object Object]') { return keyCheck(val1, val2, kStrict, memos, kNoIterator); @@ -148,18 +136,14 @@ function strictDeepEqual(val1, val2, memos) { if (!areSimilarTypedArrays(val1, val2)) { return false; } - // Buffer.compare returns true, so val1.length === val2.length - // if they both only contain numeric keys, we don't need to exam further. - const keys = objectKeys(val1); - if (keys.length !== objectKeys(val2).length) { + // Buffer.compare returns true, so val1.length === val2.length. If they both + // only contain numeric keys, we don't need to exam further than checking + // the symbols. + const keys1 = getOwnNonIndexProperties(val1); + if (keys1.length !== getOwnNonIndexProperties(val2).length) { return false; } - if (keys.length === val1.length) { - return keyCheck(val1, val2, kStrict, memos, kNoIterator, []); - } - // Only compare the special keys. - const minimalKeys = keys.slice(val1.length); - return keyCheck(val1, val2, kStrict, memos, kNoIterator, minimalKeys); + return keyCheck(val1, val2, kStrict, memos, kNoIterator, keys1); } else if (isSet(val1)) { if (!isSet(val2) || val1.size !== val2.size) { return false; @@ -173,21 +157,10 @@ function strictDeepEqual(val1, val2, memos) { // TODO: Make the valueOf checks safe. } else if (typeof val1.valueOf === 'function') { const val1Value = val1.valueOf(); - if (val1Value !== val1) { - if (typeof val2.valueOf !== 'function') { - return false; - } - if (!innerDeepEqual(val1Value, val2.valueOf(), true)) - return false; - // Fast path for boxed primitive strings. - if (typeof val1Value === 'string') { - const keys = objectKeys(val1); - if (keys.length !== objectKeys(val2).length) { - return false; - } - const minimalKeys = keys.slice(val1.length); - return keyCheck(val1, val2, kStrict, memos, kNoIterator, minimalKeys); - } + if (val1Value !== val1 && + (typeof val2.valueOf !== 'function' || + !innerDeepEqual(val1Value, val2.valueOf(), kStrict))) { + return false; } } return keyCheck(val1, val2, kStrict, memos, kNoIterator); @@ -277,7 +250,7 @@ function keyCheck(val1, val2, strict, memos, iterationType, aKeys) { } } - if (strict) { + if (strict && arguments.length === 5) { const symbolKeysA = getOwnPropertySymbols(val1); if (symbolKeysA.length !== 0) { let count = 0; @@ -310,7 +283,7 @@ function keyCheck(val1, val2, strict, memos, iterationType, aKeys) { if (aKeys.length === 0 && (iterationType === kNoIterator || iterationType === kIsArray && val1.length === 0 || - val1.size === 0)) { + val1.size === 0)) { return true; } @@ -578,8 +551,28 @@ function objEquiv(a, b, strict, keys, memos, iterationType) { } } else if (iterationType === kIsArray) { for (; i < a.length; i++) { - if (!innerDeepEqual(a[i], b[i], strict, memos)) { + if (hasOwnProperty(a, i)) { + if (!hasOwnProperty(b, i) || + !innerDeepEqual(a[i], b[i], strict, memos)) { + return false; + } + } else if (hasOwnProperty(b, i)) { return false; + } else { + // Array is sparse. + const keysA = objectKeys(a); + i++; + for (; i < keysA.length; i++) { + const key = keysA[i]; + if (!hasOwnProperty(b, key) || + !innerDeepEqual(a[key], b[i], strict, memos)) { + return false; + } + } + if (keysA.length !== objectKeys(b).length) { + return false; + } + return true; } } } |