LibJS: Avoid IteratorRecord GC-allocation in GetIterator instruction

With this change, `GetIterator` no longer GC-allocates an
`IteratorRecord`. Instead, it stores the iterator record fields in
bytecode registers. This avoids per-iteration allocations in patterns
like: `for (let [x] of array) {}`.

`IteratorRecord` now inherits from `IteratorRecordImpl`, which holds the
iteration state. This allows the existing iteration helpers
(`iterator_next()`, `iterator_step()`, etc.) operate on both the
GC-allocated and the register-backed forms.

Microbenchmarks:
1.1x array-destructuring-assignment-rest.js
1.226x array-destructuring-assignment.js
This commit is contained in:
Aliaksandr Kalenik
2025-10-27 19:46:54 +01:00
committed by Alexander Kalenik
parent a4e3890c05
commit 646457099c
Notes: github-actions[bot] 2025-11-02 19:06:58 +00:00
18 changed files with 252 additions and 235 deletions

View File

@@ -341,7 +341,8 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayConstructor::from_async)
else if (using_sync_iterator) {
// i. Set iteratorRecord to ? CreateAsyncFromSyncIterator(GetIterator(asyncItems, sync, usingSyncIterator)).
// FIXME: The Array.from proposal is out of date - it should be using GetIteratorFromMethod.
iterator_record = create_async_from_sync_iterator(vm, TRY(get_iterator_from_method(vm, async_items, *using_sync_iterator)));
auto iterator_record_impl = create_async_from_sync_iterator(vm, TRY(get_iterator_from_method(vm, async_items, *using_sync_iterator)));
iterator_record = vm.heap().allocate<IteratorRecord>(iterator_record_impl.iterator, iterator_record_impl.next_method, iterator_record_impl.done);
}
// h. If iteratorRecord is not undefined, then