Commit e57b500e authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

[async-generators] Add fast-path for primitives in AsyncGeneratorYield.

For async generators that yield primitives, there's not really a point
in creating temporary promises first, just to immediately fulfill them
with the primitive values passed to `yield`. Instead we can skip those
steps and just directly schedule a PromiseFulfillReactionJobTask to do
the job.

This improves the execution time of fibonacci-async-es2017-native from
around 189ms to roughly 183ms, which corresponds to almost a ~3% boost
here.

Bug: v8:7253
Change-Id: I91413d2cc5ffdc6c851f72f91ff5c207e048c19d
Reviewed-on: https://chromium-review.googlesource.com/966607
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52016}
parent 5460f9cb
......@@ -548,11 +548,42 @@ TF_BUILTIN(AsyncGeneratorYield, AsyncGeneratorBuiltinsAssembler) {
Node* const request = LoadFirstAsyncGeneratorRequestFromQueue(generator);
Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(request);
// Mark the generator as "awaiting".
SetGeneratorAwaiting(generator);
Await(context, generator, value, outer_promise,
Builtins::kAsyncGeneratorYieldFulfill,
Builtins::kAsyncGeneratorAwaitReject, is_caught);
Return(UndefinedConstant());
// We can skip the creation of a temporary promise and the whole
// [[Resolve]] logic if we already know that the {value} that's
// being yielded is a primitive, as in that case we would immediately
// fulfill the temporary promise anyways and schedule a fulfill
// reaction job. This gives a nice performance boost for async
// generators that yield only primitives, e.g. numbers or strings.
Label if_primitive(this), if_generic(this);
GotoIfForceSlowPath(&if_generic);
GotoIf(IsPromiseHookEnabledOrDebugIsActive(), &if_generic);
GotoIf(TaggedIsSmi(value), &if_primitive);
Branch(IsJSReceiver(value), &if_generic, &if_primitive);
BIND(&if_generic);
{
Await(context, generator, value, outer_promise,
Builtins::kAsyncGeneratorYieldFulfill,
Builtins::kAsyncGeneratorAwaitReject, is_caught);
Return(UndefinedConstant());
}
BIND(&if_primitive);
{
// For primitive {value}s we can skip the allocation of the temporary
// promise and the resolution of that, and directly allocate the fulfill
// reaction job.
Node* const microtask = AllocatePromiseReactionJobTask(
Heap::kPromiseFulfillReactionJobTaskMapRootIndex, context, value,
HeapConstant(Builtins::CallableFor(
isolate(), Builtins::kAsyncGeneratorYieldFulfill)
.code()),
generator);
TailCallBuiltin(Builtins::kEnqueueMicrotask, context, microtask);
}
}
TF_BUILTIN(AsyncGeneratorYieldFulfill, AsyncGeneratorBuiltinsAssembler) {
......
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