Skip to content

Commit bf463c4

Browse files
caitpCommit Bot
authored andcommitted
[async-iteration] implement AsyncGenerator
- Introduce new struct AsyncGeneratorRequest, which holds information pertinent to resuming execution of an AsyncGenerator, such as the Promise associated with the async generator request. It is intended to be used as a singly linked list, and holds a pointer to the next item in te queue. - Introduce JSAsyncGeneratorObject (subclass of JSGeneratorObject), which includes several new internal fields (`queue` which contains a singly linked list of AsyncGeneratorRequest objects, and `await_input` which contains the sent value from an Await expression (This is necessary to prevent function.sent (used by yield*) from having the sent value observably overwritten during execution). - Modify SuspendGenerator to accept a set of Flags, which indicate whether the suspend is for a Yield or Await, and whether it takes place on an async generator or ES6 generator. - Introduce interpreter intrinsics and TF intrinsic lowering for accessing the await input of an async generator - Modify the JSGeneratorStore operator to understand whether or not it's suspending for a normal yield, or an AsyncGenerator Await. This ensures appropriate registers are stored. - Add versions of ResumeGeneratorTrampoline which store the input value in a different field depending on wether it's an AsyncGenerator Await resume, or an ordinary resume. Also modifies whether debug code will assert that the generator object is a JSGeneratorObject or a JSAsyncGeneratorObject depending on the resume type. BUG=v8:5855 [email protected], [email protected], [email protected], [email protected], [email protected] [email protected] Change-Id: I9d58df1d344465fc937fe7eed322424204497187 Reviewed-on: https://chromium-review.googlesource.com/446961 Commit-Queue: Caitlin Potter <[email protected]> Reviewed-by: Ross McIlroy <[email protected]> Reviewed-by: Hannes Payer <[email protected]> Reviewed-by: Benedikt Meurer <[email protected]> Reviewed-by: Jakob Gruber <[email protected]> Cr-Commit-Position: refs/heads/master@{#44240}
1 parent 6234fda commit bf463c4

78 files changed

Lines changed: 3439 additions & 331 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,7 @@ v8_source_set("v8_builtins_generators") {
907907
"src/builtins/builtins-async-function-gen.cc",
908908
"src/builtins/builtins-async-gen.cc",
909909
"src/builtins/builtins-async-gen.h",
910+
"src/builtins/builtins-async-generator-gen.cc",
910911
"src/builtins/builtins-async-iterator-gen.cc",
911912
"src/builtins/builtins-boolean-gen.cc",
912913
"src/builtins/builtins-constructor-gen.cc",

include/v8.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8557,8 +8557,8 @@ class Internals {
85578557
static const int kNodeIsIndependentShift = 3;
85588558
static const int kNodeIsActiveShift = 4;
85598559

8560-
static const int kJSApiObjectType = 0xb9;
8561-
static const int kJSObjectType = 0xba;
8560+
static const int kJSApiObjectType = 0xba;
8561+
static const int kJSObjectType = 0xbb;
85628562
static const int kFirstNonstringType = 0x80;
85638563
static const int kOddballType = 0x82;
85648564
static const int kForeignType = 0x86;

src/arm/macro-assembler-arm.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,6 +2922,18 @@ void MacroAssembler::AssertGeneratorObject(Register object) {
29222922
}
29232923
}
29242924

2925+
void MacroAssembler::AssertAsyncGeneratorObject(Register object) {
2926+
if (emit_debug_code()) {
2927+
STATIC_ASSERT(kSmiTag == 0);
2928+
tst(object, Operand(kSmiTagMask));
2929+
Check(ne, kOperandIsASmiAndNotAGeneratorObject);
2930+
push(object);
2931+
CompareObjectType(object, object, object, JS_ASYNC_GENERATOR_OBJECT_TYPE);
2932+
pop(object);
2933+
Check(eq, kOperandIsNotAGeneratorObject);
2934+
}
2935+
}
2936+
29252937
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
29262938
Register scratch) {
29272939
if (emit_debug_code()) {

src/arm/macro-assembler-arm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,7 @@ class MacroAssembler: public Assembler {
12311231
// Abort execution if argument is not a JSGeneratorObject,
12321232
// enabled via --debug-code.
12331233
void AssertGeneratorObject(Register object);
1234+
void AssertAsyncGeneratorObject(Register object);
12341235

12351236
// Abort execution if argument is not undefined or an AllocationSite, enabled
12361237
// via --debug-code.

src/arm64/macro-assembler-arm64.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,6 +1656,18 @@ void MacroAssembler::AssertGeneratorObject(Register object) {
16561656
}
16571657
}
16581658

1659+
void MacroAssembler::AssertAsyncGeneratorObject(Register object) {
1660+
if (emit_debug_code()) {
1661+
AssertNotSmi(object, kOperandIsASmiAndNotAGeneratorObject);
1662+
1663+
UseScratchRegisterScope temps(this);
1664+
Register temp = temps.AcquireX();
1665+
1666+
CompareObjectType(object, temp, temp, JS_ASYNC_GENERATOR_OBJECT_TYPE);
1667+
Check(eq, kOperandIsNotAGeneratorObject);
1668+
}
1669+
}
1670+
16591671
void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
16601672
Register scratch) {
16611673
if (emit_debug_code()) {

src/arm64/macro-assembler-arm64.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,7 @@ class MacroAssembler : public Assembler {
10001000
// Abort execution if argument is not a JSGeneratorObject,
10011001
// enabled via --debug-code.
10021002
void AssertGeneratorObject(Register object);
1003+
void AssertAsyncGeneratorObject(Register object);
10031004

10041005
// Abort execution if argument is not a JSBoundFunction,
10051006
// enabled via --debug-code.

src/ast/ast-types.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) {
208208
case JS_DATE_TYPE:
209209
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
210210
case JS_GENERATOR_OBJECT_TYPE:
211+
case JS_ASYNC_GENERATOR_OBJECT_TYPE:
211212
case JS_MODULE_NAMESPACE_TYPE:
212213
case JS_ARRAY_BUFFER_TYPE:
213214
case JS_ARRAY_TYPE:
@@ -286,6 +287,7 @@ AstType::bitset AstBitsetType::Lub(i::Map* map) {
286287
case PROPERTY_CELL_TYPE:
287288
case MODULE_TYPE:
288289
case MODULE_INFO_ENTRY_TYPE:
290+
case ASYNC_GENERATOR_REQUEST_TYPE:
289291
return kOtherInternal & kTaggedPointer;
290292

291293
// Remaining instance types are unsupported for now. If any of them do

src/ast/ast.h

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,14 +2501,6 @@ class RewritableExpression final : public Expression {
25012501
class Suspend final : public Expression {
25022502
public:
25032503
enum OnException { kOnExceptionThrow, kOnExceptionRethrow };
2504-
using Flags = SuspendGeneratorFlags;
2505-
2506-
// Convenient aliases
2507-
static constexpr Flags kYield = Flags::kYield;
2508-
static constexpr Flags kYieldStar = Flags::kYieldStar;
2509-
static constexpr Flags kAwait = Flags::kAwait;
2510-
2511-
static constexpr Flags kAsyncGenerator = Flags::kAsyncGenerator;
25122504

25132505
Expression* generator_object() const { return generator_object_; }
25142506
Expression* expression() const { return expression_; }
@@ -2520,30 +2512,40 @@ class Suspend final : public Expression {
25202512
}
25212513

25222514
int suspend_id() const { return suspend_id_; }
2523-
Flags suspend_type() const {
2524-
return static_cast<Flags>(FlagsField::decode(bit_field_) &
2525-
Flags::kSuspendTypeMask);
2515+
SuspendFlags flags() const { return FlagsField::decode(bit_field_); }
2516+
SuspendFlags suspend_type() const {
2517+
return flags() & SuspendFlags::kSuspendTypeMask;
2518+
}
2519+
SuspendFlags generator_type() const {
2520+
return flags() & SuspendFlags::kGeneratorTypeMask;
25262521
}
2527-
bool is_yield() const { return suspend_type() == Flags::kYield; }
2528-
bool is_yield_star() const { return suspend_type() == Flags::kYieldStar; }
2529-
bool is_await() const { return suspend_type() == Flags::kAwait; }
2522+
bool is_yield() const { return suspend_type() == SuspendFlags::kYield; }
2523+
bool is_yield_star() const {
2524+
return suspend_type() == SuspendFlags::kYieldStar;
2525+
}
2526+
bool is_await() const { return suspend_type() == SuspendFlags::kAwait; }
25302527
bool is_async_generator() const {
2531-
return (suspend_type() & Flags::kGeneratorTypeMask) == kAsyncGenerator;
2528+
return generator_type() == SuspendFlags::kAsyncGenerator;
2529+
}
2530+
inline bool IsNonInitialAsyncGeneratorYield() const {
2531+
// Return true if is_async_generator() && !is_await() && yield_id() > 0
2532+
return suspend_id() > 0 && (flags() & SuspendFlags::kAsyncGeneratorAwait) ==
2533+
SuspendFlags::kAsyncGenerator;
25322534
}
25332535

25342536
void set_generator_object(Expression* e) { generator_object_ = e; }
25352537
void set_expression(Expression* e) { expression_ = e; }
25362538
void set_suspend_id(int id) { suspend_id_ = id; }
2537-
void set_suspend_type(Flags type) {
2538-
DCHECK_EQ(0, static_cast<int>(type & ~Flags::kSuspendTypeMask));
2539+
void set_suspend_type(SuspendFlags type) {
2540+
DCHECK_EQ(0, static_cast<int>(type & ~SuspendFlags::kSuspendTypeMask));
25392541
bit_field_ = FlagsField::update(bit_field_, type);
25402542
}
25412543

25422544
private:
25432545
friend class AstNodeFactory;
25442546

25452547
Suspend(Expression* generator_object, Expression* expression, int pos,
2546-
OnException on_exception, Flags flags)
2548+
OnException on_exception, SuspendFlags flags)
25472549
: Expression(pos, kSuspend),
25482550
suspend_id_(-1),
25492551
generator_object_(generator_object),
@@ -2558,9 +2560,9 @@ class Suspend final : public Expression {
25582560

25592561
class OnExceptionField
25602562
: public BitField<OnException, Expression::kNextBitFieldIndex, 1> {};
2561-
static constexpr int kFlagsBitWidth = static_cast<int>(Flags::kBitWidth);
25622563
class FlagsField
2563-
: public BitField<Flags, OnExceptionField::kNext, kFlagsBitWidth> {};
2564+
: public BitField<SuspendFlags, OnExceptionField::kNext,
2565+
static_cast<int>(SuspendFlags::kBitWidth)> {};
25642566
};
25652567

25662568

@@ -3509,7 +3511,7 @@ class AstNodeFactory final BASE_EMBEDDED {
35093511

35103512
Suspend* NewSuspend(Expression* generator_object, Expression* expression,
35113513
int pos, Suspend::OnException on_exception,
3512-
Suspend::Flags flags) {
3514+
SuspendFlags flags) {
35133515
if (!expression) expression = NewUndefinedLiteral(pos);
35143516
return new (zone_)
35153517
Suspend(generator_object, expression, pos, on_exception, flags);

src/bootstrapper.cc

Lines changed: 138 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ class Genesis BASE_EMBEDDED {
172172

173173
void CreateStrictModeFunctionMaps(Handle<JSFunction> empty);
174174
void CreateIteratorMaps(Handle<JSFunction> empty);
175-
void CreateAsyncIteratorMaps();
175+
void CreateAsyncIteratorMaps(Handle<JSFunction> empty);
176176
void CreateAsyncFunctionMaps(Handle<JSFunction> empty);
177177
void CreateJSProxyMaps();
178178

@@ -808,7 +808,7 @@ void Genesis::CreateIteratorMaps(Handle<JSFunction> empty) {
808808
*generator_object_prototype_map);
809809
}
810810

811-
void Genesis::CreateAsyncIteratorMaps() {
811+
void Genesis::CreateAsyncIteratorMaps(Handle<JSFunction> empty) {
812812
// %AsyncIteratorPrototype%
813813
// proposal-async-iteration/#sec-asynciteratorprototype
814814
Handle<JSObject> async_iterator_prototype =
@@ -850,6 +850,67 @@ void Genesis::CreateAsyncIteratorMaps() {
850850
async_from_sync_iterator_prototype);
851851
native_context()->set_async_from_sync_iterator_map(
852852
*async_from_sync_iterator_map);
853+
854+
// Async Generators
855+
Handle<String> AsyncGeneratorFunction_string =
856+
factory()->NewStringFromAsciiChecked("AsyncGeneratorFunction", TENURED);
857+
858+
Handle<JSObject> async_generator_object_prototype =
859+
factory()->NewJSObject(isolate()->object_function(), TENURED);
860+
Handle<JSObject> async_generator_function_prototype =
861+
factory()->NewJSObject(isolate()->object_function(), TENURED);
862+
863+
// %AsyncGenerator% / %AsyncGeneratorFunction%.prototype
864+
JSObject::ForceSetPrototype(async_generator_function_prototype, empty);
865+
866+
// The value of AsyncGeneratorFunction.prototype.prototype is the
867+
// %AsyncGeneratorPrototype% intrinsic object.
868+
// This property has the attributes
869+
// { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
870+
JSObject::AddProperty(async_generator_function_prototype,
871+
factory()->prototype_string(),
872+
async_generator_object_prototype,
873+
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
874+
JSObject::AddProperty(async_generator_function_prototype,
875+
factory()->to_string_tag_symbol(),
876+
AsyncGeneratorFunction_string,
877+
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
878+
879+
// %AsyncGeneratorPrototype%
880+
JSObject::ForceSetPrototype(async_generator_object_prototype,
881+
async_iterator_prototype);
882+
883+
JSObject::AddProperty(async_generator_object_prototype,
884+
factory()->to_string_tag_symbol(),
885+
factory()->NewStringFromAsciiChecked("AsyncGenerator"),
886+
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
887+
SimpleInstallFunction(async_generator_object_prototype, "next",
888+
Builtins::kAsyncGeneratorPrototypeNext, 1, true);
889+
SimpleInstallFunction(async_generator_object_prototype, "return",
890+
Builtins::kAsyncGeneratorPrototypeReturn, 1, true);
891+
SimpleInstallFunction(async_generator_object_prototype, "throw",
892+
Builtins::kAsyncGeneratorPrototypeThrow, 1, true);
893+
894+
// Create maps for generator functions and their prototypes. Store those
895+
// maps in the native context. The "prototype" property descriptor is
896+
// writable, non-enumerable, and non-configurable (as per ES6 draft
897+
// 04-14-15, section 25.2.4.3).
898+
Handle<Map> strict_function_map(strict_function_map_writable_prototype_);
899+
// Async Generator functions do not have "caller" or "arguments" accessors.
900+
Handle<Map> async_generator_function_map =
901+
Map::Copy(strict_function_map, "AsyncGeneratorFunction");
902+
async_generator_function_map->set_is_constructor(false);
903+
Map::SetPrototype(async_generator_function_map,
904+
async_generator_function_prototype);
905+
native_context()->set_async_generator_function_map(
906+
*async_generator_function_map);
907+
908+
Handle<JSFunction> object_function(native_context()->object_function());
909+
Handle<Map> async_generator_object_prototype_map = Map::Create(isolate(), 0);
910+
Map::SetPrototype(async_generator_object_prototype_map,
911+
async_generator_object_prototype);
912+
native_context()->set_async_generator_object_prototype_map(
913+
*async_generator_object_prototype_map);
853914
}
854915

855916
void Genesis::CreateAsyncFunctionMaps(Handle<JSFunction> empty) {
@@ -1376,6 +1437,48 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
13761437
native_context()->set_async_iterator_value_unwrap_shared_fun(*info);
13771438
}
13781439

1440+
{ // --- A s y n c G e n e r a t o r ---
1441+
Handle<JSFunction> await_caught =
1442+
SimpleCreateFunction(isolate, factory->empty_string(),
1443+
Builtins::kAsyncGeneratorAwaitCaught, 2, false);
1444+
InstallWithIntrinsicDefaultProto(isolate, await_caught,
1445+
Context::ASYNC_GENERATOR_AWAIT_CAUGHT);
1446+
1447+
Handle<JSFunction> await_uncaught =
1448+
SimpleCreateFunction(isolate, factory->empty_string(),
1449+
Builtins::kAsyncGeneratorAwaitUncaught, 2, false);
1450+
InstallWithIntrinsicDefaultProto(isolate, await_uncaught,
1451+
Context::ASYNC_GENERATOR_AWAIT_UNCAUGHT);
1452+
1453+
Handle<JSFunction> yield =
1454+
SimpleCreateFunction(isolate, factory->empty_string(),
1455+
Builtins::kAsyncGeneratorYield, 2, false);
1456+
InstallWithIntrinsicDefaultProto(isolate, yield,
1457+
Context::ASYNC_GENERATOR_YIELD);
1458+
1459+
Handle<JSFunction> raw_yield =
1460+
SimpleCreateFunction(isolate, factory->empty_string(),
1461+
Builtins::kAsyncGeneratorRawYield, 2, false);
1462+
InstallWithIntrinsicDefaultProto(isolate, raw_yield,
1463+
Context::ASYNC_GENERATOR_RAW_YIELD);
1464+
1465+
Handle<Code> code =
1466+
isolate->builtins()->AsyncGeneratorAwaitResolveClosure();
1467+
Handle<SharedFunctionInfo> info =
1468+
factory->NewSharedFunctionInfo(factory->empty_string(), code, false);
1469+
info->set_internal_formal_parameter_count(1);
1470+
info->set_length(1);
1471+
native_context()->set_async_generator_await_resolve_shared_fun(*info);
1472+
1473+
code = handle(isolate->builtins()->builtin(
1474+
Builtins::kAsyncGeneratorAwaitRejectClosure),
1475+
isolate);
1476+
info = factory->NewSharedFunctionInfo(factory->empty_string(), code, false);
1477+
info->set_internal_formal_parameter_count(1);
1478+
info->set_length(1);
1479+
native_context()->set_async_generator_await_reject_shared_fun(*info);
1480+
}
1481+
13791482
{ // --- A r r a y ---
13801483
Handle<JSFunction> array_function =
13811484
InstallFunction(global, "Array", JS_ARRAY_TYPE, JSArray::kSize,
@@ -3374,6 +3477,38 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
33743477
*generator_function_function);
33753478
}
33763479

3480+
{
3481+
PrototypeIterator iter(native_context->async_generator_function_map());
3482+
Handle<JSObject> async_generator_function_prototype(
3483+
iter.GetCurrent<JSObject>());
3484+
3485+
static const bool kUseStrictFunctionMap = true;
3486+
Handle<JSFunction> async_generator_function_function = InstallFunction(
3487+
container, "AsyncGeneratorFunction", JS_FUNCTION_TYPE,
3488+
JSFunction::kSize, async_generator_function_prototype,
3489+
Builtins::kAsyncGeneratorFunctionConstructor, kUseStrictFunctionMap);
3490+
async_generator_function_function->set_prototype_or_initial_map(
3491+
native_context->async_generator_function_map());
3492+
async_generator_function_function->shared()->DontAdaptArguments();
3493+
async_generator_function_function->shared()->SetConstructStub(
3494+
*isolate->builtins()->AsyncGeneratorFunctionConstructor());
3495+
async_generator_function_function->shared()->set_length(1);
3496+
InstallWithIntrinsicDefaultProto(
3497+
isolate, async_generator_function_function,
3498+
Context::ASYNC_GENERATOR_FUNCTION_FUNCTION_INDEX);
3499+
3500+
JSObject::ForceSetPrototype(async_generator_function_function,
3501+
isolate->function_function());
3502+
3503+
JSObject::AddProperty(
3504+
async_generator_function_prototype, factory->constructor_string(),
3505+
async_generator_function_function,
3506+
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
3507+
3508+
native_context->async_generator_function_map()->SetConstructor(
3509+
*async_generator_function_function);
3510+
}
3511+
33773512
{ // -- S e t I t e r a t o r
33783513
Handle<JSObject> set_iterator_prototype =
33793514
isolate->factory()->NewJSObject(isolate->object_function(), TENURED);
@@ -4968,7 +5103,7 @@ Genesis::Genesis(
49685103
Handle<JSFunction> empty_function = CreateEmptyFunction(isolate);
49695104
CreateStrictModeFunctionMaps(empty_function);
49705105
CreateIteratorMaps(empty_function);
4971-
CreateAsyncIteratorMaps();
5106+
CreateAsyncIteratorMaps(empty_function);
49725107
CreateAsyncFunctionMaps(empty_function);
49735108
Handle<JSGlobalObject> global_object =
49745109
CreateNewGlobals(global_proxy_template, global_proxy);

0 commit comments

Comments
 (0)