mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-10 01:59:31 +00:00
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:
parent
31301ef08b
commit
bb53485dea
Notes:
github-actions[bot]
2025-05-13 12:15:28 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: bb53485dea
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4704
6 changed files with 38 additions and 18 deletions
|
@ -203,13 +203,24 @@ ThrowCompletionOr<Value> iterator_value(VM& vm, Object& iterator_result)
|
|||
}
|
||||
|
||||
// 7.4.9 IteratorStep ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstep
|
||||
ThrowCompletionOr<GC::Ptr<Object>> iterator_step(VM& vm, IteratorRecord& iterator_record)
|
||||
ThrowCompletionOr<IterationResultOrDone> iterator_step(VM& vm, IteratorRecord& iterator_record)
|
||||
{
|
||||
if (auto* builtin_iterator = iterator_record.iterator->as_builtin_iterator_if_next_is_not_redefined()) {
|
||||
Value value;
|
||||
bool done = false;
|
||||
TRY(builtin_iterator->next(vm, done, value));
|
||||
if (done) {
|
||||
iterator_record.done = true;
|
||||
return ThrowCompletionOr<IterationResultOrDone> { IterationDone {} };
|
||||
}
|
||||
return ThrowCompletionOr<IterationResultOrDone> { IterationResult { done, value } };
|
||||
}
|
||||
|
||||
// 1. Let result be ? IteratorNext(iteratorRecord).
|
||||
auto result = TRY(iterator_next(vm, iterator_record));
|
||||
|
||||
// 2. Let done be Completion(IteratorComplete(result)).
|
||||
auto done = iterator_complete(vm, result);
|
||||
auto done = result->get(vm.names.done);
|
||||
|
||||
// 3. If done is a throw completion, then
|
||||
if (done.is_throw_completion()) {
|
||||
|
@ -224,32 +235,32 @@ ThrowCompletionOr<GC::Ptr<Object>> iterator_step(VM& vm, IteratorRecord& iterato
|
|||
auto done_value = done.release_value();
|
||||
|
||||
// 5. If done is true, then
|
||||
if (done_value) {
|
||||
if (done_value.to_boolean()) {
|
||||
// a. Set iteratorRecord.[[Done]] to true.
|
||||
iterator_record.done = true;
|
||||
|
||||
// b. Return DONE.
|
||||
return nullptr;
|
||||
return ThrowCompletionOr<IterationResultOrDone> { IterationDone {} };
|
||||
}
|
||||
|
||||
// 6. Return result.
|
||||
return result;
|
||||
return ThrowCompletionOr<IterationResultOrDone> { IterationResult { done_value, result->get(vm.names.value) } };
|
||||
}
|
||||
|
||||
// 7.4.10 IteratorStepValue ( iteratorRecord ), https://tc39.es/ecma262/#sec-iteratorstepvalue
|
||||
ThrowCompletionOr<Optional<Value>> iterator_step_value(VM& vm, IteratorRecord& iterator_record)
|
||||
{
|
||||
// 1. Let result be ? IteratorStep(iteratorRecord).
|
||||
auto result = TRY(iterator_step(vm, iterator_record));
|
||||
IterationResultOrDone result = TRY(iterator_step(vm, iterator_record));
|
||||
|
||||
// 2. If result is done, then
|
||||
if (!result) {
|
||||
if (result.has<IterationDone>()) {
|
||||
// a. Return DONE.
|
||||
return OptionalNone {};
|
||||
}
|
||||
|
||||
// 3. Let value be Completion(IteratorValue(result)).
|
||||
auto value = iterator_value(vm, *result);
|
||||
auto& value = result.get<IterationResult>().value;
|
||||
|
||||
// 4. If value is a throw completion, then
|
||||
if (value.is_throw_completion()) {
|
||||
|
@ -363,8 +374,10 @@ ThrowCompletionOr<GC::RootVector<Value>> iterator_to_list(VM& vm, IteratorRecord
|
|||
return values;
|
||||
}
|
||||
|
||||
auto value = next.release_value();
|
||||
|
||||
// c. Append next to values.
|
||||
values.append(next.release_value());
|
||||
values.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -128,10 +128,10 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::drop)
|
|||
iterator.increment_counter();
|
||||
|
||||
// ii. Let next be ? IteratorStep(iterated).
|
||||
auto next = TRY(iterator_step(vm, iterated));
|
||||
IterationResultOrDone next = TRY(iterator_step(vm, iterated));
|
||||
|
||||
// iii. If next is DONE, return ReturnCompletion(undefined).
|
||||
if (!next)
|
||||
if (next.has<IterationDone>())
|
||||
return iterator.result(js_undefined());
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue