Skip to content

Commit feb545c

Browse files
bmeurerCommit Bot
authored andcommitted
[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 <[email protected]> Reviewed-by: Georg Neis <[email protected]> Cr-Commit-Position: refs/heads/master@{#51361}
1 parent 4a90e48 commit feb545c

10 files changed

Lines changed: 143 additions & 362 deletions

src/bootstrapper.cc

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,38 +1615,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
16151615
SimpleCreateFunction(isolate, factory->empty_string(),
16161616
Builtins::kAsyncGeneratorAwaitUncaught, 1, false);
16171617
native_context()->set_async_generator_await_uncaught(*await_uncaught);
1618-
1619-
Handle<SharedFunctionInfo> info = SimpleCreateSharedFunctionInfo(
1620-
isolate, Builtins::kAsyncGeneratorAwaitResolveClosure,
1621-
factory->empty_string(), 1);
1622-
native_context()->set_async_generator_await_resolve_shared_fun(*info);
1623-
1624-
info = SimpleCreateSharedFunctionInfo(
1625-
isolate, Builtins::kAsyncGeneratorAwaitRejectClosure,
1626-
factory->empty_string(), 1);
1627-
native_context()->set_async_generator_await_reject_shared_fun(*info);
1628-
1629-
info = SimpleCreateSharedFunctionInfo(
1630-
isolate, Builtins::kAsyncGeneratorYieldResolveClosure,
1631-
factory->empty_string(), 1);
1632-
native_context()->set_async_generator_yield_resolve_shared_fun(*info);
1633-
1634-
info = SimpleCreateSharedFunctionInfo(
1635-
isolate, Builtins::kAsyncGeneratorReturnResolveClosure,
1636-
factory->empty_string(), 1);
1637-
native_context()->set_async_generator_return_resolve_shared_fun(*info);
1638-
1639-
info = SimpleCreateSharedFunctionInfo(
1640-
isolate, Builtins::kAsyncGeneratorReturnClosedResolveClosure,
1641-
factory->empty_string(), 1);
1642-
native_context()->set_async_generator_return_closed_resolve_shared_fun(
1643-
*info);
1644-
1645-
info = SimpleCreateSharedFunctionInfo(
1646-
isolate, Builtins::kAsyncGeneratorReturnClosedRejectClosure,
1647-
factory->empty_string(), 1);
1648-
native_context()->set_async_generator_return_closed_reject_shared_fun(
1649-
*info);
16501618
}
16511619

16521620
{ // --- A r r a y ---

src/builtins/builtins-async-function-gen.cc

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -88,39 +88,9 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
8888
CSA_SLOW_ASSERT(this, IsJSGeneratorObject(generator));
8989
CSA_SLOW_ASSERT(this, IsJSPromise(outer_promise));
9090

91-
Node* const native_context = LoadNativeContext(context);
92-
Node* const promise = AllocateAndInitJSPromise(native_context);
93-
94-
Node* const promise_reactions =
95-
LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
96-
Node* const fulfill_handler = HeapConstant(
97-
Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitFulfill)
98-
.code());
99-
Node* const reject_handler = HeapConstant(
100-
Builtins::CallableFor(isolate(), Builtins::kAsyncFunctionAwaitReject)
101-
.code());
102-
Node* const reaction = AllocatePromiseReaction(
103-
promise_reactions, generator, fulfill_handler, reject_handler);
104-
StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reaction);
105-
PromiseSetHasHandler(promise);
106-
107-
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « value »).
108-
CallBuiltin(Builtins::kResolvePromise, native_context, promise, awaited);
109-
110-
{
111-
Label done(this);
112-
GotoIfNot(IsDebugActive(), &done);
113-
CallRuntime(Runtime::kSetProperty, native_context, generator,
114-
LoadRoot(Heap::kgenerator_outer_promise_symbolRootIndex),
115-
outer_promise, SmiConstant(LanguageMode::kStrict));
116-
if (is_predicted_as_caught) {
117-
GotoIf(TaggedIsSmi(awaited), &done);
118-
GotoIfNot(IsJSPromise(awaited), &done);
119-
PromiseSetHandledHint(awaited);
120-
}
121-
Goto(&done);
122-
BIND(&done);
123-
}
91+
Await(context, generator, awaited, outer_promise,
92+
Builtins::kAsyncFunctionAwaitFulfill,
93+
Builtins::kAsyncFunctionAwaitReject, is_predicted_as_caught);
12494

