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

[async-generators] Also avoid throwaway promise here.

This extends the previously introduced logic for implementing await
without having to allocate the throwaway promise and the additional
closures and context, to also cover await and yield inside of async
generators.

Bug: v8:7253
Change-Id: I011583a7714bbd148c54e5f204e2076630008db0
Reviewed-on: https://chromium-review.googlesource.com/924003
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51361}
parent 4a90e486
......@@ -1615,38 +1615,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kAsyncGeneratorAwaitUncaught, 1, false);
native_context()->set_async_generator_await_uncaught(*await_uncaught);
Handle<SharedFunctionInfo> info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorAwaitResolveClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_await_resolve_shared_fun(*info);
info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorAwaitRejectClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_await_reject_shared_fun(*info);
info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorYieldResolveClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_yield_resolve_shared_fun(*info);
info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorReturnResolveClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_return_resolve_shared_fun(*info);
info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorReturnClosedResolveClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_return_closed_resolve_shared_fun(
*info);
info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorReturnClosedRejectClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_return_closed_reject_shared_fun(
*info);
}
{ // --- A r r a y ---
......
......@@ -88,39 +88,9 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
CSA_SLOW_ASSERT(this, IsJSGeneratorObject(generator));
CSA_SLOW_ASSERT(this, IsJSPromise(outer_promise));
Node* const native_context = LoadNativeContext(context);
Node* const promise = AllocateAndInitJSPromise(native_context);
Node* const promise_reactions =
LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
Node* const fulfill_handler = HeapConstant(
Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitFulfill)
.code());
Node* const reject_handler = HeapConstant(
Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitReject)
.code());
Node* const reaction = AllocatePromiseReaction(
promise_reactions, generator, fulfill_handler, reject_handler);
StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reaction);
PromiseSetHasHandler(promise);
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « value »).
CallBuiltin(Builtins::kResolvePromise, native_context, promise, awaited);
{
Label done(this);
GotoIfNot(IsDebugActive(), &done);
CallRuntime(Runtime::kSetProperty, native_context, generator,
LoadRoot(Heap::kgenerator_outer_promise_symbolRootIndex),
outer_promise, SmiConstant(LanguageMode::kStrict));
if (is_predicted_as_caught) {
GotoIf(TaggedIsSmi(awaited), &done);
GotoIfNot(IsJSPromise(awaited), &done);
PromiseSetHandledHint(awaited);
}
Goto(&done);
BIND(&done);
}
Await(context, generator, awaited, outer_promise,
Builtins::kAsyncFunctionAwaitFulfill,
Builtins::kAsyncFunctionAwaitReject, is_predicted_as_caught);
// Return outer promise to avoid adding an load of the outer promise before
// suspending in BytecodeGenerator.
......
......@@ -13,171 +13,67 @@ namespace internal {
using compiler::Node;
namespace {
// Describe fields of Context associated with the AsyncIterator unwrap closure.
class ValueUnwrapContext {
public:
enum Fields { kDoneSlot = Context::MIN_CONTEXT_SLOTS, kLength };
};
} // namespace
Node* AsyncBuiltinsAssembler::Await(
Node* context, Node* generator, Node* value, Node* outer_promise,
int context_length, const ContextInitializer& init_closure_context,
Node* on_resolve_context_index, Node* on_reject_context_index,
void AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value,
Node* outer_promise,
Builtins::Name fulfill_builtin,
Builtins::Name reject_builtin,
Node* is_predicted_as_caught) {
DCHECK_GE(context_length, Context::MIN_CONTEXT_SLOTS);
CSA_SLOW_ASSERT(this, Word32Or(IsJSAsyncGeneratorObject(generator),
IsJSGeneratorObject(generator)));
CSA_SLOW_ASSERT(this, IsJSPromise(outer_promise));
CSA_SLOW_ASSERT(this, IsBoolean(is_predicted_as_caught));
Node* const native_context = LoadNativeContext(context);
static const int kWrappedPromiseOffset = FixedArray::SizeFor(context_length);
static const int kThrowawayPromiseOffset =
kWrappedPromiseOffset + JSPromise::kSizeWithEmbedderFields;
static const int kResolveClosureOffset =
kThrowawayPromiseOffset + JSPromise::kSizeWithEmbedderFields;
static const int kRejectClosureOffset =
kResolveClosureOffset + JSFunction::kSizeWithoutPrototype;
static const int kTotalSize =
kRejectClosureOffset + JSFunction::kSizeWithoutPrototype;
Node* const base = AllocateInNewSpace(kTotalSize);
Node* const closure_context = base;
{
// Initialize closure context
InitializeFunctionContext(native_context, closure_context, context_length);
init_closure_context(closure_context);
}
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
Node* const promise_fun =
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(promise_fun)));
Node* const promise_map =
LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
// Assert that the JSPromise map has an instance size is
// JSPromise::kSizeWithEmbedderFields.
CSA_ASSERT(this, WordEqual(LoadMapInstanceSizeInWords(promise_map),
IntPtrConstant(JSPromise::kSizeWithEmbedderFields /
kPointerSize)));
Node* const wrapped_value = InnerAllocate(base, kWrappedPromiseOffset);
{
// Initialize Promise
StoreMapNoWriteBarrier(wrapped_value, promise_map);
InitializeJSObjectFromMap(
wrapped_value, promise_map,
IntPtrConstant(JSPromise::kSizeWithEmbedderFields));
PromiseInit(wrapped_value);
}
Node* const throwaway = InnerAllocate(base, kThrowawayPromiseOffset);
{
// Initialize throwawayPromise
StoreMapNoWriteBarrier(throwaway, promise_map);
InitializeJSObjectFromMap(
throwaway, promise_map,
IntPtrConstant(JSPromise::kSizeWithEmbedderFields));
PromiseInit(throwaway);
}
Node* const on_resolve = InnerAllocate(base, kResolveClosureOffset);
{
// Initialize resolve handler
InitializeNativeClosure(closure_context, native_context, on_resolve,
on_resolve_context_index);
}
Node* const on_reject = InnerAllocate(base, kRejectClosureOffset);
{
// Initialize reject handler
InitializeNativeClosure(closure_context, native_context, on_reject,
on_reject_context_index);
}
{
// Add PromiseHooks if needed
Label next(this);
GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &next);
CallRuntime(Runtime::kPromiseHookInit, context, wrapped_value,
outer_promise);
CallRuntime(Runtime::kPromiseHookInit, context, throwaway, wrapped_value);
Goto(&next);
BIND(&next);
}
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « promise »).
CallBuiltin(Builtins::kResolvePromise, context, wrapped_value, value);
// The Promise will be thrown away and not handled, but it shouldn't trigger
// unhandled reject events as its work is done
PromiseSetHasHandler(throwaway);
Label do_perform_promise_then(this);
GotoIfNot(IsDebugActive(), &do_perform_promise_then);
{
Label common(this);
GotoIf(TaggedIsSmi(value), &common);
GotoIfNot(HasInstanceType(value, JS_PROMISE_TYPE), &common);
{
// Mark the reject handler callback to be a forwarding edge, rather
// than a meaningful catch handler
Node* const key =
HeapConstant(factory()->promise_forwarding_handler_symbol());
CallRuntime(Runtime::kSetProperty, context, on_reject, key,
TrueConstant(), SmiConstant(LanguageMode::kStrict));
GotoIf(IsFalse(is_predicted_as_caught), &common);
// TODO(bmeurer): This could be optimized and folded into a single allocation.
Node* const promise = AllocateAndInitJSPromise(native_context);
Node* const promise_reactions =
LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
Node* const fulfill_handler =
HeapConstant(Builtins::CallableFor(isolate(), fulfill_builtin).code());
Node* const reject_handler =
HeapConstant(Builtins::CallableFor(isolate(), reject_builtin).code());
Node* const reaction = AllocatePromiseReaction(
promise_reactions, generator, fulfill_handler, reject_handler);
StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reaction);
PromiseSetHasHandler(promise);
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « value »).
CallBuiltin(Builtins::kResolvePromise, native_context, promise, value);
// When debugging, we need to link from the {generator} to the
// {outer_promise} of the async function/generator.
Label done(this);
GotoIfNot(IsDebugActive(), &done);
CallRuntime(Runtime::kSetProperty, native_context, generator,
LoadRoot(Heap::kgenerator_outer_promise_symbolRootIndex),
outer_promise, SmiConstant(LanguageMode::kStrict));
GotoIf(IsFalse(is_predicted_as_caught), &done);
GotoIf(TaggedIsSmi(value), &done);
GotoIfNot(IsJSPromise(value), &done);
PromiseSetHandledHint(value);
}
Goto(&common);
BIND(&common);
// Mark the dependency to outer Promise in case the throwaway Promise is
// found on the Promise stack
CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE));
Node* const key = HeapConstant(factory()->promise_handled_by_symbol());
CallRuntime(Runtime::kSetProperty, context, throwaway, key, outer_promise,
SmiConstant(LanguageMode::kStrict));
}
Goto(&do_perform_promise_then);
BIND(&do_perform_promise_then);
return CallBuiltin(Builtins::kPerformPromiseThen, context, wrapped_value,
on_resolve, on_reject, throwaway);
Goto(&done);
BIND(&done);
}
void AsyncBuiltinsAssembler::InitializeNativeClosure(Node* context,
Node* native_context,
Node* function,
Node* context_index) {
Node* const function_map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
// Ensure that we don't have to initialize prototype_or_initial_map field of
// JSFunction.
CSA_ASSERT(this, WordEqual(LoadMapInstanceSizeInWords(function_map),
IntPtrConstant(JSFunction::kSizeWithoutPrototype /
kPointerSize)));
STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize);
StoreMapNoWriteBarrier(function, function_map);
StoreObjectFieldRoot(function, JSObject::kPropertiesOrHashOffset,
Heap::kEmptyFixedArrayRootIndex);
StoreObjectFieldRoot(function, JSObject::kElementsOffset,
Heap::kEmptyFixedArrayRootIndex);
StoreObjectFieldRoot(function, JSFunction::kFeedbackVectorOffset,
Heap::kUndefinedCellRootIndex);
Node* shared_info = LoadContextElement(native_context, context_index);
CSA_ASSERT(this, IsSharedFunctionInfo(shared_info));
StoreObjectFieldNoWriteBarrier(
function, JSFunction::kSharedFunctionInfoOffset, shared_info);
StoreObjectFieldNoWriteBarrier(function, JSFunction::kContextOffset, context);
Node* const code =
LoadObjectField(shared_info, SharedFunctionInfo::kCodeOffset);
StoreObjectFieldNoWriteBarrier(function, JSFunction::kCodeOffset, code);
void AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value,
Node* outer_promise,
Builtins::Name fulfill_builtin,
Builtins::Name reject_builtin,
bool is_predicted_as_caught) {
return Await(context, generator, value, outer_promise, fulfill_builtin,
reject_builtin, BooleanConstant(is_predicted_as_caught));
}
namespace {
// Describe fields of Context associated with the AsyncIterator unwrap closure.
class ValueUnwrapContext {
public:
enum Fields { kDoneSlot = Context::MIN_CONTEXT_SLOTS, kLength };
};
} // namespace
Node* AsyncBuiltinsAssembler::CreateUnwrapClosure(Node* native_context,
Node* done) {
Node* const map = LoadContextElement(
......
......@@ -16,48 +16,23 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler {
: PromiseBuiltinsAssembler(state) {}
protected:
typedef std::function<void(Node*)> ContextInitializer;
// Perform steps to resume generator after `value` is resolved.
// `on_reject_context_index` is an index into the Native Context, which should
// point to a SharedFunctioninfo instance used to create the closure. The
// value following the reject index should be a similar value for the resolve
// closure. Returns the Promise-wrapped `value`.
Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise,
int context_length,
const ContextInitializer& init_closure_context,
Node* on_resolve_context_index, Node* on_reject_context_index,
void Await(Node* context, Node* generator, Node* value, Node* outer_promise,
Builtins::Name fulfill_builtin, Builtins::Name reject_builtin,
Node* is_predicted_as_caught);
Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise,
int context_length,
const ContextInitializer& init_closure_context,
int on_resolve_context_index, int on_reject_context_index,
Node* is_predicted_as_caught) {
return Await(context, generator, value, outer_promise, context_length,
init_closure_context, IntPtrConstant(on_resolve_context_index),
IntPtrConstant(on_reject_context_index),
is_predicted_as_caught);
}
Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise,
int context_length,
const ContextInitializer& init_closure_context,
int on_resolve_context_index, int on_reject_context_index,
bool is_predicted_as_caught) {
return Await(context, generator, value, outer_promise, context_length,
init_closure_context, on_resolve_context_index,
on_reject_context_index,
BooleanConstant(is_predicted_as_caught));
}
void Await(Node* context, Node* generator, Node* value, Node* outer_promise,
Builtins::Name fulfill_builtin, Builtins::Name reject_builtin,
bool is_predicted_as_caught);
// Return a new built-in function object as defined in
// Async Iterator Value Unwrap Functions
Node* CreateUnwrapClosure(Node* const native_context, Node* const done);
private:
void InitializeNativeClosure(Node* context, Node* native_context,
Node* function, Node* context_index);
Node* AllocateAsyncIteratorValueUnwrapContext(Node* native_context,
Node* done);
Node* AllocateAwaitPromiseJobTask(Node* generator, Node* fulfill_handler,
Node* reject_handler, Node* promise,
Node* context);
};
} // namespace internal
......
......@@ -140,8 +140,8 @@ class AsyncGeneratorBuiltinsAssembler : public AsyncBuiltinsAssembler {
// for AsyncGenerators.
template <typename Descriptor>
void AsyncGeneratorAwait(bool is_catchable);
void AsyncGeneratorAwaitResumeClosure(
Node* context, Node* value,
void AsyncGeneratorAwaitResume(
Node* context, Node* generator, Node* argument,
JSAsyncGeneratorObject::ResumeMode resume_mode);
};
......@@ -219,11 +219,9 @@ Node* AsyncGeneratorBuiltinsAssembler::AllocateAsyncGeneratorRequest(
return request;
}
void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure(
Node* context, Node* value,
void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResume(
Node* context, Node* generator, Node* argument,
JSAsyncGeneratorObject::ResumeMode resume_mode) {
Node* const generator =
LoadContextElement(context, AwaitContext::kGeneratorSlot);
CSA_SLOW_ASSERT(this, TaggedIsAsyncGenerator(generator));
SetGeneratorNotAwaiting(generator);
......@@ -235,7 +233,8 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure(
JSGeneratorObject::kResumeModeOffset,
SmiConstant(resume_mode));
CallStub(CodeFactory::ResumeGenerator(isolate()), context, value, generator);
CallStub(CodeFactory::ResumeGenerator(isolate()), context, argument,
generator);
TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
}
......@@ -251,20 +250,13 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwait(bool is_catchable) {
Node* const request = LoadFirstAsyncGeneratorRequestFromQueue(generator);
CSA_ASSERT(this, IsNotUndefined(request));
ContextInitializer init_closure_context = [&](Node* context) {
StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot,
generator);
};
Node* outer_promise =
LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset);
const int resolve_index = Context::ASYNC_GENERATOR_AWAIT_RESOLVE_SHARED_FUN;
const int reject_index = Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN;
SetGeneratorAwaiting(generator);
Await(context, generator, value, outer_promise, AwaitContext::kLength,
init_closure_context, resolve_index, reject_index, is_catchable);
Await(context, generator, value, outer_promise,
Builtins::kAsyncGeneratorAwaitFulfill,
Builtins::kAsyncGeneratorAwaitReject, is_catchable);
Return(UndefinedConstant());
}
......@@ -375,17 +367,19 @@ TF_BUILTIN(AsyncGeneratorPrototypeThrow, AsyncGeneratorBuiltinsAssembler) {
"[AsyncGenerator].prototype.throw");
}
TF_BUILTIN(AsyncGeneratorAwaitResolveClosure, AsyncGeneratorBuiltinsAssembler) {
Node* value = Parameter(Descriptor::kValue);
Node* context = Parameter(Descriptor::kContext);
AsyncGeneratorAwaitResumeClosure(context, value,
TF_BUILTIN(AsyncGeneratorAwaitFulfill, AsyncGeneratorBuiltinsAssembler) {
Node* const generator = Parameter(Descriptor::kGenerator);
Node* const argument = Parameter(Descriptor::kArgument);
Node* const context = Parameter(Descriptor::kContext);
AsyncGeneratorAwaitResume(context, generator, argument,
JSAsyncGeneratorObject::kNext);
}
TF_BUILTIN(AsyncGeneratorAwaitRejectClosure, AsyncGeneratorBuiltinsAssembler) {
Node* value = Parameter(Descriptor::kValue);
Node* context = Parameter(Descriptor::kContext);
AsyncGeneratorAwaitResumeClosure(context, value,
TF_BUILTIN(AsyncGeneratorAwaitReject, AsyncGeneratorBuiltinsAssembler) {
Node* const generator = Parameter(Descriptor::kGenerator);
Node* const argument = Parameter(Descriptor::kArgument);
Node* const context = Parameter(Descriptor::kContext);
AsyncGeneratorAwaitResume(context, generator, argument,
JSAsyncGeneratorObject::kThrow);
}
......@@ -554,31 +548,23 @@ TF_BUILTIN(AsyncGeneratorYield, AsyncGeneratorBuiltinsAssembler) {
Node* const request = LoadFirstAsyncGeneratorRequestFromQueue(generator);
Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(request);
ContextInitializer init_closure_context = [&](Node* context) {
StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot,
generator);
};
const int on_resolve = Context::ASYNC_GENERATOR_YIELD_RESOLVE_SHARED_FUN;
const int on_reject = Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN;
SetGeneratorAwaiting(generator);
Await(context, generator, value, outer_promise, AwaitContext::kLength,
init_closure_context, on_resolve, on_reject, is_caught);
Await(context, generator, value, outer_promise,
Builtins::kAsyncGeneratorYieldFulfill,
Builtins::kAsyncGeneratorAwaitReject, is_caught);
Return(UndefinedConstant());
}
TF_BUILTIN(AsyncGeneratorYieldResolveClosure, AsyncGeneratorBuiltinsAssembler) {
TF_BUILTIN(AsyncGeneratorYieldFulfill, AsyncGeneratorBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue);
Node* const generator =
LoadContextElement(context, AwaitContext::kGeneratorSlot);
Node* const generator = Parameter(Descriptor::kGenerator);
Node* const argument = Parameter(Descriptor::kArgument);
SetGeneratorNotAwaiting(generator);
// Per proposal-async-iteration/#sec-asyncgeneratoryield step 9
// Return ! AsyncGeneratorResolve(_F_.[[Generator]], _value_, *false*).
CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, value,
CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, argument,
FalseConstant());
TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
......@@ -604,39 +590,33 @@ TF_BUILTIN(AsyncGeneratorReturn, AsyncGeneratorBuiltinsAssembler) {
Node* const generator = Parameter(Descriptor::kGenerator);
Node* const value = Parameter(Descriptor::kValue);
Node* const is_caught = Parameter(Descriptor::kIsCaught);
Node* const context = Parameter(Descriptor::kContext);
Node* const req = LoadFirstAsyncGeneratorRequestFromQueue(generator);
Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(req);
CSA_ASSERT(this, IsNotUndefined(req));
Label perform_await(this);
VARIABLE(var_on_resolve, MachineType::PointerRepresentation(),
IntPtrConstant(
Context::ASYNC_GENERATOR_RETURN_CLOSED_RESOLVE_SHARED_FUN));
VARIABLE(
var_on_reject, MachineType::PointerRepresentation(),
IntPtrConstant(Context::ASYNC_GENERATOR_RETURN_CLOSED_REJECT_SHARED_FUN));
Label if_closed(this, Label::kDeferred), if_not_closed(this), done(this);
Node* const state = LoadGeneratorState(generator);
GotoIf(IsGeneratorStateClosed(state), &perform_await);
var_on_resolve.Bind(
IntPtrConstant(Context::ASYNC_GENERATOR_RETURN_RESOLVE_SHARED_FUN));
var_on_reject.Bind(
IntPtrConstant(Context::ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN));
Goto(&perform_await);
BIND(&perform_await);
SetGeneratorAwaiting(generator);
Branch(IsGeneratorStateClosed(state), &if_closed, &if_not_closed);
ContextInitializer init_closure_context = [&](Node* context) {
StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot,
generator);
};
BIND(&if_closed);
{
Await(context, generator, value, outer_promise,
Builtins::kAsyncGeneratorReturnClosedFulfill,
Builtins::kAsyncGeneratorReturnClosedReject, is_caught);
Goto(&done);
}
SetGeneratorAwaiting(generator);
Node* const context = Parameter(Descriptor::kContext);
Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(req);
Await(context, generator, value, outer_promise, AwaitContext::kLength,
init_closure_context, var_on_resolve.value(), var_on_reject.value(),
is_caught);
BIND(&if_not_closed);
{
Await(context, generator, value, outer_promise,
Builtins::kAsyncGeneratorReturnFulfill,
Builtins::kAsyncGeneratorAwaitReject, is_caught);
Goto(&done);
}
BIND(&done);
Return(UndefinedConstant());
}
......@@ -644,47 +624,44 @@ TF_BUILTIN(AsyncGeneratorReturn, AsyncGeneratorBuiltinsAssembler) {
// Resume the generator with "return" resume_mode, and finally perform
// AsyncGeneratorResumeNext. Per
// proposal-async-iteration/#sec-asyncgeneratoryield step 8.e
TF_BUILTIN(AsyncGeneratorReturnResolveClosure,
AsyncGeneratorBuiltinsAssembler) {
TF_BUILTIN(AsyncGeneratorReturnFulfill, AsyncGeneratorBuiltinsAssembler) {
Node* const generator = Parameter(Descriptor::kGenerator);
Node* const argument = Parameter(Descriptor::kArgument);
Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue);
AsyncGeneratorAwaitResumeClosure(context, value, JSGeneratorObject::kReturn);
AsyncGeneratorAwaitResume(context, generator, argument,
JSGeneratorObject::kReturn);
}
// On-resolve closure for Await in AsyncGeneratorReturn
// Perform AsyncGeneratorResolve({awaited_value}, true) and finally perform
// AsyncGeneratorResumeNext.
TF_BUILTIN(AsyncGeneratorReturnClosedResolveClosure,
AsyncGeneratorBuiltinsAssembler) {
TF_BUILTIN(AsyncGeneratorReturnClosedFulfill, AsyncGeneratorBuiltinsAssembler) {
Node* const generator = Parameter(Descriptor::kGenerator);
Node* const argument = Parameter(Descriptor::kArgument);
Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue);
Node* const generator =
LoadContextElement(context, AwaitContext::kGeneratorSlot);
SetGeneratorNotAwaiting(generator);
// https://tc39.github.io/proposal-async-iteration/
// #async-generator-resume-next-return-processor-fulfilled step 2:
// Return ! AsyncGeneratorResolve(_F_.[[Generator]], _value_, *true*).
CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, value,
CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, argument,
TrueConstant());
TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
}
TF_BUILTIN(AsyncGeneratorReturnClosedRejectClosure,
AsyncGeneratorBuiltinsAssembler) {
TF_BUILTIN(AsyncGeneratorReturnClosedReject, AsyncGeneratorBuiltinsAssembler) {
Node* const generator = Parameter(Descriptor::kGenerator);
Node* const argument = Parameter(Descriptor::kArgument);
Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue);
Node* const generator =
LoadContextElement(context, AwaitContext::kGeneratorSlot);
SetGeneratorNotAwaiting(generator);
// https://tc39.github.io/proposal-async-iteration/
// #async-generator-resume-next-return-processor-rejected step 2:
// Return ! AsyncGeneratorReject(_F_.[[Generator]], _reason_).
CallBuiltin(Builtins::kAsyncGeneratorReject, context, generator, value);
CallBuiltin(Builtins::kAsyncGeneratorReject, context, generator, argument);
TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
}
......
......@@ -1173,6 +1173,17 @@ namespace internal {
\
/* AsyncGenerator */ \
\
/* Await (proposal-async-iteration/#await), with resume behaviour */ \
/* specific to Async Generators. Internal / Not exposed to JS code. */ \
TFJ(AsyncGeneratorAwaitCaught, 2, kGenerator, kAwaited) \
TFJ(AsyncGeneratorAwaitUncaught, 2, kGenerator, kAwaited) \
TFC(AsyncGeneratorAwaitFulfill, PromiseReactionHandler, 1) \
TFC(AsyncGeneratorAwaitReject, PromiseReactionHandler, 1) \
TFC(AsyncGeneratorYieldFulfill, PromiseReactionHandler, 1) \
TFC(AsyncGeneratorReturnClosedFulfill, PromiseReactionHandler, 1) \
TFC(AsyncGeneratorReturnClosedReject, PromiseReactionHandler, 1) \
TFC(AsyncGeneratorReturnFulfill, PromiseReactionHandler, 1) \
\
TFS(AsyncGeneratorResolve, kGenerator, kValue, kDone) \
TFS(AsyncGeneratorReject, kGenerator, kValue) \
TFS(AsyncGeneratorYield, kGenerator, kValue, kIsCaught) \
......@@ -1195,17 +1206,6 @@ namespace internal {
TFJ(AsyncGeneratorPrototypeThrow, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
\
/* Await (proposal-async-iteration/#await), with resume behaviour */ \
/* specific to Async Generators. Internal / Not exposed to JS code. */ \
TFJ(AsyncGeneratorAwaitCaught, 2, kGenerator, kAwaited) \
TFJ(AsyncGeneratorAwaitUncaught, 2, kGenerator, kAwaited) \
TFJ(AsyncGeneratorAwaitResolveClosure, 1, kValue) \
TFJ(AsyncGeneratorAwaitRejectClosure, 1, kValue) \
TFJ(AsyncGeneratorYieldResolveClosure, 1, kValue) \
TFJ(AsyncGeneratorReturnClosedResolveClosure, 1, kValue) \
TFJ(AsyncGeneratorReturnClosedRejectClosure, 1, kValue) \
TFJ(AsyncGeneratorReturnResolveClosure, 1, kValue) \
\
/* Async-from-Sync Iterator */ \
\
/* %AsyncFromSyncIteratorPrototype% */ \
......
......@@ -235,6 +235,8 @@ bool Builtins::IsLazy(int index) {
case kArrayReduceRightLoopLazyDeoptContinuation:
case kArraySomeLoopEagerDeoptContinuation: // https://crbug.com/v8/6786.
case kArraySomeLoopLazyDeoptContinuation: // https://crbug.com/v8/6786.
case kAsyncGeneratorAwaitCaught: // https://crbug.com/v8/6786.
case kAsyncGeneratorAwaitUncaught: // https://crbug.com/v8/6786.
case kCheckOptimizationMarker:
case kCompileLazy:
case kDeserializeLazy:
......
......@@ -4561,6 +4561,10 @@ Node* CodeStubAssembler::IsJSArrayMap(Node* map) {
return IsJSArrayInstanceType(LoadMapInstanceType(map));
}
Node* CodeStubAssembler::IsJSAsyncGeneratorObject(Node* object) {
return HasInstanceType(object, JS_ASYNC_GENERATOR_OBJECT_TYPE);
}
Node* CodeStubAssembler::IsFixedArray(Node* object) {
return HasInstanceType(object, FIXED_ARRAY_TYPE);
}
......
......@@ -1121,6 +1121,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IsJSArrayInstanceType(Node* instance_type);
Node* IsJSArrayMap(Node* object);
Node* IsJSArray(Node* object);
Node* IsJSAsyncGeneratorObject(Node* object);
Node* IsJSFunctionInstanceType(Node* instance_type);
Node* IsJSFunctionMap(Node* object);
Node* IsJSFunction(Node* object);
......
......@@ -211,18 +211,6 @@ enum ContextLookupFlags {
async_generator_function_function) \
V(ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN, SharedFunctionInfo, \
async_iterator_value_unwrap_shared_fun) \
V(ASYNC_GENERATOR_AWAIT_REJECT_SHARED_FUN, SharedFunctionInfo, \
async_generator_await_reject_shared_fun) \
V(ASYNC_GENERATOR_AWAIT_RESOLVE_SHARED_FUN, SharedFunctionInfo, \
async_generator_await_resolve_shared_fun) \
V(ASYNC_GENERATOR_YIELD_RESOLVE_SHARED_FUN, SharedFunctionInfo, \
async_generator_yield_resolve_shared_fun) \
V(ASYNC_GENERATOR_RETURN_RESOLVE_SHARED_FUN, SharedFunctionInfo, \
async_generator_return_resolve_shared_fun) \
V(ASYNC_GENERATOR_RETURN_CLOSED_RESOLVE_SHARED_FUN, SharedFunctionInfo, \
async_generator_return_closed_resolve_shared_fun) \
V(ASYNC_GENERATOR_RETURN_CLOSED_REJECT_SHARED_FUN, SharedFunctionInfo, \
async_generator_return_closed_reject_shared_fun) \
V(ATOMICS_OBJECT, JSObject, atomics_object) \
V(BIGINT_FUNCTION_INDEX, JSFunction, bigint_function) \
V(BIGINT64_ARRAY_FUN_INDEX, JSFunction, bigint64_array_fun) \
......
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