tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit ee59ccae6549ed060a176932442c9e3735a8761c
parent 59e2d6aa313559cb8e9cacdebbb4a0be23bd069e
Author: Meg Ford <meg387@gmail.com>
Date:   Tue, 16 Dec 2025 17:14:30 +0000

Bug 2000092 - Add initial implementation for IteratorChunks. r=dminor,arai

Differential Revision: https://phabricator.services.mozilla.com/D274493

Diffstat:
Mjs/public/friend/ErrorNumbers.msg | 1+
Mjs/src/builtin/Iterator.js | 62+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Ajs/src/tests/non262/Iterator/prototype/chunking/chunking.js | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 122 insertions(+), 1 deletion(-)

diff --git a/js/public/friend/ErrorNumbers.msg b/js/public/friend/ErrorNumbers.msg @@ -839,6 +839,7 @@ MSG_DEF(JSMSG_BAD_WEAKREF_TARGET, 0, JSEXN_TYPEERR, "cann // Iterator Helpers MSG_DEF(JSMSG_NEGATIVE_LIMIT, 0, JSEXN_RANGEERR, "Iterator limits cannot be negative") +MSG_DEF(JSMSG_INVALID_CHUNKSIZE, 0, JSEXN_RANGEERR, "Iterator chunkSize must be an integer between 1 and 2**32-1 inclusive") MSG_DEF(JSMSG_ITERATOR_ZIP_INVALID_OPTION_TYPE, 2, JSEXN_TYPEERR, "invalid type for \"{0}\" option: {1}") MSG_DEF(JSMSG_ITERATOR_ZIP_INVALID_OPTION_VALUE, 2, JSEXN_TYPEERR, "invalid value for \"{0}\" option: {1}") MSG_DEF(JSMSG_ITERATOR_ZIP_STRICT_OPEN_ITERATOR, 0, JSEXN_TYPEERR, "too few iterator results for \"strict\" mode") diff --git a/js/src/builtin/Iterator.js b/js/src/builtin/Iterator.js @@ -1929,7 +1929,67 @@ function IteratorRange(start, end, optionOrStep) { * https://tc39.es/proposal-iterator-chunking/#sec-iterator.prototype.chunks */ function IteratorChunks(chunkSize) { - return false; + // Step 1. Let O be the this value. + var iterator = this; + + // Step 2. If O is not an Object, throw a TypeError exception. + if (!IsObject(iterator)) { + ThrowTypeError(JSMSG_OBJECT_REQUIRED, iterator === null ? "null" : typeof iterator); + } + + // Step 3. Let iterated be the Iterator Record + // { [[Iterator]]: O, [[NextMethod]]: undefined, [[Done]]: false }. + + // Step 4. If chunkSize is not an integral Number in the inclusive interval + // from 1𝔽 to 𝔽(2**32 - 1), then + if (!Number_isInteger(chunkSize) || (chunkSize < 1 || chunkSize > (2 ** 32) - 1)) { + // Step 4.a. Let error be ThrowCompletion(a newly created RangeError object). + // Step 4.b. Return ? IteratorClose(iterated, error). + try { + IteratorClose(iterator); + } catch {} + ThrowRangeError(JSMSG_INVALID_CHUNKSIZE); + } + + // Step 5. Set iterated to ? GetIteratorDirect(O). + var nextMethod = iterator.next; + + // Step 6. Let closure be a new Abstract Closure with ... + // (Handled in IteratorChunksGenerator.) + + // Step 7. Let result be CreateIteratorFromClosure( + // closure, "Iterator Helper", %IteratorHelperPrototype%, + // « [[UnderlyingIterators]] » + // ). + var result = NewIteratorHelper(); + var generator = IteratorChunksGenerator(iterator, nextMethod, chunkSize); + + // Step 8. Set result.[[UnderlyingIterators]] to « iterated ». + UnsafeSetReservedSlot( + result, + ITERATOR_HELPER_GENERATOR_SLOT, + generator + ); + UnsafeSetReservedSlot( + result, + ITERATOR_HELPER_UNDERLYING_ITERATOR_SLOT, + iterator + ); + + // Step 9. Return result. + return result; +} + +/** + * Iterator.prototype.chunks ( chunkSize ) + * + * Abstract closure definition. + * + * https://tc39.es/proposal-iterator-chunking/#sec-iterator.prototype.chunks + */ +/* eslint-disable-next-line require-yield */ +function* IteratorChunksGenerator(iterator, nextMethod, chunkSize) { + IteratorClose(iterator); } /** diff --git a/js/src/tests/non262/Iterator/prototype/chunking/chunking.js b/js/src/tests/non262/Iterator/prototype/chunking/chunking.js @@ -0,0 +1,60 @@ +// |reftest| shell-option(--enable-iterator-chunking) skip-if(!Iterator.prototype.hasOwnProperty('chunks')) + +/*--- +features: [Iterator.chunks] +---*/ + +// Invalid parameter types +assertThrowsInstanceOf(() => Iterator.prototype.chunks('1'), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(null), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(undefined), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks({}), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks([]), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(true), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(Symbol()), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(() => {}), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(10n), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(-10n), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(BigInt(10)), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(BigInt(-10)), RangeError); + +// NaN and Infinity tests +assertThrowsInstanceOf(() => Iterator.prototype.chunks(NaN), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(Infinity), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(-Infinity), RangeError); + +// Out of range values +assertThrowsInstanceOf(() => Iterator.prototype.chunks(0), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(3.25), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(-1), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(2 ** 32), RangeError); +assertThrowsInstanceOf(() => Iterator.prototype.chunks(2 ** 32 + 1), RangeError); + +// Verify no side effect happens if you pass a non-number value +var toPrimitiveCalled = false; +var valueOfCalled = false; +var toStringCalled = false; +const testToPrimitiveObj = { + get [Symbol.toPrimitive]() { + toPrimitiveCalled = true; + } +}; +const testValueOfObj = { + get valueOf() { + valueOfCalled = true; + } +}; +const testToStringObj = { + get toString() { + toStringCalled = true; + } +}; +assertThrowsInstanceOf(() =>[1, 2, 3, 4][Symbol.iterator]().chunks(testToPrimitiveObj), RangeError); +assertEq(toPrimitiveCalled, false); +assertThrowsInstanceOf(() =>[1, 2, 3, 4][Symbol.iterator]().chunks(testValueOfObj), RangeError); +assertEq(valueOfCalled, false); +assertThrowsInstanceOf(() =>[1, 2, 3, 4][Symbol.iterator]().chunks(testToStringObj), RangeError); +assertEq(toStringCalled, false); + +if (typeof reportCompare === 'function') + reportCompare(0, 0);