mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-28 10:37:17 +02:00
LibJS: Synchronous await fast path when microtask queue is empty
When an async function is resumed from a microtask and hits another await with a non-thenable value (primitive or already-settled native promise), and the microtask queue is empty, we can resolve the await synchronously without suspending. No other microtask can observe the difference in execution order, making this optimization safe. This avoids the overhead of creating a GC::Function for the microtask job, enqueuing/dequeuing from the microtask queue, and the execution context push/pop that comes with it. A new VM host hook, host_promise_job_queue_is_empty, is added so both the standalone js binary and LibWeb can provide the appropriate check for their respective job queue implementations.
This commit is contained in:
committed by
Andreas Kling
parent
94d3aa8d89
commit
3e1145ef07
Notes:
github-actions[bot]
2026-03-17 00:16:01 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/3e1145ef07b Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8454
@@ -181,12 +181,44 @@ void AsyncFunctionDriverWrapper::continue_async_execution(VM& vm, Value value, b
|
||||
return {};
|
||||
}
|
||||
|
||||
// We hit `await Promise`
|
||||
// We hit `await value`
|
||||
//
|
||||
// OPTIMIZATION: Synchronous await fast path.
|
||||
// If we're not in the initial execution (i.e. we were resumed from a microtask)
|
||||
// and the microtask queue is empty, we can resolve the await synchronously
|
||||
// without suspending. This is safe because no other microtask can observe the
|
||||
// difference in execution order.
|
||||
if (!m_is_initial_execution && vm.host_promise_job_queue_is_empty()) {
|
||||
auto& realm = *vm.current_realm();
|
||||
if (!promise_value.is_object()) {
|
||||
// Primitive values are never thenable.
|
||||
generator_result = m_generator_object->resume(vm, promise_value, {});
|
||||
continue;
|
||||
}
|
||||
if (auto promise = promise_value.as_if<Promise>()) {
|
||||
auto* promise_prototype = realm.intrinsics().promise_prototype().ptr();
|
||||
if (promise->state() != Promise::State::Pending
|
||||
&& promise->shape().property_count() == 0
|
||||
&& promise->shape().prototype() == promise_prototype
|
||||
&& promise_prototype->get_without_side_effects(vm.names.constructor) == Value(realm.intrinsics().promise_constructor())) {
|
||||
auto is_fulfilled = promise->state() == Promise::State::Fulfilled;
|
||||
promise->set_is_handled();
|
||||
if (is_fulfilled) {
|
||||
generator_result = m_generator_object->resume(vm, promise->result(), {});
|
||||
} else {
|
||||
generator_result = m_generator_object->resume_abrupt(vm, throw_completion(promise->result()), {});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto await_result = this->await(promise_value);
|
||||
if (await_result.is_throw_completion()) {
|
||||
generator_result = m_generator_object->resume_abrupt(vm, await_result.release_error(), {});
|
||||
continue;
|
||||
}
|
||||
m_is_initial_execution = false;
|
||||
return {};
|
||||
}
|
||||
}();
|
||||
|
||||
Reference in New Issue
Block a user