mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-02 22:30:31 +00:00
LibJS: Localize popping of execution context in AsyncFunctionDriver
Instead of adding a flag for the two callers that need a pop of the execution context stack when invoking continue_async_execution inline the pop of the execution context. This makes the management of these stacks and surrounding VERIFY calls much more obvious.
This commit is contained in:
parent
d1f9e3be90
commit
b58ba2e1bd
Notes:
github-actions[bot]
2025-01-30 20:58:24 +00:00
Author: https://github.com/shannonbooth
Commit: b58ba2e1bd
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3231
Reviewed-by: https://github.com/ADKaster ✅
2 changed files with 6 additions and 15 deletions
|
@ -24,7 +24,7 @@ GC::Ref<Promise> AsyncFunctionDriverWrapper::create(Realm& realm, GeneratorObjec
|
||||||
auto wrapper = realm.create<AsyncFunctionDriverWrapper>(realm, *generator_object, *top_level_promise);
|
auto wrapper = realm.create<AsyncFunctionDriverWrapper>(realm, *generator_object, *top_level_promise);
|
||||||
// Prime the generator:
|
// Prime the generator:
|
||||||
// This runs until the first `await value;`
|
// This runs until the first `await value;`
|
||||||
wrapper->continue_async_execution(realm.vm(), js_undefined(), true, IsInitialExecution::Yes);
|
wrapper->continue_async_execution(realm.vm(), js_undefined(), true);
|
||||||
|
|
||||||
return top_level_promise;
|
return top_level_promise;
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,7 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
|
||||||
// d. Resume the suspended evaluation of asyncContext using NormalCompletion(v) as the result of the operation that
|
// d. Resume the suspended evaluation of asyncContext using NormalCompletion(v) as the result of the operation that
|
||||||
// suspended it.
|
// suspended it.
|
||||||
continue_async_execution(vm, value, true);
|
continue_async_execution(vm, value, true);
|
||||||
|
vm.pop_execution_context();
|
||||||
|
|
||||||
// e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and
|
// 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.
|
// prevContext is the currently running execution context.
|
||||||
|
@ -91,6 +92,7 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
|
||||||
// d. Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that
|
// d. Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that
|
||||||
// suspended it.
|
// suspended it.
|
||||||
continue_async_execution(vm, reason, false);
|
continue_async_execution(vm, reason, false);
|
||||||
|
vm.pop_execution_context();
|
||||||
|
|
||||||
// e. Assert: When we reach this step, asyncContext has already been removed from the execution context stack and
|
// 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.
|
// prevContext is the currently running execution context.
|
||||||
|
@ -107,11 +109,9 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
|
||||||
m_current_promise = as<Promise>(promise_object);
|
m_current_promise = as<Promise>(promise_object);
|
||||||
m_current_promise->perform_then(on_fulfilled, on_rejected, {});
|
m_current_promise->perform_then(on_fulfilled, 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
|
// 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.
|
// execution context stack as the running execution context.
|
||||||
// NOTE: This is done later on for us in continue_async_execution.
|
|
||||||
|
|
||||||
// NOTE: None of these are necessary. 10-12 are handled by step d of the above lambdas.
|
|
||||||
// 9. Let callerContext be the running execution context.
|
// 9. Let callerContext be the running execution context.
|
||||||
// 10. Resume callerContext passing empty. If asyncContext is ever resumed again, let completion be the Completion Record with which it is resumed.
|
// 10. Resume callerContext passing empty. If asyncContext is ever resumed again, let completion be the Completion Record with which it is resumed.
|
||||||
// 11. Assert: If control reaches here, then asyncContext is the running execution context again.
|
// 11. Assert: If control reaches here, then asyncContext is the running execution context again.
|
||||||
|
@ -119,7 +119,7 @@ ThrowCompletionOr<void> AsyncFunctionDriverWrapper::await(JS::Value value)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncFunctionDriverWrapper::continue_async_execution(VM& vm, Value value, bool is_successful, IsInitialExecution is_initial_execution)
|
void AsyncFunctionDriverWrapper::continue_async_execution(VM& vm, Value value, bool is_successful)
|
||||||
{
|
{
|
||||||
auto generator_result = is_successful
|
auto generator_result = is_successful
|
||||||
? m_generator_object->resume(vm, value, {})
|
? m_generator_object->resume(vm, value, {})
|
||||||
|
@ -168,10 +168,6 @@ void AsyncFunctionDriverWrapper::continue_async_execution(VM& vm, Value value, b
|
||||||
if (result.is_throw_completion()) {
|
if (result.is_throw_completion()) {
|
||||||
m_top_level_promise->reject(result.throw_completion().value().value_or(js_undefined()));
|
m_top_level_promise->reject(result.throw_completion().value().value_or(js_undefined()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the initial execution, the execution context will be popped for us later on by ECMAScriptFunctionObject.
|
|
||||||
if (is_initial_execution == IsInitialExecution::No)
|
|
||||||
vm.pop_execution_context();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncFunctionDriverWrapper::visit_edges(Cell::Visitor& visitor)
|
void AsyncFunctionDriverWrapper::visit_edges(Cell::Visitor& visitor)
|
||||||
|
|
|
@ -19,17 +19,12 @@ class AsyncFunctionDriverWrapper final : public Promise {
|
||||||
GC_DECLARE_ALLOCATOR(AsyncFunctionDriverWrapper);
|
GC_DECLARE_ALLOCATOR(AsyncFunctionDriverWrapper);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class IsInitialExecution {
|
|
||||||
No,
|
|
||||||
Yes,
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] static GC::Ref<Promise> create(Realm&, GeneratorObject*);
|
[[nodiscard]] static GC::Ref<Promise> create(Realm&, GeneratorObject*);
|
||||||
|
|
||||||
virtual ~AsyncFunctionDriverWrapper() override = default;
|
virtual ~AsyncFunctionDriverWrapper() override = default;
|
||||||
void visit_edges(Cell::Visitor&) override;
|
void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
void continue_async_execution(VM&, Value, bool is_successful, IsInitialExecution is_initial_execution = IsInitialExecution::No);
|
void continue_async_execution(VM&, Value, bool is_successful);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AsyncFunctionDriverWrapper(Realm&, GC::Ref<GeneratorObject>, GC::Ref<Promise> top_level_promise);
|
AsyncFunctionDriverWrapper(Realm&, GC::Ref<GeneratorObject>, GC::Ref<Promise> top_level_promise);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue