Skip to content

Commit ccf713b

Browse files
alimpfardlinusg
authored andcommitted
LibJS: Spin the event loop while waiting for async completion in await
1 parent f7ba81a commit ccf713b

File tree

1 file changed

+25
-13
lines changed

1 file changed

+25
-13
lines changed

Userland/Libraries/LibJS/Runtime/Completion.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
#include <AK/TypeCasts.h>
9+
#include <LibCore/EventLoop.h>
910
#include <LibJS/Runtime/Completion.h>
1011
#include <LibJS/Runtime/GlobalObject.h>
1112
#include <LibJS/Runtime/NativeFunction.h>
@@ -33,15 +34,15 @@ ThrowCompletionOr<Value> await(GlobalObject& global_object, Value value)
3334
auto& vm = global_object.vm();
3435

3536
// 1. Let asyncContext be the running execution context.
36-
auto& async_context = vm.running_execution_context();
37+
// NOTE: This is not needed, as we don't suspend anything.
3738

3839
// 2. Let promise be ? PromiseResolve(%Promise%, value).
39-
auto* promise = TRY(promise_resolve(global_object, *global_object.promise_constructor(), value));
40+
auto* promise_object = TRY(promise_resolve(global_object, *global_object.promise_constructor(), value));
4041

41-
bool success = false;
42+
Optional<bool> success;
4243
Value result;
4344
// 3. Let fulfilledClosure be a new Abstract Closure with parameters (value) that captures asyncContext and performs the following steps when called:
44-
auto fulfilled_closure = [&async_context, &success, &result](VM& vm, GlobalObject& global_object) -> ThrowCompletionOr<Value> {
45+
auto fulfilled_closure = [&success, &result](VM& vm, GlobalObject&) -> ThrowCompletionOr<Value> {
4546
// a. Let prevContext be the running execution context.
4647
// b. Suspend prevContext.
4748
// FIXME: We don't have this concept yet.
@@ -51,7 +52,7 @@ ThrowCompletionOr<Value> await(GlobalObject& global_object, Value value)
5152
result = vm.argument(0);
5253

5354
// c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
54-
TRY(vm.push_execution_context(async_context, global_object));
55+
// NOTE: This is not done, because we're not suspending anything (see above).
5556

5657
// d. Resume the suspended evaluation of asyncContext using NormalCompletion(value) as the result of the operation that suspended it.
5758
// e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
@@ -65,7 +66,7 @@ ThrowCompletionOr<Value> await(GlobalObject& global_object, Value value)
6566
auto on_fulfilled = NativeFunction::create(global_object, "", move(fulfilled_closure));
6667

6768
// 5. Let rejectedClosure be a new Abstract Closure with parameters (reason) that captures asyncContext and performs the following steps when called:
68-
auto rejected_closure = [&async_context, &success, &result](VM& vm, GlobalObject& global_object) -> ThrowCompletionOr<Value> {
69+
auto rejected_closure = [&success, &result](VM& vm, GlobalObject&) -> ThrowCompletionOr<Value> {
6970
// a. Let prevContext be the running execution context.
7071
// b. Suspend prevContext.
7172
// FIXME: We don't have this concept yet.
@@ -75,7 +76,7 @@ ThrowCompletionOr<Value> await(GlobalObject& global_object, Value value)
7576
result = vm.argument(0);
7677

7778
// c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context.
78-
TRY(vm.push_execution_context(async_context, global_object));
79+
// NOTE: This is not done, because we're not suspending anything (see above).
7980

8081
// d. Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that suspended it.
8182
// e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and prevContext is the currently running execution context.
@@ -89,21 +90,32 @@ ThrowCompletionOr<Value> await(GlobalObject& global_object, Value value)
8990
auto on_rejected = NativeFunction::create(global_object, "", move(rejected_closure));
9091

9192
// 7. Perform ! PerformPromiseThen(promise, onFulfilled, onRejected).
92-
verify_cast<Promise>(promise)->perform_then(on_fulfilled, on_rejected, {});
93+
auto* promise = verify_cast<Promise>(promise_object);
94+
promise->perform_then(on_fulfilled, on_rejected, {});
95+
96+
// FIXME: Since we don't support context suspension, we attempt to "wait" for the promise to resolve
97+
// by letting the event loop spin until our promise is no longer pending, and then synchronously
98+
// running all queued promise jobs.
99+
// Note: This is not used by LibJS itself, and is performed for the embedder (i.e. LibWeb).
100+
if (Core::EventLoop::has_been_instantiated())
101+
Core::EventLoop::current().spin_until([&] { return promise->state() != Promise::State::Pending; });
93102

94103
// 8. Remove asyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context.
95-
vm.pop_execution_context();
104+
// NOTE: Since we don't push any EC, this step is not performed.
96105

97106
// 9. Set the code evaluation state of asyncContext such that when evaluation is resumed with a Completion completion, the following steps of the algorithm that invoked Await will be performed, with completion available.
98107
// 10. Return.
99108
// 11. NOTE: This returns to the evaluation of the operation that had most previously resumed evaluation of asyncContext.
100-
// FIXME: Since we don't support context suspension, we synchronously execute the promise
109+
101110
vm.run_queued_promise_jobs();
102111

103-
if (success)
112+
// Make sure that the promise _actually_ resolved.
113+
// Note that this is checked down the chain (result.is_empty()) anyway, but let's make the source of the issue more clear.
114+
VERIFY(success.has_value());
115+
116+
if (success.value())
104117
return result;
105-
else
106-
return throw_completion(result);
118+
return throw_completion(result);
107119
}
108120

109121
}

0 commit comments

Comments
 (0)