OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-promise.h" | 5 #include "src/builtins/builtins-promise.h" |
6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
7 #include "src/builtins/builtins.h" | 7 #include "src/builtins/builtins.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/code-stub-assembler.h" | 9 #include "src/code-stub-assembler.h" |
10 #include "src/promise-utils.h" | 10 #include "src/promise-utils.h" |
11 | 11 |
12 namespace v8 { | 12 namespace v8 { |
13 namespace internal { | 13 namespace internal { |
14 | 14 |
15 typedef compiler::Node Node; | 15 typedef compiler::Node Node; |
16 typedef CodeStubAssembler::ParameterMode ParameterMode; | 16 typedef CodeStubAssembler::ParameterMode ParameterMode; |
17 typedef compiler::CodeAssemblerState CodeAssemblerState; | 17 typedef compiler::CodeAssemblerState CodeAssemblerState; |
18 | 18 |
19 Node* PromiseBuiltinsAssembler::AllocateAndInitPromise(Node* context, | |
20 Node* parent) { | |
21 Node* const instance = AllocateJSPromise(context); | |
22 PromiseInit(instance); | |
23 | |
24 Label out(this); | |
25 GotoUnless(IsPromiseHookEnabled(), &out); | |
26 CallRuntime(Runtime::kPromiseHookInit, context, instance, parent); | |
27 Goto(&out); | |
28 | |
29 Bind(&out); | |
30 return instance; | |
31 } | |
32 | |
19 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext( | 33 Node* PromiseBuiltinsAssembler::CreatePromiseResolvingFunctionsContext( |
20 Node* promise, Node* debug_event, Node* native_context) { | 34 Node* promise, Node* debug_event, Node* native_context) { |
21 Node* const context = | 35 Node* const context = |
22 Allocate(FixedArray::SizeFor(PromiseUtils::kPromiseContextLength)); | 36 Allocate(FixedArray::SizeFor(PromiseUtils::kPromiseContextLength)); |
23 StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex); | 37 StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex); |
24 StoreObjectFieldNoWriteBarrier( | 38 StoreObjectFieldNoWriteBarrier( |
25 context, FixedArray::kLengthOffset, | 39 context, FixedArray::kLengthOffset, |
26 SmiConstant(PromiseUtils::kPromiseContextLength)); | 40 SmiConstant(PromiseUtils::kPromiseContextLength)); |
27 | 41 |
28 Node* const empty_fn = | 42 Node* const empty_fn = |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 Node* new_elements = AllocateFixedArray(kind, new_capacity, mode, flags); | 188 Node* new_elements = AllocateFixedArray(kind, new_capacity, mode, flags); |
175 | 189 |
176 CopyFixedArrayElements(kind, elements, new_elements, length, barrier_mode, | 190 CopyFixedArrayElements(kind, elements, new_elements, length, barrier_mode, |
177 mode); | 191 mode); |
178 StoreFixedArrayElement(new_elements, length, value, barrier_mode, | 192 StoreFixedArrayElement(new_elements, length, value, barrier_mode, |
179 additional_offset, mode); | 193 additional_offset, mode); |
180 | 194 |
181 StoreObjectField(promise, offset, new_elements); | 195 StoreObjectField(promise, offset, new_elements); |
182 } | 196 } |
183 | 197 |
184 Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen(Node* context, | 198 Node* PromiseBuiltinsAssembler::InternalPerformPromiseThen( |
185 Node* promise, | 199 Node* context, Node* promise, Node* on_resolve, Node* on_reject, |
186 Node* on_resolve, | 200 Node* deferred_promise, Node* deferred_on_resolve, |
187 Node* on_reject, | 201 Node* deferred_on_reject) { |
188 Node* deferred) { | |
189 Node* const native_context = LoadNativeContext(context); | 202 Node* const native_context = LoadNativeContext(context); |
190 | 203 |
191 Variable var_on_resolve(this, MachineRepresentation::kTagged), | 204 Variable var_on_resolve(this, MachineRepresentation::kTagged), |
192 var_on_reject(this, MachineRepresentation::kTagged); | 205 var_on_reject(this, MachineRepresentation::kTagged); |
193 | 206 |
194 var_on_resolve.Bind(on_resolve); | 207 var_on_resolve.Bind(on_resolve); |
195 var_on_reject.Bind(on_reject); | 208 var_on_reject.Bind(on_reject); |
196 | 209 |
197 Label out(this), if_onresolvenotcallable(this), onrejectcheck(this), | 210 Label out(this), if_onresolvenotcallable(this), onrejectcheck(this), |
198 append_callbacks(this); | 211 append_callbacks(this); |
(...skipping 27 matching lines...) Expand all Loading... | |
226 } | 239 } |
227 } | 240 } |
228 | 241 |
229 Bind(&append_callbacks); | 242 Bind(&append_callbacks); |
230 { | 243 { |
231 Label fulfilled_check(this); | 244 Label fulfilled_check(this); |
232 Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset); | 245 Node* const status = LoadObjectField(promise, JSPromise::kStatusOffset); |
233 GotoUnless(SmiEqual(status, SmiConstant(kPromisePending)), | 246 GotoUnless(SmiEqual(status, SmiConstant(kPromisePending)), |
234 &fulfilled_check); | 247 &fulfilled_check); |
235 | 248 |
236 Node* const existing_deferred = | 249 Node* const existing_deferred_promise = |
237 LoadObjectField(promise, JSPromise::kDeferredOffset); | 250 LoadObjectField(promise, JSPromise::kDeferredPromiseOffset); |
238 | 251 |
239 Label if_noexistingcallbacks(this), if_existingcallbacks(this); | 252 Label if_noexistingcallbacks(this), if_existingcallbacks(this); |
240 Branch(IsUndefined(existing_deferred), &if_noexistingcallbacks, | 253 Branch(IsUndefined(existing_deferred_promise), &if_noexistingcallbacks, |
241 &if_existingcallbacks); | 254 &if_existingcallbacks); |
242 | 255 |
243 Bind(&if_noexistingcallbacks); | 256 Bind(&if_noexistingcallbacks); |
244 { | 257 { |
245 // Store callbacks directly in the slots. | 258 // Store callbacks directly in the slots. |
246 StoreObjectField(promise, JSPromise::kDeferredOffset, deferred); | 259 StoreObjectField(promise, JSPromise::kDeferredPromiseOffset, |
260 deferred_promise); | |
261 StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset, | |
262 deferred_on_resolve); | |
263 StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset, | |
264 deferred_on_reject); | |
247 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, | 265 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
248 var_on_resolve.value()); | 266 var_on_resolve.value()); |
249 StoreObjectField(promise, JSPromise::kRejectReactionsOffset, | 267 StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
250 var_on_reject.value()); | 268 var_on_reject.value()); |
251 Goto(&out); | 269 Goto(&out); |
252 } | 270 } |
253 | 271 |
254 Bind(&if_existingcallbacks); | 272 Bind(&if_existingcallbacks); |
255 { | 273 { |
256 Label if_singlecallback(this), if_multiplecallbacks(this); | 274 Label if_singlecallback(this), if_multiplecallbacks(this); |
257 BranchIfJSObject(existing_deferred, &if_singlecallback, | 275 BranchIfJSObject(existing_deferred_promise, &if_singlecallback, |
258 &if_multiplecallbacks); | 276 &if_multiplecallbacks); |
259 | 277 |
260 Bind(&if_singlecallback); | 278 Bind(&if_singlecallback); |
261 { | 279 { |
262 // Create new FixedArrays to store callbacks, and migrate | 280 // Create new FixedArrays to store callbacks, and migrate |
263 // existing callbacks. | 281 // existing callbacks. |
264 Node* const deferreds = | 282 Node* const deferred_promises = |
265 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | 283 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
266 StoreFixedArrayElement(deferreds, 0, existing_deferred); | 284 StoreFixedArrayElement(deferred_promises, 0, existing_deferred_promise); |
267 StoreFixedArrayElement(deferreds, 1, deferred); | 285 StoreFixedArrayElement(deferred_promises, 1, deferred_promise); |
286 | |
287 Node* const deferred_on_resolves = | |
288 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | |
289 StoreFixedArrayElement( | |
290 deferred_on_resolves, 0, | |
291 LoadObjectField(promise, JSPromise::kDeferredOnResolveOffset)); | |
292 StoreFixedArrayElement(deferred_on_resolve, 1, deferred_on_resolve); | |
293 | |
294 Node* const deferred_on_rejects = | |
295 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | |
296 StoreFixedArrayElement( | |
297 deferred_on_rejects, 0, | |
298 LoadObjectField(promise, JSPromise::kDeferredOnRejectOffset)); | |
299 StoreFixedArrayElement(deferred_on_rejects, 1, deferred_on_reject); | |
268 | 300 |
269 Node* const fulfill_reactions = | 301 Node* const fulfill_reactions = |
270 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | 302 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
271 StoreFixedArrayElement( | 303 StoreFixedArrayElement( |
272 fulfill_reactions, 0, | 304 fulfill_reactions, 0, |
273 LoadObjectField(promise, JSPromise::kFulfillReactionsOffset)); | 305 LoadObjectField(promise, JSPromise::kFulfillReactionsOffset)); |
274 StoreFixedArrayElement(fulfill_reactions, 1, var_on_resolve.value()); | 306 StoreFixedArrayElement(fulfill_reactions, 1, var_on_resolve.value()); |
275 | 307 |
276 Node* const reject_reactions = | 308 Node* const reject_reactions = |
277 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); | 309 AllocateFixedArray(FAST_ELEMENTS, IntPtrConstant(2)); |
278 StoreFixedArrayElement( | 310 StoreFixedArrayElement( |
279 reject_reactions, 0, | 311 reject_reactions, 0, |
280 LoadObjectField(promise, JSPromise::kRejectReactionsOffset)); | 312 LoadObjectField(promise, JSPromise::kRejectReactionsOffset)); |
281 StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value()); | 313 StoreFixedArrayElement(reject_reactions, 1, var_on_reject.value()); |
282 | 314 |
283 // Store new FixedArrays in promise. | 315 // Store new FixedArrays in promise. |
284 StoreObjectField(promise, JSPromise::kDeferredOffset, deferreds); | 316 StoreObjectField(promise, JSPromise::kDeferredPromiseOffset, |
caitp
2016/12/20 02:53:01
The multiple chains case seems likely to regress w
| |
317 deferred_promises); | |
318 StoreObjectField(promise, JSPromise::kDeferredOnResolveOffset, | |
319 deferred_on_resolves); | |
320 StoreObjectField(promise, JSPromise::kDeferredOnRejectOffset, | |
321 deferred_on_rejects); | |
285 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, | 322 StoreObjectField(promise, JSPromise::kFulfillReactionsOffset, |
286 fulfill_reactions); | 323 fulfill_reactions); |
287 StoreObjectField(promise, JSPromise::kRejectReactionsOffset, | 324 StoreObjectField(promise, JSPromise::kRejectReactionsOffset, |
288 reject_reactions); | 325 reject_reactions); |
289 Goto(&out); | 326 Goto(&out); |
290 } | 327 } |
291 | 328 |
292 Bind(&if_multiplecallbacks); | 329 Bind(&if_multiplecallbacks); |
293 { | 330 { |
294 AppendPromiseCallback(JSPromise::kDeferredOffset, promise, deferred); | 331 AppendPromiseCallback(JSPromise::kDeferredPromiseOffset, promise, |
332 deferred_promise); | |
333 AppendPromiseCallback(JSPromise::kDeferredOnResolveOffset, promise, | |
334 deferred_on_resolve); | |
335 AppendPromiseCallback(JSPromise::kDeferredOnRejectOffset, promise, | |
336 deferred_on_reject); | |
295 AppendPromiseCallback(JSPromise::kFulfillReactionsOffset, promise, | 337 AppendPromiseCallback(JSPromise::kFulfillReactionsOffset, promise, |
296 var_on_resolve.value()); | 338 var_on_resolve.value()); |
297 AppendPromiseCallback(JSPromise::kRejectReactionsOffset, promise, | 339 AppendPromiseCallback(JSPromise::kRejectReactionsOffset, promise, |
298 var_on_reject.value()); | 340 var_on_reject.value()); |
299 Goto(&out); | 341 Goto(&out); |
300 } | 342 } |
301 } | 343 } |
302 | 344 |
303 Bind(&fulfilled_check); | 345 Bind(&fulfilled_check); |
304 { | 346 { |
305 Label reject(this); | 347 Label reject(this); |
306 Node* const result = LoadObjectField(promise, JSPromise::kResultOffset); | 348 Node* const result = LoadObjectField(promise, JSPromise::kResultOffset); |
307 GotoUnless(WordEqual(status, SmiConstant(kPromiseFulfilled)), &reject); | 349 GotoUnless(WordEqual(status, SmiConstant(kPromiseFulfilled)), &reject); |
308 | 350 |
309 // TODO(gsathya): Move this to TF. | 351 Node* info = AllocatePromiseReactionJobInfo( |
310 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, result, | 352 promise, result, var_on_resolve.value(), deferred_promise, |
311 var_on_resolve.value(), deferred, | 353 deferred_on_resolve, deferred_on_reject, context); |
354 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info, | |
312 SmiConstant(kPromiseFulfilled)); | 355 SmiConstant(kPromiseFulfilled)); |
313 Goto(&out); | 356 Goto(&out); |
314 | 357 |
315 Bind(&reject); | 358 Bind(&reject); |
316 { | 359 { |
317 Node* const has_handler = PromiseHasHandler(promise); | 360 Node* const has_handler = PromiseHasHandler(promise); |
318 Label enqueue(this); | 361 Label enqueue(this); |
319 | 362 |
320 // TODO(gsathya): Fold these runtime calls and move to TF. | 363 // TODO(gsathya): Fold these runtime calls and move to TF. |
321 GotoIf(has_handler, &enqueue); | 364 GotoIf(has_handler, &enqueue); |
322 CallRuntime(Runtime::kPromiseRevokeReject, context, promise); | 365 CallRuntime(Runtime::kPromiseRevokeReject, context, promise); |
323 Goto(&enqueue); | 366 Goto(&enqueue); |
324 | 367 |
325 Bind(&enqueue); | 368 Bind(&enqueue); |
326 { | 369 { |
327 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, promise, | 370 Node* info = AllocatePromiseReactionJobInfo( |
328 result, var_on_reject.value(), deferred, | 371 promise, result, var_on_reject.value(), deferred_promise, |
372 deferred_on_resolve, deferred_on_reject, context); | |
373 CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, info, | |
329 SmiConstant(kPromiseRejected)); | 374 SmiConstant(kPromiseRejected)); |
330 | 375 |
331 Goto(&out); | 376 Goto(&out); |
332 } | 377 } |
333 } | 378 } |
334 } | 379 } |
335 } | 380 } |
336 | 381 |
337 Bind(&out); | 382 Bind(&out); |
338 PromiseSetHasHandler(promise); | 383 PromiseSetHasHandler(promise); |
339 | 384 return deferred_promise; |
340 // TODO(gsathya): This call will be removed once we don't have to | |
341 // deal with deferred objects. | |
342 Isolate* isolate = this->isolate(); | |
343 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
344 Node* const key = | |
345 HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); | |
346 Node* const result = CallStub(getproperty_callable, context, deferred, key); | |
347 | |
348 return result; | |
349 } | 385 } |
350 | 386 |
351 // Promise fast path implementations rely on unmodified JSPromise instances. | 387 // Promise fast path implementations rely on unmodified JSPromise instances. |
352 // We use a fairly coarse granularity for this and simply check whether both | 388 // We use a fairly coarse granularity for this and simply check whether both |
353 // the promise itself is unmodified (i.e. its map has not changed) and its | 389 // the promise itself is unmodified (i.e. its map has not changed) and its |
354 // prototype is unmodified. | 390 // prototype is unmodified. |
355 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp | 391 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp |
356 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, | 392 void PromiseBuiltinsAssembler::BranchIfFastPath(Node* context, Node* promise, |
357 Label* if_isunmodified, | 393 Label* if_isunmodified, |
358 Label* if_ismodified) { | 394 Label* if_ismodified) { |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
698 Node* const message_id = | 734 Node* const message_id = |
699 SmiConstant(MessageTemplate::kResolverNotAFunction); | 735 SmiConstant(MessageTemplate::kResolverNotAFunction); |
700 CallRuntime(Runtime::kThrowTypeError, context, message_id, executor); | 736 CallRuntime(Runtime::kThrowTypeError, context, message_id, executor); |
701 Return(UndefinedConstant()); // Never reached. | 737 Return(UndefinedConstant()); // Never reached. |
702 } | 738 } |
703 } | 739 } |
704 | 740 |
705 TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) { | 741 TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) { |
706 Node* const parent = Parameter(1); | 742 Node* const parent = Parameter(1); |
707 Node* const context = Parameter(4); | 743 Node* const context = Parameter(4); |
708 Node* const instance = AllocateJSPromise(context); | 744 Return(AllocateAndInitPromise(context, parent)); |
709 PromiseInit(instance); | |
710 | |
711 Label out(this); | |
712 GotoUnless(IsPromiseHookEnabled(), &out); | |
713 CallRuntime(Runtime::kPromiseHookInit, context, instance, parent); | |
714 Goto(&out); | |
715 Bind(&out); | |
716 | |
717 Return(instance); | |
718 } | 745 } |
719 | 746 |
720 TF_BUILTIN(PromiseCreateAndSet, PromiseBuiltinsAssembler) { | 747 TF_BUILTIN(PromiseCreateAndSet, PromiseBuiltinsAssembler) { |
721 Node* const status = Parameter(1); | 748 Node* const status = Parameter(1); |
722 Node* const result = Parameter(2); | 749 Node* const result = Parameter(2); |
723 Node* const context = Parameter(5); | 750 Node* const context = Parameter(5); |
724 | 751 |
725 Node* const instance = AllocateJSPromise(context); | 752 Node* const instance = AllocateJSPromise(context); |
726 PromiseSet(instance, status, result); | 753 PromiseSet(instance, status, result); |
727 | 754 |
(...skipping 17 matching lines...) Expand all Loading... | |
745 Return(result); | 772 Return(result); |
746 | 773 |
747 Bind(&if_notpromise); | 774 Bind(&if_notpromise); |
748 Return(FalseConstant()); | 775 Return(FalseConstant()); |
749 } | 776 } |
750 | 777 |
751 TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) { | 778 TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) { |
752 Node* const promise = Parameter(1); | 779 Node* const promise = Parameter(1); |
753 Node* const on_resolve = Parameter(2); | 780 Node* const on_resolve = Parameter(2); |
754 Node* const on_reject = Parameter(3); | 781 Node* const on_reject = Parameter(3); |
755 Node* const deferred = Parameter(4); | 782 Node* const deferred_promise = Parameter(4); |
756 Node* const context = Parameter(7); | 783 Node* const context = Parameter(7); |
757 | 784 |
758 Node* const result = InternalPerformPromiseThen(context, promise, on_resolve, | 785 // No deferred_on_resolve/deferred_on_reject because this is just an |
759 on_reject, deferred); | 786 // internal promise created by async-await. |
787 Node* const result = InternalPerformPromiseThen( | |
788 context, promise, on_resolve, on_reject, deferred_promise, | |
789 UndefinedConstant(), UndefinedConstant()); | |
760 | 790 |
761 // TODO(gsathya): This is unused, but value is returned according to spec. | 791 // TODO(gsathya): This is unused, but value is returned according to spec. |
762 Return(result); | 792 Return(result); |
763 } | 793 } |
764 | 794 |
765 TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) { | 795 TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) { |
766 // 1. Let promise be the this value. | 796 // 1. Let promise be the this value. |
767 Node* const promise = Parameter(0); | 797 Node* const promise = Parameter(0); |
768 Node* const on_resolve = Parameter(1); | 798 Node* const on_resolve = Parameter(1); |
769 Node* const on_reject = Parameter(2); | 799 Node* const on_reject = Parameter(2); |
770 Node* const context = Parameter(5); | 800 Node* const context = Parameter(5); |
771 Isolate* isolate = this->isolate(); | 801 Isolate* isolate = this->isolate(); |
772 | 802 |
773 // 2. If IsPromise(promise) is false, throw a TypeError exception. | 803 // 2. If IsPromise(promise) is false, throw a TypeError exception. |
774 ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE, | 804 ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE, |
775 "Promise.prototype.then"); | 805 "Promise.prototype.then"); |
776 | 806 |
777 Node* const native_context = LoadNativeContext(context); | 807 Node* const native_context = LoadNativeContext(context); |
778 Node* const promise_fun = | 808 Node* const promise_fun = |
779 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); | 809 LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
780 | 810 |
781 // 3. Let C be ? SpeciesConstructor(promise, %Promise%). | 811 // 3. Let C be ? SpeciesConstructor(promise, %Promise%). |
782 Node* constructor = SpeciesConstructor(context, promise, promise_fun); | 812 Node* constructor = SpeciesConstructor(context, promise, promise_fun); |
783 | 813 |
784 // 4. Let resultCapability be ? NewPromiseCapability(C). | 814 // 4. Let resultCapability be ? NewPromiseCapability(C). |
785 Callable call_callable = CodeFactory::Call(isolate); | 815 Callable call_callable = CodeFactory::Call(isolate); |
786 Label fast_promise_capability(this), promise_capability(this), | 816 Label fast_promise_capability(this), promise_capability(this), |
787 perform_promise_then(this); | 817 perform_promise_then(this); |
788 Variable var_deferred(this, MachineRepresentation::kTagged); | 818 Variable var_deferred_promise(this, MachineRepresentation::kTagged), |
819 var_deferred_on_resolve(this, MachineRepresentation::kTagged), | |
820 var_deferred_on_reject(this, MachineRepresentation::kTagged); | |
789 | 821 |
790 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, | 822 Branch(WordEqual(promise_fun, constructor), &fast_promise_capability, |
791 &promise_capability); | 823 &promise_capability); |
792 | 824 |
793 // TODO(gsathya): Remove deferred object and move | |
794 // NewPromiseCapabability functions to TF. | |
795 Bind(&fast_promise_capability); | 825 Bind(&fast_promise_capability); |
796 { | 826 { |
797 // TODO(gsathya): Move this to TF. | 827 Node* const deferred_promise = AllocateAndInitPromise(context, promise); |
798 Node* const promise_internal_capability = LoadContextElement( | 828 PromiseInit(deferred_promise); |
799 native_context, Context::INTERNAL_PROMISE_CAPABILITY_INDEX); | 829 var_deferred_promise.Bind(deferred_promise); |
800 Node* const capability = | 830 var_deferred_on_resolve.Bind(UndefinedConstant()); |
801 CallJS(call_callable, context, promise_internal_capability, | 831 var_deferred_on_reject.Bind(UndefinedConstant()); |
802 UndefinedConstant(), promise); | |
803 var_deferred.Bind(capability); | |
804 Goto(&perform_promise_then); | 832 Goto(&perform_promise_then); |
805 } | 833 } |
806 | 834 |
807 Bind(&promise_capability); | 835 Bind(&promise_capability); |
808 { | 836 { |
809 // TODO(gsathya): Move this to TF. | 837 // TODO(gsathya): Move this to TF. |
810 Node* const new_promise_capability = LoadContextElement( | 838 Node* const new_promise_capability = LoadContextElement( |
811 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); | 839 native_context, Context::NEW_PROMISE_CAPABILITY_INDEX); |
812 Node* const capability = | 840 Node* const deferred = |
813 CallJS(call_callable, context, new_promise_capability, | 841 CallJS(call_callable, context, new_promise_capability, |
814 UndefinedConstant(), constructor); | 842 UndefinedConstant(), constructor); |
815 var_deferred.Bind(capability); | 843 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
844 Node* key = HeapConstant(isolate->factory()->promise_string()); | |
845 Node* const deferred_promise = | |
846 CallStub(getproperty_callable, context, deferred, key); | |
847 var_deferred_promise.Bind(deferred_promise); | |
848 | |
849 key = HeapConstant(isolate->factory()->resolve_string()); | |
850 Node* const deferred_on_resolve = | |
851 CallStub(getproperty_callable, context, deferred, key); | |
852 var_deferred_on_resolve.Bind(deferred_on_resolve); | |
853 | |
854 key = HeapConstant(isolate->factory()->reject_string()); | |
855 Node* const deferred_on_reject = | |
856 CallStub(getproperty_callable, context, deferred, key); | |
857 var_deferred_on_reject.Bind(deferred_on_reject); | |
858 | |
816 Goto(&perform_promise_then); | 859 Goto(&perform_promise_then); |
817 } | 860 } |
818 | 861 |
819 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, | 862 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, |
820 // resultCapability). | 863 // resultCapability). |
821 Bind(&perform_promise_then); | 864 Bind(&perform_promise_then); |
822 Node* const result = InternalPerformPromiseThen( | 865 Node* const result = InternalPerformPromiseThen( |
823 context, promise, on_resolve, on_reject, var_deferred.value()); | 866 context, promise, on_resolve, on_reject, var_deferred_promise.value(), |
867 var_deferred_on_resolve.value(), var_deferred_on_reject.value()); | |
824 Return(result); | 868 Return(result); |
825 } | 869 } |
826 | 870 |
827 // ES#sec-promise-resolve-functions | 871 // ES#sec-promise-resolve-functions |
828 // Promise Resolve Functions | 872 // Promise Resolve Functions |
829 TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) { | 873 TF_BUILTIN(PromiseResolveClosure, PromiseBuiltinsAssembler) { |
830 Node* const value = Parameter(1); | 874 Node* const value = Parameter(1); |
831 Node* const context = Parameter(4); | 875 Node* const context = Parameter(4); |
832 | 876 |
833 Label out(this); | 877 Label out(this); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
892 { | 936 { |
893 CallJS(call_callable, context, on_reject, UndefinedConstant(), exception); | 937 CallJS(call_callable, context, on_reject, UndefinedConstant(), exception); |
894 Return(UndefinedConstant()); | 938 Return(UndefinedConstant()); |
895 } | 939 } |
896 } | 940 } |
897 | 941 |
898 TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { | 942 TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { |
899 Node* const promise = Parameter(1); | 943 Node* const promise = Parameter(1); |
900 Node* const value = Parameter(2); | 944 Node* const value = Parameter(2); |
901 Node* const handler = Parameter(3); | 945 Node* const handler = Parameter(3); |
902 Node* const deferred = Parameter(4); | 946 Node* const deferred_promise = Parameter(4); |
903 Node* const context = Parameter(7); | 947 Node* const deferred_on_resolve = Parameter(5); |
948 Node* const deferred_on_reject = Parameter(6); | |
949 Node* const context = Parameter(9); | |
904 Isolate* isolate = this->isolate(); | 950 Isolate* isolate = this->isolate(); |
905 | 951 |
906 // Get promise from deferred | 952 // Get promise from deferred |
907 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | |
908 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
909 Node* const key = HeapConstant(isolate->factory()->promise_string()); | |
910 Node* const deferred_promise = | |
911 CallStub(getproperty_callable, context, deferred, key); | |
912 | |
913 Variable var_reason(this, MachineRepresentation::kTagged); | 953 Variable var_reason(this, MachineRepresentation::kTagged); |
914 | 954 |
915 Node* const is_debug_active = IsDebugActive(); | 955 Node* const is_debug_active = IsDebugActive(); |
916 Label run_handler(this), if_rejectpromise(this), promisehook_before(this), | 956 Label run_handler(this), if_rejectpromise(this), promisehook_before(this), |
917 promisehook_after(this), debug_pop(this); | 957 promisehook_after(this), debug_pop(this); |
918 | 958 |
919 GotoUnless(is_debug_active, &promisehook_before); | 959 GotoUnless(is_debug_active, &promisehook_before); |
920 CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); | 960 CallRuntime(Runtime::kDebugPushPromise, context, deferred_promise); |
921 Goto(&promisehook_before); | 961 Goto(&promisehook_before); |
922 | 962 |
923 Bind(&promisehook_before); | 963 Bind(&promisehook_before); |
924 { | 964 { |
925 GotoUnless(IsPromiseHookEnabled(), &run_handler); | 965 GotoUnless(IsPromiseHookEnabled(), &run_handler); |
926 CallRuntime(Runtime::kPromiseHookBefore, context, promise); | 966 CallRuntime(Runtime::kPromiseHookBefore, context, promise); |
927 Goto(&run_handler); | 967 Goto(&run_handler); |
928 } | 968 } |
929 | 969 |
930 Bind(&run_handler); | 970 Bind(&run_handler); |
931 { | 971 { |
932 Callable call_callable = CodeFactory::Call(isolate); | 972 Callable call_callable = CodeFactory::Call(isolate); |
933 | |
934 Node* const result = | 973 Node* const result = |
935 CallJS(call_callable, context, handler, UndefinedConstant(), value); | 974 CallJS(call_callable, context, handler, UndefinedConstant(), value); |
936 | 975 |
937 GotoIfException(result, &if_rejectpromise, &var_reason); | 976 GotoIfException(result, &if_rejectpromise, &var_reason); |
938 | 977 |
939 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | 978 Node* const on_resolve = deferred_on_resolve; |
940 Node* const key = HeapConstant(isolate->factory()->resolve_string()); | |
941 Node* const on_resolve = | |
942 CallStub(getproperty_callable, context, deferred, key); | |
943 | 979 |
944 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); | 980 Label if_internalhandler(this), if_customhandler(this, Label::kDeferred); |
945 Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); | 981 Branch(IsUndefined(on_resolve), &if_internalhandler, &if_customhandler); |
946 | 982 |
947 Bind(&if_internalhandler); | 983 Bind(&if_internalhandler); |
948 InternalResolvePromise(context, deferred_promise, result, | 984 InternalResolvePromise(context, deferred_promise, result, |
949 &promisehook_after); | 985 &promisehook_after); |
950 | 986 |
951 Bind(&if_customhandler); | 987 Bind(&if_customhandler); |
952 { | 988 { |
953 Node* const maybe_exception = CallJS(call_callable, context, on_resolve, | 989 Node* const maybe_exception = CallJS(call_callable, context, on_resolve, |
954 UndefinedConstant(), result); | 990 UndefinedConstant(), result); |
955 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); | 991 GotoIfException(maybe_exception, &if_rejectpromise, &var_reason); |
956 Goto(&promisehook_after); | 992 Goto(&promisehook_after); |
957 } | 993 } |
958 } | 994 } |
959 | 995 |
960 Bind(&if_rejectpromise); | 996 Bind(&if_rejectpromise); |
961 { | 997 { |
962 // TODO(gsathya): Remove this lookup by getting rid of the deferred object. | 998 Node* const on_reject = deferred_on_reject; |
963 Node* const key = HeapConstant(isolate->factory()->reject_string()); | |
964 Node* const on_reject = | |
965 CallStub(getproperty_callable, context, deferred, key); | |
966 | |
967 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); | 999 Callable promise_handle_reject = CodeFactory::PromiseHandleReject(isolate); |
968 CallStub(promise_handle_reject, context, deferred_promise, on_reject, | 1000 CallStub(promise_handle_reject, context, deferred_promise, on_reject, |
969 var_reason.value()); | 1001 var_reason.value()); |
970 Goto(&promisehook_after); | 1002 Goto(&promisehook_after); |
971 } | 1003 } |
972 | 1004 |
973 Bind(&promisehook_after); | 1005 Bind(&promisehook_after); |
974 { | 1006 { |
975 GotoUnless(IsPromiseHookEnabled(), &debug_pop); | 1007 GotoUnless(IsPromiseHookEnabled(), &debug_pop); |
976 CallRuntime(Runtime::kPromiseHookAfter, context, promise); | 1008 CallRuntime(Runtime::kPromiseHookAfter, context, promise); |
977 Goto(&debug_pop); | 1009 Goto(&debug_pop); |
978 } | 1010 } |
979 | 1011 |
980 Bind(&debug_pop); | 1012 Bind(&debug_pop); |
981 { | 1013 { |
982 Label out(this); | 1014 Label out(this); |
983 | 1015 |
984 GotoUnless(is_debug_active, &out); | 1016 GotoUnless(is_debug_active, &out); |
985 CallRuntime(Runtime::kDebugPopPromise, context); | 1017 CallRuntime(Runtime::kDebugPopPromise, context); |
986 Goto(&out); | 1018 Goto(&out); |
987 | 1019 |
988 Bind(&out); | 1020 Bind(&out); |
989 Return(UndefinedConstant()); | 1021 Return(UndefinedConstant()); |
990 } | 1022 } |
991 } | 1023 } |
992 | 1024 |
993 } // namespace internal | 1025 } // namespace internal |
994 } // namespace v8 | 1026 } // namespace v8 |
OLD | NEW |