LibJS+LibWeb: Add fast path for builtin iterators in iterator_step()

We already have fast path for built-in iterators that skips `next()`
lookup and iteration result object allocation applied for `for..of` and
`for..in` loops. This change extends it to `iterator_step()` to cover
`Array.from()`, `[...arr]` and many other cases.

Makes following function go 2.35x faster on my computer:
```js
(function f() {
  let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  for (let i = 0; i < 1000000; i++) {
    let [a, ...rest] = arr;
  }
})();
```
This commit is contained in:
Aliaksandr Kalenik 2025-05-12 00:31:51 +03:00 committed by Alexander Kalenik
commit bb53485dea
Notes: github-actions[bot] 2025-05-13 12:15:28 +00:00
6 changed files with 38 additions and 18 deletions

View file

@ -76,6 +76,13 @@ protected:
bool m_next_method_was_redefined { false };
};
struct IterationResult {
ThrowCompletionOr<Value> done;
ThrowCompletionOr<Value> value;
};
struct IterationDone { };
using IterationResultOrDone = Variant<IterationResult, IterationDone>;
// 7.4.12 IfAbruptCloseIterator ( value, iteratorRecord ), https://tc39.es/ecma262/#sec-ifabruptcloseiterator
#define TRY_OR_CLOSE_ITERATOR(vm, iterator_record, expression) \
({ \
@ -101,7 +108,7 @@ ThrowCompletionOr<GC::Ref<IteratorRecord>> get_iterator_flattenable(VM&, Value,
ThrowCompletionOr<GC::Ref<Object>> iterator_next(VM&, IteratorRecord&, Optional<Value> = {});
ThrowCompletionOr<bool> iterator_complete(VM&, Object& iterator_result);
ThrowCompletionOr<Value> iterator_value(VM&, Object& iterator_result);
ThrowCompletionOr<GC::Ptr<Object>> iterator_step(VM&, IteratorRecord&);
ThrowCompletionOr<IterationResultOrDone> iterator_step(VM&, IteratorRecord&);
ThrowCompletionOr<Optional<Value>> iterator_step_value(VM&, IteratorRecord&);
Completion iterator_close(VM&, IteratorRecord const&, Completion);
Completion async_iterator_close(VM&, IteratorRecord const&, Completion);