From bfe049d9c87b4c83a9de88389da1acef0a3e769f Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 20 Jan 2025 18:11:04 -0800 Subject: [PATCH] [Fix] `ES2024`+: `GetViewByteLength`, `TypedArrayByteLength`, `TypedArrayLength`: properly handle resizable arrays --- 2024/GetViewByteLength.js | 6 +++-- 2024/TypedArrayByteLength.js | 6 ++++- 2024/TypedArrayLength.js | 8 +++--- test/tests.js | 47 ++++++++++++++++++++++++++++++++++-- 4 files changed, 59 insertions(+), 8 deletions(-) diff --git a/2024/GetViewByteLength.js b/2024/GetViewByteLength.js index 7d11ae3a..a5837e8b 100644 --- a/2024/GetViewByteLength.js +++ b/2024/GetViewByteLength.js @@ -24,12 +24,14 @@ module.exports = function GetViewByteLength(viewRecord) { var view = viewRecord['[[Object]]']; // step 2 - var viewByteLength = dataViewByteLength(view); // view.[[ByteLength]] + var isFixed = IsFixedLengthArrayBuffer(dataViewBuffer(view)); + + var viewByteLength = isFixed ? dataViewByteLength(view) : 'AUTO'; // view.[[ByteLength]] if (viewByteLength !== 'AUTO') { return viewByteLength; // step 3 } - if (IsFixedLengthArrayBuffer(dataViewBuffer(view))) { + if (isFixed) { throw new $TypeError('Assertion failed: DataView’s ArrayBuffer is not fixed length'); // step 4 } diff --git a/2024/TypedArrayByteLength.js b/2024/TypedArrayByteLength.js index c455cd75..703ef0ab 100644 --- a/2024/TypedArrayByteLength.js +++ b/2024/TypedArrayByteLength.js @@ -2,12 +2,14 @@ var $TypeError = require('es-errors/type'); +var IsFixedLengthArrayBuffer = require('./IsFixedLengthArrayBuffer'); var IsTypedArrayOutOfBounds = require('./IsTypedArrayOutOfBounds'); var TypedArrayElementSize = require('./TypedArrayElementSize'); var TypedArrayLength = require('./TypedArrayLength'); var isTypedArrayWithBufferWitnessRecord = require('../helpers/records/typed-array-with-buffer-witness-record'); +var typedArrayByffer = require('typed-array-buffer'); var typedArrayByteLength = require('typed-array-byte-length'); // https://262.ecma-international.org/15.0/#sec-typedarraybytelength @@ -28,7 +30,9 @@ module.exports = function TypedArrayByteLength(taRecord) { var O = taRecord['[[Object]]']; // step 4 - var byteLength = typedArrayByteLength(O); + var isFixed = IsFixedLengthArrayBuffer(typedArrayByffer(O)); + + var byteLength = isFixed ? typedArrayByteLength(O) : 'AUTO'; if (byteLength !== 'AUTO') { return byteLength; // step 5 } diff --git a/2024/TypedArrayLength.js b/2024/TypedArrayLength.js index d07519d3..30b21acd 100644 --- a/2024/TypedArrayLength.js +++ b/2024/TypedArrayLength.js @@ -13,7 +13,7 @@ var typedArrayBuffer = require('typed-array-buffer'); var typedArrayByteOffset = require('typed-array-byte-offset'); var typedArrayLength = require('typed-array-length'); -// http://www.ecma-international.org/ecma-262/15.0/#sec-typedarraylength +// https://www.ecma-international.org/ecma-262/15.0/#sec-typedarraylength module.exports = function TypedArrayLength(taRecord) { if (!isTypedArrayWithBufferWitnessRecord(taRecord)) { @@ -26,12 +26,14 @@ module.exports = function TypedArrayLength(taRecord) { var O = taRecord['[[Object]]']; // step 2 - var length = typedArrayLength(O); + var isFixed = IsFixedLengthArrayBuffer(typedArrayBuffer(O)); + + var length = isFixed ? typedArrayLength(O) : 'AUTO'; if (length !== 'AUTO') { return length; // step 3 } - if (IsFixedLengthArrayBuffer(typedArrayBuffer(O))) { + if (isFixed) { throw new $TypeError('Assertion failed: array buffer is not fixed length'); // step 4 } diff --git a/test/tests.js b/test/tests.js index 5e1aeae4..0efc52b4 100644 --- a/test/tests.js +++ b/test/tests.js @@ -18007,9 +18007,52 @@ var es2024 = function ES2024(ES, ops, expectedMissing, skips) { // TODO: actual TA byteLength auto, but not fixed length? (may not be possible) - tat.test('non-fixed length, return floor((byteLength - byteOffset) / elementSize)', { todo: 'blocked on native resizable ABs/growable SABs' }); + var elementSize = elementSizes['$' + type]; + + tat.test( + 'non-fixed length, return floor((byteLength - byteOffset) / elementSize)', + { skip: !('resizable' in ArrayBuffer.prototype) }, + function (tsat) { + var rab = new ArrayBuffer(17, { maxByteLength: 64 }); + var arr = new TA(rab, 8); + record = ES.MakeTypedArrayWithBufferWitnessRecord(arr, 'UNORDERED'); + + tsat.equal( + ES.TypedArrayLength(record), + Math.floor((17 - 8) / elementSize), + type + ' + resizable AB: has expected length' + ); + + tsat.end(); + } + ); + + tat.test( + 'non-fixed length, detached throws', + { skip: !('resizable' in ArrayBuffer.prototype) || !canDetach }, + function (tsat) { + var rab = new ArrayBuffer(17, { maxByteLength: 64 }); + var arr = new TA(rab, 8); + record = ES.MakeTypedArrayWithBufferWitnessRecord(arr, 'UNORDERED'); + + ES.DetachArrayBuffer(rab); - tat.test('non-fixed length, detached throws', { todo: 'blocked on native resizable ABs/growable SABs' }); + tsat['throws']( + function () { ES.TypedArrayLength(record); }, + TypeError, + 'detached RAB with a non-detached TAWBR throws' + ); + + record = ES.MakeTypedArrayWithBufferWitnessRecord(arr, 'UNORDERED'); + tsat['throws']( + function () { ES.TypedArrayLength(record); }, + TypeError, + 'detached RAB with a detached TAWBR throws' + ); + + tsat.end(); + } + ); }); });