From e8b4c0b375f8a31d779d37b4e66bf27c70b4a52c Mon Sep 17 00:00:00 2001 From: alejandrodev-vn Date: Mon, 9 Nov 2026 16:00:23 +0700 Subject: [PATCH 1/2] assert: avoid excess float array comparisons Signed-off-by: alejandrodev-vn --- benchmark/assert/deepequal-floatarrays.js | 38 +++++++++++++++++++ lib/internal/util/comparisons.js | 5 ++- ...est-assert-deep-equal-floatarray-length.js | 34 +++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 benchmark/assert/deepequal-floatarrays.js create mode 100644 test/parallel/test-assert-deep-equal-floatarray-length.js diff --git a/benchmark/assert/deepequal-floatarrays.js b/benchmark/assert/deepequal-floatarrays.js new file mode 100644 index 000000000000..fc9ead57698d --- /dev/null +++ b/benchmark/assert/deepequal-floatarrays.js @@ -0,0 +1,38 @@ +'use strict'; +const common = require('../common.js'); +const assert = require('node:assert'); + +const bench = common.createBenchmark(main, { + type: ['Float16Array', 'Float32Array', 'Float64Array'], + len: [0, 1, 100, 5000], + scenario: ['equal', 'different_first', 'different_last', 'different_length'], + n: [10000], +}, { + combinationFilter({ len, scenario }) { + return len !== 0 || scenario === 'equal' || scenario === 'different_length'; + }, +}); + +function main({ type, len, scenario, n }) { + const clazz = globalThis[type]; + const actual = new clazz(len); + const expected = new clazz(len + Number(scenario === 'different_length')); + actual.fill(1.5); + expected.fill(1.5); + + if (len > 0 && scenario === 'different_first') { + expected[0] = 2.5; + } else if (len > 0 && scenario === 'different_last') { + expected[len - 1] = 2.5; + } + + const fn = scenario === 'equal' ? + // eslint-disable-next-line no-restricted-properties + assert.deepEqual : assert.notDeepEqual; + + bench.start(); + for (let i = 0; i < n; i++) { + fn(actual, expected); + } + bench.end(n); +} diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js index 535c3484bfea..2b56faf38d89 100644 --- a/lib/internal/util/comparisons.js +++ b/lib/internal/util/comparisons.js @@ -44,6 +44,7 @@ const { SymbolPrototypeValueOf, SymbolToStringTag, TypedArrayPrototypeGetByteLength: getByteLength, + TypedArrayPrototypeGetLength, TypedArrayPrototypeGetSymbolToStringTag, Uint16Array, Uint32Array, @@ -181,8 +182,8 @@ function isPartialArrayBufferView(a, b) { } function areSimilarFloatArrays(a, b) { - const len = getByteLength(a); - if (len !== getByteLength(b)) { + const len = TypedArrayPrototypeGetLength(a); + if (len !== TypedArrayPrototypeGetLength(b)) { return false; } for (let offset = 0; offset < len; offset++) { diff --git a/test/parallel/test-assert-deep-equal-floatarray-length.js b/test/parallel/test-assert-deep-equal-floatarray-length.js new file mode 100644 index 000000000000..02c7b7307f1b --- /dev/null +++ b/test/parallel/test-assert-deep-equal-floatarray-length.js @@ -0,0 +1,34 @@ +'use strict'; + +const common = require('../common'); +const assert = require('node:assert'); + +for (const FloatArray of [Float16Array, Float32Array, Float64Array]) { + const actual = new FloatArray([0, 1.5, 2.5, 0]).subarray(1, 3); + const equal = new FloatArray([1.5, 2.5]); + const different = new FloatArray([1.5, 3.5]); + const shorter = new FloatArray([1.5]); + const empty = new FloatArray(0); + const emptyEqual = new FloatArray(0); + + // Own properties must not replace the view's intrinsic element count. + for (const view of [actual, equal, different, shorter, empty, emptyEqual]) { + Object.defineProperty(view, 'length', { + get: common.mustNotCall('length getter'), + }); + Object.defineProperty(view, 'byteLength', { + get: common.mustNotCall('byteLength getter'), + }); + } + + // eslint-disable-next-line no-restricted-properties + assert.deepEqual(actual, equal); + // eslint-disable-next-line no-restricted-properties + assert.notDeepEqual(actual, different); + // eslint-disable-next-line no-restricted-properties + assert.notDeepEqual(actual, shorter); + // eslint-disable-next-line no-restricted-properties + assert.notDeepEqual(actual, empty); + // eslint-disable-next-line no-restricted-properties + assert.deepEqual(empty, emptyEqual); +} From e2baf0057bab1aea6b71e5dcc89760d58dd69deb Mon Sep 17 00:00:00 2001 From: alejandrodev-vn Date: Tue, 10 Nov 2026 10:55:47 +0700 Subject: [PATCH 2/2] test: add strict float array assertions Signed-off-by: alejandrodev-vn --- test/parallel/test-assert-deep-equal-floatarray-length.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/parallel/test-assert-deep-equal-floatarray-length.js b/test/parallel/test-assert-deep-equal-floatarray-length.js index 02c7b7307f1b..7ba4be2905d5 100644 --- a/test/parallel/test-assert-deep-equal-floatarray-length.js +++ b/test/parallel/test-assert-deep-equal-floatarray-length.js @@ -11,6 +11,13 @@ for (const FloatArray of [Float16Array, Float32Array, Float64Array]) { const empty = new FloatArray(0); const emptyEqual = new FloatArray(0); + // Check strict comparisons before installing the loose-mode getter guards. + assert.deepStrictEqual(actual, equal); + assert.notDeepStrictEqual(actual, different); + assert.notDeepStrictEqual(actual, shorter); + assert.notDeepStrictEqual(actual, empty); + assert.deepStrictEqual(empty, emptyEqual); + // Own properties must not replace the view's intrinsic element count. for (const view of [actual, equal, different, shorter, empty, emptyEqual]) { Object.defineProperty(view, 'length', {