LibJS: Cache rejected/fulfilled callbacks in AsyncFunctionDriverWrapper

Saves us two NativeFunction allocations per each `await`.

With this change, following function goes 80% faster on my computer:
```js
(async () => {
    const resolved = Promise.resolve();
    for (let i = 0; i < 5_000_000; i++) {
        await resolved;
    }
})();
```
This commit is contained in:
Aliaksandr Kalenik 2025-05-09 04:57:02 +03:00 committed by Andreas Kling
parent 4c789ac689
commit 6530f55f34
Notes: github-actions[bot] 2025-05-09 10:31:10 +00:00
2 changed files with 10 additions and 3 deletions

View file

@ -75,7 +75,8 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
};
// 4. Let onFulfilled be CreateBuiltinFunction(fulfilledClosure, 1, "", « »).
auto on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 1);
if (!m_on_fulfilled)
m_on_fulfilled = NativeFunction::create(realm, move(fulfilled_closure), 1);
// 5. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures asyncContext and performs the
// following steps when called:
@ -103,11 +104,12 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
};
// 6. Let onRejected be CreateBuiltinFunction(rejectedClosure, 1, "", « »).
auto on_rejected = NativeFunction::create(realm, move(rejected_closure), 1);
if (!m_on_rejected)
m_on_rejected = NativeFunction::create(realm, move(rejected_closure), 1);
// 7. Perform PerformPromiseThen(promise, onFulfilled, onRejected).
m_current_promise = as<Promise>(promise_object);
m_current_promise->perform_then(on_fulfilled, on_rejected, {});
m_current_promise->perform_then(m_on_fulfilled, m_on_rejected, {});
// NOTE: None of these are necessary. 8-12 are handled by step d of the above lambdas.
// 8. Remove asyncContext from the execution context stack and restore the execution context that is at the top of the
@ -176,6 +178,8 @@ void AsyncFunctionDriverWrapper::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_current_promise);
if (m_suspended_execution_context)
m_suspended_execution_context->visit_edges(visitor);
visitor.visit(m_on_fulfilled);
visitor.visit(m_on_rejected);
}
}