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, ...@@ -1615,38 +1615,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
SimpleCreateFunction(isolate, factory->empty_string(), SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kAsyncGeneratorAwaitUncaught, 1, false); Builtins::kAsyncGeneratorAwaitUncaught, 1, false);
native_context()->set_async_generator_await_uncaught(*await_uncaught); 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 --- { // --- A r r a y ---
......
...@@ -88,39 +88,9 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait( ...@@ -88,39 +88,9 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
CSA_SLOW_ASSERT(this, IsJSGeneratorObject(generator)); CSA_SLOW_ASSERT(this, IsJSGeneratorObject(generator));
CSA_SLOW_ASSERT(this, IsJSPromise(outer_promise)); CSA_SLOW_ASSERT(this, IsJSPromise(outer_promise));
Node* const native_context = LoadNativeContext(context); Await(context, generator, awaited, outer_promise,
Node* const promise = AllocateAndInitJSPromise(native_context); Builtins::kAsyncFunctionAwaitFulfill,
Builtins::kAsyncFunctionAwaitReject, is_predicted_as_caught);
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);
}
// Return outer promise to avoid adding an load of the outer promise before // Return outer promise to avoid adding an load of the outer promise before
// suspending in BytecodeGenerator. // suspending in BytecodeGenerator.
......
...@@ -13,171 +13,67 @@ namespace internal { ...@@ -13,171 +13,67 @@ namespace internal {
using compiler::Node; using compiler::Node;
namespace { void AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value,
// Describe fields of Context associated with the AsyncIterator unwrap closure. Node* outer_promise,
class ValueUnwrapContext { Builtins::Name fulfill_builtin,
public: Builtins::Name reject_builtin,
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,
Node* is_predicted_as_caught) { 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); Node* const native_context = LoadNativeContext(context);
static const int kWrappedPromiseOffset = FixedArray::SizeFor(context_length); // TODO(bmeurer): This could be optimized and folded into a single allocation.
static const int kThrowawayPromiseOffset = Node* const promise = AllocateAndInitJSPromise(native_context);
kWrappedPromiseOffset + JSPromise::kSizeWithEmbedderFields; Node* const promise_reactions =
static const int kResolveClosureOffset = LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
kThrowawayPromiseOffset + JSPromise::kSizeWithEmbedderFields; Node* const fulfill_handler =
static const int kRejectClosureOffset = HeapConstant(Builtins::CallableFor(isolate(), fulfill_builtin).code());
kResolveClosureOffset + JSFunction::kSizeWithoutPrototype; Node* const reject_handler =
static const int kTotalSize = HeapConstant(Builtins::CallableFor(isolate(), reject_builtin).code());
kRejectClosureOffset + JSFunction::kSizeWithoutPrototype; Node* const reaction = AllocatePromiseReaction(
promise_reactions, generator, fulfill_handler, reject_handler);
Node* const base = AllocateInNewSpace(kTotalSize); StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reaction);
Node* const closure_context = base; PromiseSetHasHandler(promise);
{
// Initialize closure context // Perform ! Call(promiseCapability.[[Resolve]], undefined, « value »).
InitializeFunctionContext(native_context, closure_context, context_length); CallBuiltin(Builtins::kResolvePromise, native_context, promise, value);
init_closure_context(closure_context);
} // When debugging, we need to link from the {generator} to the
// {outer_promise} of the async function/generator.
// Let promiseCapability be ! NewPromiseCapability(%Promise%). Label done(this);
Node* const promise_fun = GotoIfNot(IsDebugActive(), &done);
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); CallRuntime(Runtime::kSetProperty, native_context, generator,
CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(promise_fun))); LoadRoot(Heap::kgenerator_outer_promise_symbolRootIndex),
Node* const promise_map = outer_promise, SmiConstant(LanguageMode::kStrict));
LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); GotoIf(IsFalse(is_predicted_as_caught), &done);
// Assert that the JSPromise map has an instance size is GotoIf(TaggedIsSmi(value), &done);
// JSPromise::kSizeWithEmbedderFields. GotoIfNot(IsJSPromise(value), &done);
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);
PromiseSetHandledHint(value); PromiseSetHandledHint(value);
} Goto(&done);
BIND(&done);
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);
} }
void AsyncBuiltinsAssembler::InitializeNativeClosure(Node* context, void AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value,
Node* native_context, Node* outer_promise,
Node* function, Builtins::Name fulfill_builtin,
Node* context_index) { Builtins::Name reject_builtin,
Node* const function_map = LoadContextElement( bool is_predicted_as_caught) {
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); return Await(context, generator, value, outer_promise, fulfill_builtin,
// Ensure that we don't have to initialize prototype_or_initial_map field of reject_builtin, BooleanConstant(is_predicted_as_caught));
// 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);
} }
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* AsyncBuiltinsAssembler::CreateUnwrapClosure(Node* native_context,
Node* done) { Node* done) {
Node* const map = LoadContextElement( Node* const map = LoadContextElement(
......
...@@ -16,48 +16,23 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler { ...@@ -16,48 +16,23 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler {
: PromiseBuiltinsAssembler(state) {} : PromiseBuiltinsAssembler(state) {}
protected: protected:
typedef std::function<void(Node*)> ContextInitializer; void Await(Node* context, Node* generator, Node* value, Node* outer_promise,
Builtins::Name fulfill_builtin, Builtins::Name reject_builtin,
// 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,
Node* is_predicted_as_caught); Node* is_predicted_as_caught);
Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise, void Await(Node* context, Node* generator, Node* value, Node* outer_promise,
int context_length, Builtins::Name fulfill_builtin, Builtins::Name reject_builtin,
const ContextInitializer& init_closure_context, bool is_predicted_as_caught);
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));
}
// Return a new built-in function object as defined in // Return a new built-in function object as defined in
// Async Iterator Value Unwrap Functions // Async Iterator Value Unwrap Functions
Node* CreateUnwrapClosure(Node* const native_context, Node* const done); Node* CreateUnwrapClosure(Node* const native_context, Node* const done);
private: private:
void InitializeNativeClosure(Node* context, Node* native_context,
Node* function, Node* context_index);
Node* AllocateAsyncIteratorValueUnwrapContext(Node* native_context, Node* AllocateAsyncIteratorValueUnwrapContext(Node* native_context,
Node* done); Node* done);
Node* AllocateAwaitPromiseJobTask(Node* generator, Node* fulfill_handler,
Node* reject_handler, Node* promise,
Node* context);
}; };
} // namespace internal } // namespace internal
......
...@@ -140,8 +140,8 @@ class AsyncGeneratorBuiltinsAssembler : public AsyncBuiltinsAssembler { ...@@ -140,8 +140,8 @@ class AsyncGeneratorBuiltinsAssembler : public AsyncBuiltinsAssembler {
// for AsyncGenerators. // for AsyncGenerators.
template <typename Descriptor> template <typename Descriptor>
void AsyncGeneratorAwait(bool is_catchable); void AsyncGeneratorAwait(bool is_catchable);
void AsyncGeneratorAwaitResumeClosure( void AsyncGeneratorAwaitResume(
Node* context, Node* value, Node* context, Node* generator, Node* argument,
JSAsyncGeneratorObject::ResumeMode resume_mode); JSAsyncGeneratorObject::ResumeMode resume_mode);
}; };
...@@ -219,11 +219,9 @@ Node* AsyncGeneratorBuiltinsAssembler::AllocateAsyncGeneratorRequest( ...@@ -219,11 +219,9 @@ Node* AsyncGeneratorBuiltinsAssembler::AllocateAsyncGeneratorRequest(
return request; return request;
} }
void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure( void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResume(
Node* context, Node* value, Node* context, Node* generator, Node* argument,
JSAsyncGeneratorObject::ResumeMode resume_mode) { JSAsyncGeneratorObject::ResumeMode resume_mode) {
Node* const generator =
LoadContextElement(context, AwaitContext::kGeneratorSlot);
CSA_SLOW_ASSERT(this, TaggedIsAsyncGenerator(generator)); CSA_SLOW_ASSERT(this, TaggedIsAsyncGenerator(generator));
SetGeneratorNotAwaiting(generator); SetGeneratorNotAwaiting(generator);
...@@ -235,7 +233,8 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure( ...@@ -235,7 +233,8 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwaitResumeClosure(
JSGeneratorObject::kResumeModeOffset, JSGeneratorObject::kResumeModeOffset,
SmiConstant(resume_mode)); SmiConstant(resume_mode));
CallStub(CodeFactory::ResumeGenerator(isolate()), context, value, generator); CallStub(CodeFactory::ResumeGenerator(isolate()), context, argument,
generator);
TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator); TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
} }
...@@ -251,20 +250,13 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwait(bool is_catchable) { ...@@ -251,20 +250,13 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorAwait(bool is_catchable) {
Node* const request = LoadFirstAsyncGeneratorRequestFromQueue(generator); Node* const request = LoadFirstAsyncGeneratorRequestFromQueue(generator);
CSA_ASSERT(this, IsNotUndefined(request)); CSA_ASSERT(this, IsNotUndefined(request));
ContextInitializer init_closure_context = [&](Node* context) {
StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot,
generator);
};
Node* outer_promise = Node* outer_promise =
LoadObjectField(request, AsyncGeneratorRequest::kPromiseOffset); 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); SetGeneratorAwaiting(generator);
Await(context, generator, value, outer_promise, AwaitContext::kLength, Await(context, generator, value, outer_promise,
init_closure_context, resolve_index, reject_index, is_catchable); Builtins::kAsyncGeneratorAwaitFulfill,
Builtins::kAsyncGeneratorAwaitReject, is_catchable);
Return(UndefinedConstant()); Return(UndefinedConstant());
} }
...@@ -375,17 +367,19 @@ TF_BUILTIN(AsyncGeneratorPrototypeThrow, AsyncGeneratorBuiltinsAssembler) { ...@@ -375,17 +367,19 @@ TF_BUILTIN(AsyncGeneratorPrototypeThrow, AsyncGeneratorBuiltinsAssembler) {
"[AsyncGenerator].prototype.throw"); "[AsyncGenerator].prototype.throw");
} }
TF_BUILTIN(AsyncGeneratorAwaitResolveClosure, AsyncGeneratorBuiltinsAssembler) { TF_BUILTIN(AsyncGeneratorAwaitFulfill, AsyncGeneratorBuiltinsAssembler) {
Node* value = Parameter(Descriptor::kValue); Node* const generator = Parameter(Descriptor::kGenerator);
Node* context = Parameter(Descriptor::kContext); Node* const argument = Parameter(Descriptor::kArgument);
AsyncGeneratorAwaitResumeClosure(context, value, Node* const context = Parameter(Descriptor::kContext);
AsyncGeneratorAwaitResume(context, generator, argument,
JSAsyncGeneratorObject::kNext); JSAsyncGeneratorObject::kNext);
} }
TF_BUILTIN(AsyncGeneratorAwaitRejectClosure, AsyncGeneratorBuiltinsAssembler) { TF_BUILTIN(AsyncGeneratorAwaitReject, AsyncGeneratorBuiltinsAssembler) {
Node* value = Parameter(Descriptor::kValue); Node* const generator = Parameter(Descriptor::kGenerator);
Node* context = Parameter(Descriptor::kContext); Node* const argument = Parameter(Descriptor::kArgument);
AsyncGeneratorAwaitResumeClosure(context, value, Node* const context = Parameter(Descriptor::kContext);
AsyncGeneratorAwaitResume(context, generator, argument,
JSAsyncGeneratorObject::kThrow); JSAsyncGeneratorObject::kThrow);
} }
...@@ -554,31 +548,23 @@ TF_BUILTIN(AsyncGeneratorYield, AsyncGeneratorBuiltinsAssembler) { ...@@ -554,31 +548,23 @@ TF_BUILTIN(AsyncGeneratorYield, AsyncGeneratorBuiltinsAssembler) {
Node* const request = LoadFirstAsyncGeneratorRequestFromQueue(generator); Node* const request = LoadFirstAsyncGeneratorRequestFromQueue(generator);
Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(request); 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); SetGeneratorAwaiting(generator);
Await(context, generator, value, outer_promise, AwaitContext::kLength, Await(context, generator, value, outer_promise,
init_closure_context, on_resolve, on_reject, is_caught); Builtins::kAsyncGeneratorYieldFulfill,
Builtins::kAsyncGeneratorAwaitReject, is_caught);
Return(UndefinedConstant()); Return(UndefinedConstant());
} }
TF_BUILTIN(AsyncGeneratorYieldResolveClosure, AsyncGeneratorBuiltinsAssembler) { TF_BUILTIN(AsyncGeneratorYieldFulfill, AsyncGeneratorBuiltinsAssembler) {
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue); Node* const generator = Parameter(Descriptor::kGenerator);
Node* const generator = Node* const argument = Parameter(Descriptor::kArgument);
LoadContextElement(context, AwaitContext::kGeneratorSlot);
SetGeneratorNotAwaiting(generator); SetGeneratorNotAwaiting(generator);
// Per proposal-async-iteration/#sec-asyncgeneratoryield step 9 // Per proposal-async-iteration/#sec-asyncgeneratoryield step 9
// Return ! AsyncGeneratorResolve(_F_.[[Generator]], _value_, *false*). // Return ! AsyncGeneratorResolve(_F_.[[Generator]], _value_, *false*).
CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, value, CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, argument,
FalseConstant()); FalseConstant());
TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator); TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
...@@ -604,39 +590,33 @@ TF_BUILTIN(AsyncGeneratorReturn, AsyncGeneratorBuiltinsAssembler) { ...@@ -604,39 +590,33 @@ TF_BUILTIN(AsyncGeneratorReturn, AsyncGeneratorBuiltinsAssembler) {
Node* const generator = Parameter(Descriptor::kGenerator); Node* const generator = Parameter(Descriptor::kGenerator);
Node* const value = Parameter(Descriptor::kValue); Node* const value = Parameter(Descriptor::kValue);
Node* const is_caught = Parameter(Descriptor::kIsCaught); Node* const is_caught = Parameter(Descriptor::kIsCaught);
Node* const context = Parameter(Descriptor::kContext);
Node* const req = LoadFirstAsyncGeneratorRequestFromQueue(generator); Node* const req = LoadFirstAsyncGeneratorRequestFromQueue(generator);
Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(req);
CSA_ASSERT(this, IsNotUndefined(req)); CSA_ASSERT(this, IsNotUndefined(req));
Label perform_await(this); Label if_closed(this, Label::kDeferred), if_not_closed(this), done(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));
Node* const state = LoadGeneratorState(generator); Node* const state = LoadGeneratorState(generator);
GotoIf(IsGeneratorStateClosed(state), &perform_await); SetGeneratorAwaiting(generator);
var_on_resolve.Bind( Branch(IsGeneratorStateClosed(state), &if_closed, &if_not_closed);
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);
ContextInitializer init_closure_context = [&](Node* context) { BIND(&if_closed);
StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot, {
generator); Await(context, generator, value, outer_promise,
}; Builtins::kAsyncGeneratorReturnClosedFulfill,
Builtins::kAsyncGeneratorReturnClosedReject, is_caught);
Goto(&done);
}
SetGeneratorAwaiting(generator); BIND(&if_not_closed);
Node* const context = Parameter(Descriptor::kContext); {
Node* const outer_promise = LoadPromiseFromAsyncGeneratorRequest(req); Await(context, generator, value, outer_promise,
Await(context, generator, value, outer_promise, AwaitContext::kLength, Builtins::kAsyncGeneratorReturnFulfill,
init_closure_context, var_on_resolve.value(), var_on_reject.value(), Builtins::kAsyncGeneratorAwaitReject, is_caught);
is_caught); Goto(&done);
}
BIND(&done);
Return(UndefinedConstant()); Return(UndefinedConstant());
} }
...@@ -644,47 +624,44 @@ TF_BUILTIN(AsyncGeneratorReturn, AsyncGeneratorBuiltinsAssembler) { ...@@ -644,47 +624,44 @@ TF_BUILTIN(AsyncGeneratorReturn, AsyncGeneratorBuiltinsAssembler) {
// Resume the generator with "return" resume_mode, and finally perform // Resume the generator with "return" resume_mode, and finally perform
// AsyncGeneratorResumeNext. Per // AsyncGeneratorResumeNext. Per
// proposal-async-iteration/#sec-asyncgeneratoryield step 8.e // proposal-async-iteration/#sec-asyncgeneratoryield step 8.e
TF_BUILTIN(AsyncGeneratorReturnResolveClosure, TF_BUILTIN(AsyncGeneratorReturnFulfill, AsyncGeneratorBuiltinsAssembler) {
AsyncGeneratorBuiltinsAssembler) { Node* const generator = Parameter(Descriptor::kGenerator);
Node* const argument = Parameter(Descriptor::kArgument);
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue); AsyncGeneratorAwaitResume(context, generator, argument,
AsyncGeneratorAwaitResumeClosure(context, value, JSGeneratorObject::kReturn); JSGeneratorObject::kReturn);
} }
// On-resolve closure for Await in AsyncGeneratorReturn // On-resolve closure for Await in AsyncGeneratorReturn
// Perform AsyncGeneratorResolve({awaited_value}, true) and finally perform // Perform AsyncGeneratorResolve({awaited_value}, true) and finally perform
// AsyncGeneratorResumeNext. // AsyncGeneratorResumeNext.
TF_BUILTIN(AsyncGeneratorReturnClosedResolveClosure, TF_BUILTIN(AsyncGeneratorReturnClosedFulfill, AsyncGeneratorBuiltinsAssembler) {
AsyncGeneratorBuiltinsAssembler) { Node* const generator = Parameter(Descriptor::kGenerator);
Node* const argument = Parameter(Descriptor::kArgument);
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue);
Node* const generator =
LoadContextElement(context, AwaitContext::kGeneratorSlot);
SetGeneratorNotAwaiting(generator); SetGeneratorNotAwaiting(generator);
// https://tc39.github.io/proposal-async-iteration/ // https://tc39.github.io/proposal-async-iteration/
// #async-generator-resume-next-return-processor-fulfilled step 2: // #async-generator-resume-next-return-processor-fulfilled step 2:
// Return ! AsyncGeneratorResolve(_F_.[[Generator]], _value_, *true*). // Return ! AsyncGeneratorResolve(_F_.[[Generator]], _value_, *true*).
CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, value, CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, argument,
TrueConstant()); TrueConstant());
TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator); TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
} }
TF_BUILTIN(AsyncGeneratorReturnClosedRejectClosure, TF_BUILTIN(AsyncGeneratorReturnClosedReject, AsyncGeneratorBuiltinsAssembler) {
AsyncGeneratorBuiltinsAssembler) { Node* const generator = Parameter(Descriptor::kGenerator);
Node* const argument = Parameter(Descriptor::kArgument);
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
Node* const value = Parameter(Descriptor::kValue);
Node* const generator =
LoadContextElement(context, AwaitContext::kGeneratorSlot);
SetGeneratorNotAwaiting(generator); SetGeneratorNotAwaiting(generator);
// https://tc39.github.io/proposal-async-iteration/ // https://tc39.github.io/proposal-async-iteration/
// #async-generator-resume-next-return-processor-rejected step 2: // #async-generator-resume-next-return-processor-rejected step 2:
// Return ! AsyncGeneratorReject(_F_.[[Generator]], _reason_). // Return ! AsyncGeneratorReject(_F_.[[Generator]], _reason_).
CallBuiltin(Builtins::kAsyncGeneratorReject, context, generator, value); CallBuiltin(Builtins::kAsyncGeneratorReject, context, generator, argument);
TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator); TailCallBuiltin(Builtins::kAsyncGeneratorResumeNext, context, generator);
} }
......
...@@ -1173,6 +1173,17 @@ namespace internal { ...@@ -1173,6 +1173,17 @@ namespace internal {
\ \
/* AsyncGenerator */ \ /* 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(AsyncGeneratorResolve, kGenerator, kValue, kDone) \
TFS(AsyncGeneratorReject, kGenerator, kValue) \ TFS(AsyncGeneratorReject, kGenerator, kValue) \
TFS(AsyncGeneratorYield, kGenerator, kValue, kIsCaught) \ TFS(AsyncGeneratorYield, kGenerator, kValue, kIsCaught) \
...@@ -1195,17 +1206,6 @@ namespace internal { ...@@ -1195,17 +1206,6 @@ namespace internal {
TFJ(AsyncGeneratorPrototypeThrow, \ TFJ(AsyncGeneratorPrototypeThrow, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \ 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 */ \ /* Async-from-Sync Iterator */ \
\ \
/* %AsyncFromSyncIteratorPrototype% */ \ /* %AsyncFromSyncIteratorPrototype% */ \
......
...@@ -235,6 +235,8 @@ bool Builtins::IsLazy(int index) { ...@@ -235,6 +235,8 @@ bool Builtins::IsLazy(int index) {
case kArrayReduceRightLoopLazyDeoptContinuation: case kArrayReduceRightLoopLazyDeoptContinuation:
case kArraySomeLoopEagerDeoptContinuation: // https://crbug.com/v8/6786. case kArraySomeLoopEagerDeoptContinuation: // https://crbug.com/v8/6786.
case kArraySomeLoopLazyDeoptContinuation: // 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 kCheckOptimizationMarker:
case kCompileLazy: case kCompileLazy:
case kDeserializeLazy: case kDeserializeLazy:
......
...@@ -4561,6 +4561,10 @@ Node* CodeStubAssembler::IsJSArrayMap(Node* map) { ...@@ -4561,6 +4561,10 @@ Node* CodeStubAssembler::IsJSArrayMap(Node* map) {
return IsJSArrayInstanceType(LoadMapInstanceType(map)); return IsJSArrayInstanceType(LoadMapInstanceType(map));
} }
Node* CodeStubAssembler::IsJSAsyncGeneratorObject(Node* object) {
return HasInstanceType(object, JS_ASYNC_GENERATOR_OBJECT_TYPE);
}
Node* CodeStubAssembler::IsFixedArray(Node* object) { Node* CodeStubAssembler::IsFixedArray(Node* object) {
return HasInstanceType(object, FIXED_ARRAY_TYPE); return HasInstanceType(object, FIXED_ARRAY_TYPE);
} }
......
...@@ -1121,6 +1121,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -1121,6 +1121,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IsJSArrayInstanceType(Node* instance_type); Node* IsJSArrayInstanceType(Node* instance_type);
Node* IsJSArrayMap(Node* object); Node* IsJSArrayMap(Node* object);
Node* IsJSArray(Node* object); Node* IsJSArray(Node* object);
Node* IsJSAsyncGeneratorObject(Node* object);
Node* IsJSFunctionInstanceType(Node* instance_type); Node* IsJSFunctionInstanceType(Node* instance_type);
Node* IsJSFunctionMap(Node* object); Node* IsJSFunctionMap(Node* object);
Node* IsJSFunction(Node* object); Node* IsJSFunction(Node* object);
......
...@@ -211,18 +211,6 @@ enum ContextLookupFlags { ...@@ -211,18 +211,6 @@ enum ContextLookupFlags {
async_generator_function_function) \ async_generator_function_function) \
V(ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN, SharedFunctionInfo, \ V(ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN, SharedFunctionInfo, \
async_iterator_value_unwrap_shared_fun) \ 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(ATOMICS_OBJECT, JSObject, atomics_object) \
V(BIGINT_FUNCTION_INDEX, JSFunction, bigint_function) \ V(BIGINT_FUNCTION_INDEX, JSFunction, bigint_function) \
V(BIGINT64_ARRAY_FUN_INDEX, JSFunction, bigint64_array_fun) \ 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