12595
// Return outer promise to avoid adding an load of the outer promise before
12696
// suspending in BytecodeGenerator.

src/builtins/builtins-async-gen.cc

Lines changed: 52 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,58 @@ namespace internal {
1313

1414
using compiler::Node;
1515

16+
void AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value,
17+
Node* outer_promise,
18+
Builtins::Name fulfill_builtin,
19+
Builtins::Name reject_builtin,
20+
Node* is_predicted_as_caught) {
21+
CSA_SLOW_ASSERT(this, Word32Or(IsJSAsyncGeneratorObject(generator),
22+
IsJSGeneratorObject(generator)));
23+
CSA_SLOW_ASSERT(this, IsJSPromise(outer_promise));
24+
CSA_SLOW_ASSERT(this, IsBoolean(is_predicted_as_caught));
25+
26+
Node* const native_context = LoadNativeContext(context);
27+
28+
// TODO(bmeurer): This could be optimized and folded into a single allocation.
29+
Node* const promise = AllocateAndInitJSPromise(native_context);
30+
Node* const promise_reactions =
31+
LoadObjectField(promise, JSPromise::kReactionsOrResultOffset);
32+
Node* const fulfill_handler =
33+
HeapConstant(Builtins::CallableFor(isolate(), fulfill_builtin).code());
34+
Node* const reject_handler =
35+
HeapConstant(Builtins::CallableFor(isolate(), reject_builtin).code());
36+
Node* const reaction = AllocatePromiseReaction(
37+
promise_reactions, generator, fulfill_handler, reject_handler);
38+
StoreObjectField(promise, JSPromise::kReactionsOrResultOffset, reaction);
39+
PromiseSetHasHandler(promise);
40+
41+
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « value »).
42+
CallBuiltin(Builtins::kResolvePromise, native_context, promise, value);
43+
44+
// When debugging, we need to link from the {generator} to the
45+
// {outer_promise} of the async function/generator.
46+
Label done(this);
47+
GotoIfNot(IsDebugActive(), &done);
48+
CallRuntime(Runtime::kSetProperty, native_context, generator,
49+
LoadRoot(Heap::kgenerator_outer_promise_symbolRootIndex),
50+
outer_promise, SmiConstant(LanguageMode::kStrict));
51+
GotoIf(IsFalse(is_predicted_as_caught), &done);
52+
GotoIf(TaggedIsSmi(value), &done);
53+
GotoIfNot(IsJSPromise(value), &done);
54+
PromiseSetHandledHint(value);
55+
Goto(&done);
56+
BIND(&done);
57+
}
58+
59+
void AsyncBuiltinsAssembler::Await(Node* context, Node* generator, Node* value,
60+
Node* outer_promise,
61+
Builtins::Name fulfill_builtin,
62+
Builtins::Name reject_builtin,
63+
bool is_predicted_as_caught) {
64+
return Await(context, generator, value, outer_promise, fulfill_builtin,
65+
reject_builtin, BooleanConstant(is_predicted_as_caught));
66+
}
67+
1668
namespace {
1769
// Describe fields of Context associated with the AsyncIterator unwrap closure.
1870
class ValueUnwrapContext {
@@ -22,162 +74,6 @@ class ValueUnwrapContext {
2274

2375
} // namespace
2476

25-
Node* AsyncBuiltinsAssembler::Await(
26-
Node* context, Node* generator, Node* value, Node* outer_promise,
27-
int context_length, const ContextInitializer& init_closure_context,
28-
Node* on_resolve_context_index, Node* on_reject_context_index,
29-
Node* is_predicted_as_caught) {
30-
DCHECK_GE(context_length, Context::MIN_CONTEXT_SLOTS);
31-
32-
Node* const native_context = LoadNativeContext(context);
33-
34-
static const int kWrappedPromiseOffset = FixedArray::SizeFor(context_length);
35-
static const int kThrowawayPromiseOffset =
36-
kWrappedPromiseOffset + JSPromise::kSizeWithEmbedderFields;
37-
static const int kResolveClosureOffset =
38-
kThrowawayPromiseOffset + JSPromise::kSizeWithEmbedderFields;
39-
static const int kRejectClosureOffset =
40-
kResolveClosureOffset + JSFunction::kSizeWithoutPrototype;
41-
static const int kTotalSize =
42-
kRejectClosureOffset + JSFunction::kSizeWithoutPrototype;
43-
44-
Node* const base = AllocateInNewSpace(kTotalSize);
45-
Node* const closure_context = base;
46-
{
47-
// Initialize closure context
48-
InitializeFunctionContext(native_context, closure_context, context_length);
49-
init_closure_context(closure_context);
50-
}
51-
52-
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
53-
Node* const promise_fun =
54-
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
55-
CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(promise_fun)));
56-
Node* const promise_map =
57-
LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
58-
// Assert that the JSPromise map has an instance size is
59-
// JSPromise::kSizeWithEmbedderFields.
60-
CSA_ASSERT(this, WordEqual(LoadMapInstanceSizeInWords(promise_map),
61-
IntPtrConstant(JSPromise::kSizeWithEmbedderFields /
62-
kPointerSize)));
63-
Node* const wrapped_value = InnerAllocate(base, kWrappedPromiseOffset);
64-
{
65-
// Initialize Promise
66-
StoreMapNoWriteBarrier(wrapped_value, promise_map);
67-
InitializeJSObjectFromMap(
68-
wrapped_value, promise_map,
69-
IntPtrConstant(JSPromise::kSizeWithEmbedderFields));
70-
PromiseInit(wrapped_value);
71-
}
72-
73-
Node* const throwaway = InnerAllocate(base, kThrowawayPromiseOffset);
74-
{
75-
// Initialize throwawayPromise
76-
StoreMapNoWriteBarrier(throwaway, promise_map);
77-
InitializeJSObjectFromMap(
78-
throwaway, promise_map,
79-
IntPtrConstant(JSPromise::kSizeWithEmbedderFields));
80-
PromiseInit(throwaway);
81-
}
82-
83-
Node* const on_resolve = InnerAllocate(base, kResolveClosureOffset);
84-
{
85-
// Initialize resolve handler
86-
InitializeNativeClosure(closure_context, native_context, on_resolve,
87-
on_resolve_context_index);
88-
}
89-
90-
Node* const on_reject = InnerAllocate(base, kRejectClosureOffset);
91-
{
92-
// Initialize reject handler
93-
InitializeNativeClosure(closure_context, native_context, on_reject,
94-
on_reject_context_index);
95-
}
96-
97-
{
98-
// Add PromiseHooks if needed
99-
Label next(this);
100-
GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &next);
101-
CallRuntime(Runtime::kPromiseHookInit, context, wrapped_value,
102-
outer_promise);
103-
CallRuntime(Runtime::kPromiseHookInit, context, throwaway, wrapped_value);
104-
Goto(&next);
105-
BIND(&next);
106-
}
107-
108-
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « promise »).
109-
CallBuiltin(Builtins::kResolvePromise, context, wrapped_value, value);
110-
111-
// The Promise will be thrown away and not handled, but it shouldn't trigger
112-
// unhandled reject events as its work is done
113-
PromiseSetHasHandler(throwaway);
114-
115-
Label do_perform_promise_then(this);
116-
GotoIfNot(IsDebugActive(), &do_perform_promise_then);
117-
{
118-
Label common(this);
119-
GotoIf(TaggedIsSmi(value), &common);
120-
GotoIfNot(HasInstanceType(value, JS_PROMISE_TYPE), &common);
121-
{
122-
// Mark the reject handler callback to be a forwarding edge, rather
123-
// than a meaningful catch handler
124-
Node* const key =
125-
HeapConstant(factory()->promise_forwarding_handler_symbol());
126-
CallRuntime(Runtime::kSetProperty, context, on_reject, key,
127-
TrueConstant(), SmiConstant(LanguageMode::kStrict));
128-
129-
GotoIf(IsFalse(is_predicted_as_caught), &common);
130-
PromiseSetHandledHint(value);
131-
}
132-
133-
Goto(&common);
134-
BIND(&common);
135-
// Mark the dependency to outer Promise in case the throwaway Promise is
136-
// found on the Promise stack
137-
CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE));
138-
139-
Node* const key = HeapConstant(factory()->promise_handled_by_symbol());
140-
CallRuntime(Runtime::kSetProperty, context, throwaway, key, outer_promise,
141-
SmiConstant(LanguageMode::kStrict));
142-
}
143-
144-
Goto(&do_perform_promise_then);
145-
BIND(&do_perform_promise_then);
146-
return CallBuiltin(Builtins::kPerformPromiseThen, context, wrapped_value,
147-
on_resolve, on_reject, throwaway);
148-
}
149-
150-
void AsyncBuiltinsAssembler::InitializeNativeClosure(Node* context,
151-
Node* native_context,
152-
Node* function,
153-
Node* context_index) {
154-
Node* const function_map = LoadContextElement(
155-
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
156-
// Ensure that we don't have to initialize prototype_or_initial_map field of
157-
// JSFunction.
158-
CSA_ASSERT(this, WordEqual(LoadMapInstanceSizeInWords(function_map),
159-
IntPtrConstant(JSFunction::kSizeWithoutPrototype /
160-
kPointerSize)));
161-
STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize);
162-
StoreMapNoWriteBarrier(function, function_map);
163-
StoreObjectFieldRoot(function, JSObject::kPropertiesOrHashOffset,
164-
Heap::kEmptyFixedArrayRootIndex);
165-
StoreObjectFieldRoot(function, JSObject::kElementsOffset,
166-
Heap::kEmptyFixedArrayRootIndex);
167-
StoreObjectFieldRoot(function, JSFunction::kFeedbackVectorOffset,
168-
Heap::kUndefinedCellRootIndex);
169-
170-
Node* shared_info = LoadContextElement(native_context, context_index);
171-
CSA_ASSERT(this, IsSharedFunctionInfo(shared_info));
172-
StoreObjectFieldNoWriteBarrier(
173-
function, JSFunction::kSharedFunctionInfoOffset, shared_info);
174-
StoreObjectFieldNoWriteBarrier(function, JSFunction::kContextOffset, context);
175-
176-
Node* const code =
177-
LoadObjectField(shared_info, SharedFunctionInfo::kCodeOffset);
178-
StoreObjectFieldNoWriteBarrier(function, JSFunction::kCodeOffset, code);
179-
}
180-
18177
Node* AsyncBuiltinsAssembler::CreateUnwrapClosure(Node* native_context,
18278
Node* done) {
18379
Node* const map = LoadContextElement(

src/builtins/builtins-async-gen.h

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,48 +16,23 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler {
1616
: PromiseBuiltinsAssembler(state) {}
1717

1818
protected:
19-
typedef std::function<void(Node*)> ContextInitializer;
20-
21-
// Perform steps to resume generator after `value` is resolved.
22-
// `on_reject_context_index` is an index into the Native Context, which should
23-
// point to a SharedFunctioninfo instance used to create the closure. The
24-
// value following the reject index should be a similar value for the resolve
25-
// closure. Returns the Promise-wrapped `value`.
26-
Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise,
27-
int context_length,
28-
const ContextInitializer& init_closure_context,
29-
Node* on_resolve_context_index, Node* on_reject_context_index,
30-
Node* is_predicted_as_caught);
31-
Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise,
32-
int context_length,
33-
const ContextInitializer& init_closure_context,
34-
int on_resolve_context_index, int on_reject_context_index,
35-
Node* is_predicted_as_caught) {
36-
return Await(context, generator, value, outer_promise, context_length,
37-
init_closure_context, IntPtrConstant(on_resolve_context_index),
38-
IntPtrConstant(on_reject_context_index),
39-
is_predicted_as_caught);
40-
}
41-
Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise,
42-
int context_length,
43-
const ContextInitializer& init_closure_context,
44-
int on_resolve_context_index, int on_reject_context_index,
45-
bool is_predicted_as_caught) {
46-
return Await(context, generator, value, outer_promise, context_length,
47-
init_closure_context, on_resolve_context_index,
48-
on_reject_context_index,
49-
BooleanConstant(is_predicted_as_caught));
50-
}
19+
void Await(Node* context, Node* generator, Node* value, Node* outer_promise,
20+
Builtins::Name fulfill_builtin, Builtins::Name reject_builtin,
21+
Node* is_predicted_as_caught);
22+
void Await(Node* context, Node* generator, Node* value, Node* outer_promise,
23+
Builtins::Name fulfill_builtin, Builtins::Name reject_builtin,
24+
bool is_predicted_as_caught);
5125

5226
// Return a new built-in function object as defined in
5327
// Async Iterator Value Unwrap Functions
5428
Node* CreateUnwrapClosure(Node* const native_context, Node* const done);
5529

5630
private:
57-
void InitializeNativeClosure(Node* context, Node* native_context,
58-
Node* function, Node* context_index);
5931
Node* AllocateAsyncIteratorValueUnwrapContext(Node* native_context,
6032
Node* done);
33+
Node* AllocateAwaitPromiseJobTask(Node* generator, Node* fulfill_handler,
34+
Node* reject_handler, Node* promise,
35+
Node* context);
6136
};
6237

6338
} // namespace internal

0 commit comments

Comments
 (0)