Commit 302a5d20 authored by Benedikt Meurer's avatar Benedikt Meurer Committed by V8 LUCI CQ

[async-await] Further simplify `await` and its instrumentation.

Following up on https://crrev.com/c/3383775 we are now able to further
simplify the implementation of `await` and its instrumentation (for both
debugger and promise hooks), which aligns the implementation more
closely with the spec text and removes a whole bunch of unnecessary
code.

This also moves the `await` instrumentation into runtime-debug.cc along
with the other instrumentation methods for async functions.

Bug: chromium:1280519, chromium:1277451, chromium:1246867
Change-Id: I3fb543c76229091b502f3188da962784977158ab
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3386597
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78610}
parent fec4bd06
This diff is collapsed.
......@@ -48,26 +48,6 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler {
TNode<SharedFunctionInfo> shared_info);
TNode<Context> AllocateAsyncIteratorValueUnwrapContext(
TNode<NativeContext> native_context, TNode<Oddball> done);
TNode<Object> AwaitOld(TNode<Context> context,
TNode<JSGeneratorObject> generator,
TNode<Object> value, TNode<JSPromise> outer_promise,
TNode<SharedFunctionInfo> on_resolve_sfi,
TNode<SharedFunctionInfo> on_reject_sfi,
TNode<Oddball> is_predicted_as_caught);
TNode<Object> AwaitOptimized(TNode<Context> context,
TNode<JSGeneratorObject> generator,
TNode<JSPromise> promise,
TNode<JSPromise> outer_promise,
TNode<SharedFunctionInfo> on_resolve_sfi,
TNode<SharedFunctionInfo> on_reject_sfi,
TNode<Oddball> is_predicted_as_caught);
void InitAwaitPromise(
Runtime::FunctionId id, TNode<Context> context, TNode<Object> value,
TNode<Object> promise, TNode<Object> outer_promise,
TNode<HeapObject> on_reject, TNode<Oddball> is_predicted_as_caught,
TVariable<HeapObject>* var_throwaway);
};
} // namespace internal
......
......@@ -826,6 +826,46 @@ RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionEntered) {
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionSuspended) {
DCHECK_EQ(4, args.length());
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, outer_promise, 1);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, reject_handler, 2);
CONVERT_BOOLEAN_ARG_CHECKED(is_predicted_as_caught, 3);
// Allocate the throwaway promise and fire the appropriate init
// hook for the throwaway promise (passing the {promise} as its
// parent).
Handle<JSPromise> throwaway = isolate->factory()->NewJSPromiseWithoutHook();
isolate->OnAsyncFunctionSuspended(throwaway, promise);
// The Promise will be thrown away and not handled, but it
// shouldn't trigger unhandled reject events as its work is done
throwaway->set_has_handler(true);
// Enable proper debug support for promises.
if (isolate->debug()->is_active()) {
Object::SetProperty(isolate, reject_handler,
isolate->factory()->promise_forwarding_handler_symbol(),
isolate->factory()->true_value(),
StoreOrigin::kMaybeKeyed,
Just(ShouldThrow::kThrowOnError))
.Check();
promise->set_handled_hint(is_predicted_as_caught);
// Mark the dependency to {outer_promise} in case the {throwaway}
// Promise is found on the Promise stack
Object::SetProperty(isolate, throwaway,
isolate->factory()->promise_handled_by_symbol(),
outer_promise, StoreOrigin::kMaybeKeyed,
Just(ShouldThrow::kThrowOnError))
.Check();
}
return *throwaway;
}
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionResumed) {
DCHECK_EQ(1, args.length());
HandleScope scope(isolate);
......@@ -836,7 +876,7 @@ RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionResumed) {
RUNTIME_FUNCTION(Runtime_DebugAsyncFunctionFinished) {
DCHECK_EQ(1, args.length());
HandleScope shs(isolate);
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 0);
isolate->OnAsyncFunctionFinished(promise);
return *promise;
......
......@@ -121,78 +121,6 @@ RUNTIME_FUNCTION(Runtime_PromiseHookInit) {
return ReadOnlyRoots(isolate).undefined_value();
}
namespace {
Handle<JSPromise> AwaitPromisesInitCommon(Isolate* isolate,
Handle<Object> value,
Handle<JSPromise> promise,
Handle<JSPromise> outer_promise,
Handle<JSFunction> reject_handler,
bool is_predicted_as_caught) {
// Allocate the throwaway promise and fire the appropriate init
// hook for the throwaway promise (passing the {promise} as its
// parent).
Handle<JSPromise> throwaway = isolate->factory()->NewJSPromiseWithoutHook();
isolate->OnAsyncFunctionSuspended(throwaway, promise);
// The Promise will be thrown away and not handled, but it
// shouldn't trigger unhandled reject events as its work is done
throwaway->set_has_handler(true);
// Enable proper debug support for promises.
if (isolate->debug()->is_active()) {
if (value->IsJSPromise()) {
Object::SetProperty(
isolate, reject_handler,
isolate->factory()->promise_forwarding_handler_symbol(),
isolate->factory()->true_value(), StoreOrigin::kMaybeKeyed,
Just(ShouldThrow::kThrowOnError))
.Check();
Handle<JSPromise>::cast(value)->set_handled_hint(is_predicted_as_caught);
}
// Mark the dependency to {outer_promise} in case the {throwaway}
// Promise is found on the Promise stack
Object::SetProperty(isolate, throwaway,
isolate->factory()->promise_handled_by_symbol(),
outer_promise, StoreOrigin::kMaybeKeyed,
Just(ShouldThrow::kThrowOnError))
.Check();
}
return throwaway;
}
} // namespace
RUNTIME_FUNCTION(Runtime_AwaitPromisesInit) {
DCHECK_EQ(5, args.length());
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 1);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, outer_promise, 2);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, reject_handler, 3);
CONVERT_BOOLEAN_ARG_CHECKED(is_predicted_as_caught, 4);
return *AwaitPromisesInitCommon(isolate, value, promise, outer_promise,
reject_handler, is_predicted_as_caught);
}
RUNTIME_FUNCTION(Runtime_AwaitPromisesInitOld) {
DCHECK_EQ(5, args.length());
HandleScope scope(isolate);
CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, promise, 1);
CONVERT_ARG_HANDLE_CHECKED(JSPromise, outer_promise, 2);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, reject_handler, 3);
CONVERT_BOOLEAN_ARG_CHECKED(is_predicted_as_caught, 4);
// Fire the init hook for the wrapper promise (that we created for the
// {value} previously).
isolate->RunAllPromiseHooks(PromiseHookType::kInit, promise, outer_promise);
return *AwaitPromisesInitCommon(isolate, value, promise, outer_promise,
reject_handler, is_predicted_as_caught);
}
RUNTIME_FUNCTION(Runtime_PromiseHookBefore) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -124,6 +124,7 @@ namespace internal {
F(ClearStepping, 0, 1) \
F(CollectGarbage, 1, 1) \
F(DebugAsyncFunctionEntered, 1, 1) \
F(DebugAsyncFunctionSuspended, 4, 1) \
F(DebugAsyncFunctionResumed, 1, 1) \
F(DebugAsyncFunctionFinished, 2, 1) \
F(DebugBreakAtEntry, 1, 1) \
......@@ -374,8 +375,6 @@ namespace internal {
F(PromiseHookAfter, 1, 1) \
F(PromiseHookBefore, 1, 1) \
F(PromiseHookInit, 2, 1) \
F(AwaitPromisesInit, 5, 1) \
F(AwaitPromisesInitOld, 5, 1) \
F(PromiseRejectEventFromStack, 2, 1) \
F(PromiseRevokeReject, 1, 1) \
F(PromiseStatus, 1, 1) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment