Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/builtins/builtins-async-gen.h"
6 :
7 : #include "src/builtins/builtins-utils-gen.h"
8 : #include "src/factory-inl.h"
9 : #include "src/objects/shared-function-info.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 : using compiler::Node;
15 :
16 : namespace {
17 : // Describe fields of Context associated with the AsyncIterator unwrap closure.
18 : class ValueUnwrapContext {
19 : public:
20 : enum Fields { kDoneSlot = Context::MIN_CONTEXT_SLOTS, kLength };
21 : };
22 :
23 : } // namespace
24 :
25 186 : 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 372 : Node* const native_context = LoadNativeContext(context);
33 :
34 217 : static const int kWrappedPromiseOffset = FixedArray::SizeFor(context_length);
35 : static const int kThrowawayPromiseOffset =
36 186 : kWrappedPromiseOffset + JSPromise::kSizeWithEmbedderFields;
37 : static const int kResolveClosureOffset =
38 186 : kThrowawayPromiseOffset + JSPromise::kSizeWithEmbedderFields;
39 : static const int kRejectClosureOffset =
40 186 : kResolveClosureOffset + JSFunction::kSizeWithoutPrototype;
41 : static const int kTotalSize =
42 186 : kRejectClosureOffset + JSFunction::kSizeWithoutPrototype;
43 :
44 186 : Node* const base = AllocateInNewSpace(kTotalSize);
45 : Node* const closure_context = base;
46 : {
47 : // Initialize closure context
48 186 : InitializeFunctionContext(native_context, closure_context, context_length);
49 186 : init_closure_context(closure_context);
50 : }
51 :
52 : // Let promiseCapability be ! NewPromiseCapability(%Promise%).
53 : Node* const promise_fun =
54 372 : 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(LoadMapInstanceSize(promise_map),
61 : IntPtrConstant(JSPromise::kSizeWithEmbedderFields /
62 : kPointerSize)));
63 186 : Node* const wrapped_value = InnerAllocate(base, kWrappedPromiseOffset);
64 : {
65 : // Initialize Promise
66 186 : StoreMapNoWriteBarrier(wrapped_value, promise_map);
67 : InitializeJSObjectFromMap(
68 : wrapped_value, promise_map,
69 186 : IntPtrConstant(JSPromise::kSizeWithEmbedderFields),
70 744 : EmptyFixedArrayConstant(), EmptyFixedArrayConstant());
71 186 : PromiseInit(wrapped_value);
72 : }
73 :
74 186 : Node* const throwaway = InnerAllocate(base, kThrowawayPromiseOffset);
75 : {
76 : // Initialize throwawayPromise
77 186 : StoreMapNoWriteBarrier(throwaway, promise_map);
78 : InitializeJSObjectFromMap(
79 : throwaway, promise_map,
80 : IntPtrConstant(JSPromise::kSizeWithEmbedderFields),
81 744 : EmptyFixedArrayConstant(), EmptyFixedArrayConstant());
82 186 : PromiseInit(throwaway);
83 : }
84 :
85 186 : Node* const on_resolve = InnerAllocate(base, kResolveClosureOffset);
86 : {
87 : // Initialize resolve handler
88 : InitializeNativeClosure(closure_context, native_context, on_resolve,
89 186 : on_resolve_context_index);
90 : }
91 :
92 186 : Node* const on_reject = InnerAllocate(base, kRejectClosureOffset);
93 : {
94 : // Initialize reject handler
95 : InitializeNativeClosure(closure_context, native_context, on_reject,
96 186 : on_reject_context_index);
97 : }
98 :
99 : {
100 : // Add PromiseHooks if needed
101 : Label next(this);
102 372 : GotoIfNot(IsPromiseHookEnabledOrDebugIsActive(), &next);
103 : CallRuntime(Runtime::kPromiseHookInit, context, wrapped_value,
104 : outer_promise);
105 : CallRuntime(Runtime::kPromiseHookInit, context, throwaway, wrapped_value);
106 186 : Goto(&next);
107 186 : BIND(&next);
108 : }
109 :
110 : // Perform ! Call(promiseCapability.[[Resolve]], undefined, « promise »).
111 186 : CallBuiltin(Builtins::kResolveNativePromise, context, wrapped_value, value);
112 :
113 : // The Promise will be thrown away and not handled, but it shouldn't trigger
114 : // unhandled reject events as its work is done
115 186 : PromiseSetHasHandler(throwaway);
116 :
117 : Label do_perform_promise_then(this);
118 372 : GotoIfNot(IsDebugActive(), &do_perform_promise_then);
119 : {
120 : Label common(this);
121 372 : GotoIf(TaggedIsSmi(value), &common);
122 372 : GotoIfNot(HasInstanceType(value, JS_PROMISE_TYPE), &common);
123 : {
124 : // Mark the reject handler callback to be a forwarding edge, rather
125 : // than a meaningful catch handler
126 : Node* const key =
127 186 : HeapConstant(factory()->promise_forwarding_handler_symbol());
128 : CallRuntime(Runtime::kSetProperty, context, on_reject, key,
129 : TrueConstant(),
130 186 : SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
131 :
132 372 : GotoIf(IsFalse(is_predicted_as_caught), &common);
133 186 : PromiseSetHandledHint(value);
134 : }
135 :
136 186 : Goto(&common);
137 186 : BIND(&common);
138 : // Mark the dependency to outer Promise in case the throwaway Promise is
139 : // found on the Promise stack
140 : CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE));
141 :
142 186 : Node* const key = HeapConstant(factory()->promise_handled_by_symbol());
143 : CallRuntime(Runtime::kSetProperty, context, throwaway, key, outer_promise,
144 372 : SmiConstant(Smi::FromEnum(LanguageMode::kStrict)));
145 : }
146 :
147 186 : Goto(&do_perform_promise_then);
148 186 : BIND(&do_perform_promise_then);
149 :
150 : CallBuiltin(Builtins::kPerformNativePromiseThen, context, wrapped_value,
151 186 : on_resolve, on_reject, throwaway);
152 :
153 186 : return wrapped_value;
154 : }
155 :
156 372 : void AsyncBuiltinsAssembler::InitializeNativeClosure(Node* context,
157 : Node* native_context,
158 : Node* function,
159 : Node* context_index) {
160 : Node* const function_map = LoadContextElement(
161 744 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
162 : // Ensure that we don't have to initialize prototype_or_initial_map field of
163 : // JSFunction.
164 : CSA_ASSERT(this, WordEqual(LoadMapInstanceSize(function_map),
165 : IntPtrConstant(JSFunction::kSizeWithoutPrototype /
166 : kPointerSize)));
167 372 : StoreMapNoWriteBarrier(function, function_map);
168 : StoreObjectFieldRoot(function, JSObject::kPropertiesOrHashOffset,
169 372 : Heap::kEmptyFixedArrayRootIndex);
170 : StoreObjectFieldRoot(function, JSObject::kElementsOffset,
171 372 : Heap::kEmptyFixedArrayRootIndex);
172 : StoreObjectFieldRoot(function, JSFunction::kFeedbackVectorOffset,
173 372 : Heap::kUndefinedCellRootIndex);
174 :
175 744 : Node* shared_info = LoadContextElement(native_context, context_index);
176 : CSA_ASSERT(this, IsSharedFunctionInfo(shared_info));
177 : StoreObjectFieldNoWriteBarrier(
178 372 : function, JSFunction::kSharedFunctionInfoOffset, shared_info);
179 372 : StoreObjectFieldNoWriteBarrier(function, JSFunction::kContextOffset, context);
180 :
181 : Node* const code =
182 : LoadObjectField(shared_info, SharedFunctionInfo::kCodeOffset);
183 372 : StoreObjectFieldNoWriteBarrier(function, JSFunction::kCodeOffset, code);
184 372 : }
185 :
186 93 : Node* AsyncBuiltinsAssembler::CreateUnwrapClosure(Node* native_context,
187 : Node* done) {
188 : Node* const map = LoadContextElement(
189 186 : native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
190 : Node* const on_fulfilled_shared = LoadContextElement(
191 186 : native_context, Context::ASYNC_ITERATOR_VALUE_UNWRAP_SHARED_FUN);
192 : CSA_ASSERT(this,
193 : HasInstanceType(on_fulfilled_shared, SHARED_FUNCTION_INFO_TYPE));
194 : Node* const closure_context =
195 93 : AllocateAsyncIteratorValueUnwrapContext(native_context, done);
196 : return AllocateFunctionWithMapAndContext(map, on_fulfilled_shared,
197 93 : closure_context);
198 : }
199 :
200 93 : Node* AsyncBuiltinsAssembler::AllocateAsyncIteratorValueUnwrapContext(
201 : Node* native_context, Node* done) {
202 : CSA_ASSERT(this, IsNativeContext(native_context));
203 : CSA_ASSERT(this, IsBoolean(done));
204 :
205 : Node* const context =
206 93 : CreatePromiseContext(native_context, ValueUnwrapContext::kLength);
207 : StoreContextElementNoWriteBarrier(context, ValueUnwrapContext::kDoneSlot,
208 93 : done);
209 93 : return context;
210 : }
211 :
212 124 : TF_BUILTIN(AsyncIteratorValueUnwrap, AsyncBuiltinsAssembler) {
213 : Node* const value = Parameter(Descriptor::kValue);
214 : Node* const context = Parameter(Descriptor::kContext);
215 :
216 62 : Node* const done = LoadContextElement(context, ValueUnwrapContext::kDoneSlot);
217 : CSA_ASSERT(this, IsBoolean(done));
218 :
219 : Node* const unwrapped_value =
220 31 : CallBuiltin(Builtins::kCreateIterResultObject, context, value, done);
221 :
222 31 : Return(unwrapped_value);
223 31 : }
224 :
225 : } // namespace internal
226 : } // namespace v8
|