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-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
9 #include "src/promise-utils.h" | 9 #include "src/promise-utils.h" |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 | 13 |
14 // ES#sec-promise-resolve-functions | |
15 // Promise Resolve Functions | |
16 BUILTIN(PromiseResolveClosure) { | |
17 HandleScope scope(isolate); | |
18 | |
19 Handle<Context> context(isolate->context(), isolate); | |
20 | |
21 if (PromiseUtils::HasAlreadyVisited(context)) { | |
22 return isolate->heap()->undefined_value(); | |
23 } | |
24 | |
25 PromiseUtils::SetAlreadyVisited(context); | |
26 Handle<JSObject> promise = handle(PromiseUtils::GetPromise(context), isolate); | |
27 Handle<Object> value = args.atOrUndefined(isolate, 1); | |
28 | |
29 MaybeHandle<Object> maybe_result; | |
30 Handle<Object> argv[] = {promise, value}; | |
31 RETURN_FAILURE_ON_EXCEPTION( | |
32 isolate, Execution::Call(isolate, isolate->promise_resolve(), | |
33 isolate->factory()->undefined_value(), | |
34 arraysize(argv), argv)); | |
35 return isolate->heap()->undefined_value(); | |
36 } | |
37 | |
38 // ES#sec-promise-reject-functions | 14 // ES#sec-promise-reject-functions |
39 // Promise Reject Functions | 15 // Promise Reject Functions |
40 BUILTIN(PromiseRejectClosure) { | 16 BUILTIN(PromiseRejectClosure) { |
41 HandleScope scope(isolate); | 17 HandleScope scope(isolate); |
42 | 18 |
43 Handle<Context> context(isolate->context(), isolate); | 19 Handle<Context> context(isolate->context(), isolate); |
44 | 20 |
45 if (PromiseUtils::HasAlreadyVisited(context)) { | 21 if (PromiseUtils::HasAlreadyVisited(context)) { |
46 return isolate->heap()->undefined_value(); | 22 return isolate->heap()->undefined_value(); |
47 } | 23 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 | 55 |
80 return *isolate->factory()->NewJSArrayWithElements(result, FAST_ELEMENTS, 2, | 56 return *isolate->factory()->NewJSArrayWithElements(result, FAST_ELEMENTS, 2, |
81 NOT_TENURED); | 57 NOT_TENURED); |
82 } | 58 } |
83 | 59 |
84 void PromiseInit(CodeStubAssembler* a, compiler::Node* promise, | 60 void PromiseInit(CodeStubAssembler* a, compiler::Node* promise, |
85 compiler::Node* status, compiler::Node* result) { | 61 compiler::Node* status, compiler::Node* result) { |
86 CSA_ASSERT(a, a->TaggedIsSmi(status)); | 62 CSA_ASSERT(a, a->TaggedIsSmi(status)); |
87 a->StoreObjectField(promise, JSPromise::kStatusOffset, status); | 63 a->StoreObjectField(promise, JSPromise::kStatusOffset, status); |
88 a->StoreObjectField(promise, JSPromise::kResultOffset, result); | 64 a->StoreObjectField(promise, JSPromise::kResultOffset, result); |
| 65 a->StoreObjectField(promise, JSPromise::kFlagsOffset, a->SmiConstant(0)); |
89 } | 66 } |
90 | 67 |
91 void Builtins::Generate_PromiseConstructor( | 68 void Builtins::Generate_PromiseConstructor( |
92 compiler::CodeAssemblerState* state) { | 69 compiler::CodeAssemblerState* state) { |
93 CodeStubAssembler a(state); | 70 CodeStubAssembler a(state); |
94 typedef CodeStubAssembler::Variable Variable; | 71 typedef CodeStubAssembler::Variable Variable; |
95 typedef CodeStubAssembler::Label Label; | 72 typedef CodeStubAssembler::Label Label; |
96 typedef compiler::Node Node; | 73 typedef compiler::Node Node; |
97 | 74 |
98 Node* const executor = a.Parameter(1); | 75 Node* const executor = a.Parameter(1); |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 { | 256 { |
280 Node* const message_id = a->SmiConstant(msg_template); | 257 Node* const message_id = a->SmiConstant(msg_template); |
281 a->CallRuntime(Runtime::kThrowTypeError, context, message_id); | 258 a->CallRuntime(Runtime::kThrowTypeError, context, message_id); |
282 var_value_map.Bind(a->UndefinedConstant()); | 259 var_value_map.Bind(a->UndefinedConstant()); |
283 a->Goto(&out); // Never reached. | 260 a->Goto(&out); // Never reached. |
284 } | 261 } |
285 | 262 |
286 a->Bind(&out); | 263 a->Bind(&out); |
287 return var_value_map.value(); | 264 return var_value_map.value(); |
288 } | 265 } |
| 266 |
289 } // namespace | 267 } // namespace |
290 | 268 |
291 void Builtins::Generate_IsPromise(compiler::CodeAssemblerState* state) { | 269 void Builtins::Generate_IsPromise(compiler::CodeAssemblerState* state) { |
292 CodeStubAssembler a(state); | 270 CodeStubAssembler a(state); |
293 typedef compiler::Node Node; | 271 typedef compiler::Node Node; |
294 typedef CodeStubAssembler::Label Label; | 272 typedef CodeStubAssembler::Label Label; |
295 | 273 |
296 Node* const maybe_promise = a.Parameter(1); | 274 Node* const maybe_promise = a.Parameter(1); |
297 Label if_notpromise(&a, Label::kDeferred); | 275 Label if_notpromise(&a, Label::kDeferred); |
298 | 276 |
299 a.GotoIf(a.TaggedIsSmi(maybe_promise), &if_notpromise); | 277 a.GotoIf(a.TaggedIsSmi(maybe_promise), &if_notpromise); |
300 | 278 |
301 Node* const result = a.SelectBooleanConstant( | 279 Node* const result = a.SelectBooleanConstant( |
302 a.HasInstanceType(maybe_promise, JS_PROMISE_TYPE)); | 280 a.HasInstanceType(maybe_promise, JS_PROMISE_TYPE)); |
303 a.Return(result); | 281 a.Return(result); |
304 | 282 |
305 a.Bind(&if_notpromise); | 283 a.Bind(&if_notpromise); |
306 a.Return(a.FalseConstant()); | 284 a.Return(a.FalseConstant()); |
307 } | 285 } |
308 | 286 |
309 namespace { | 287 namespace { |
| 288 |
| 289 compiler::Node* PromiseHasHandler(CodeStubAssembler* a, |
| 290 compiler::Node* promise) { |
| 291 typedef compiler::Node Node; |
| 292 |
| 293 Node* const flags = a->LoadObjectField(promise, JSPromise::kFlagsOffset); |
| 294 return a->IsSetWord(a->SmiUntag(flags), 1 << JSPromise::kHasHandlerBit); |
| 295 } |
| 296 |
| 297 void PromiseSetHasHandler(CodeStubAssembler* a, compiler::Node* promise) { |
| 298 typedef compiler::Node Node; |
| 299 |
| 300 Node* const flags = a->LoadObjectField(promise, JSPromise::kFlagsOffset); |
| 301 Node* const new_flags = |
| 302 a->WordOr(flags, a->IntPtrConstant(1 << JSPromise::kHasHandlerBit)); |
| 303 a->StoreObjectField(promise, JSPromise::kFlagsOffset, a->SmiTag(new_flags)); |
| 304 } |
| 305 |
310 compiler::Node* SpeciesConstructor(CodeStubAssembler* a, Isolate* isolate, | 306 compiler::Node* SpeciesConstructor(CodeStubAssembler* a, Isolate* isolate, |
311 compiler::Node* context, | 307 compiler::Node* context, |
312 compiler::Node* object, | 308 compiler::Node* object, |
313 compiler::Node* default_constructor) { | 309 compiler::Node* default_constructor) { |
314 typedef compiler::Node Node; | 310 typedef compiler::Node Node; |
315 typedef CodeStubAssembler::Label Label; | 311 typedef CodeStubAssembler::Label Label; |
316 typedef CodeStubAssembler::Variable Variable; | 312 typedef CodeStubAssembler::Variable Variable; |
317 | 313 |
318 Variable var_result(a, MachineRepresentation::kTagged); | 314 Variable var_result(a, MachineRepresentation::kTagged); |
319 var_result.Bind(default_constructor); | 315 var_result.Bind(default_constructor); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 | 393 |
398 compiler::Node* InternalPerformPromiseThen(CodeStubAssembler* a, | 394 compiler::Node* InternalPerformPromiseThen(CodeStubAssembler* a, |
399 compiler::Node* context, | 395 compiler::Node* context, |
400 compiler::Node* promise, | 396 compiler::Node* promise, |
401 compiler::Node* on_resolve, | 397 compiler::Node* on_resolve, |
402 compiler::Node* on_reject, | 398 compiler::Node* on_reject, |
403 compiler::Node* deferred) { | 399 compiler::Node* deferred) { |
404 typedef CodeStubAssembler::Variable Variable; | 400 typedef CodeStubAssembler::Variable Variable; |
405 typedef CodeStubAssembler::Label Label; | 401 typedef CodeStubAssembler::Label Label; |
406 typedef compiler::Node Node; | 402 typedef compiler::Node Node; |
407 | |
408 Isolate* isolate = a->isolate(); | 403 Isolate* isolate = a->isolate(); |
409 Node* const native_context = a->LoadNativeContext(context); | 404 Node* const native_context = a->LoadNativeContext(context); |
410 | 405 |
411 Variable var_on_resolve(a, MachineRepresentation::kTagged), | 406 Variable var_on_resolve(a, MachineRepresentation::kTagged), |
412 var_on_reject(a, MachineRepresentation::kTagged); | 407 var_on_reject(a, MachineRepresentation::kTagged); |
413 | 408 |
414 var_on_resolve.Bind(on_resolve); | 409 var_on_resolve.Bind(on_resolve); |
415 var_on_reject.Bind(on_reject); | 410 var_on_reject.Bind(on_reject); |
416 | 411 |
417 Label out(a), if_onresolvenotcallable(a), onrejectcheck(a), | 412 Label out(a), if_onresolvenotcallable(a), onrejectcheck(a), |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 &reject); | 524 &reject); |
530 | 525 |
531 // TODO(gsathya): Move this to TF. | 526 // TODO(gsathya): Move this to TF. |
532 a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, result, | 527 a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, result, |
533 var_on_resolve.value(), deferred, | 528 var_on_resolve.value(), deferred, |
534 a->SmiConstant(kPromiseFulfilled)); | 529 a->SmiConstant(kPromiseFulfilled)); |
535 a->Goto(&out); | 530 a->Goto(&out); |
536 | 531 |
537 a->Bind(&reject); | 532 a->Bind(&reject); |
538 { | 533 { |
539 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | 534 Node* const has_handler = PromiseHasHandler(a, promise); |
540 Node* const key = | |
541 a->HeapConstant(isolate->factory()->promise_has_handler_symbol()); | |
542 Node* const has_handler = | |
543 a->CallStub(getproperty_callable, context, promise, key); | |
544 | |
545 Label enqueue(a); | 535 Label enqueue(a); |
546 | 536 |
547 // TODO(gsathya): Fold these runtime calls and move to TF. | 537 // TODO(gsathya): Fold these runtime calls and move to TF. |
548 a->GotoIf(a->WordEqual(has_handler, a->TrueConstant()), &enqueue); | 538 a->GotoIf(has_handler, &enqueue); |
549 a->CallRuntime(Runtime::kPromiseRevokeReject, context, promise); | 539 a->CallRuntime(Runtime::kPromiseRevokeReject, context, promise); |
550 a->Goto(&enqueue); | 540 a->Goto(&enqueue); |
551 | 541 |
552 a->Bind(&enqueue); | 542 a->Bind(&enqueue); |
553 { | 543 { |
554 a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, result, | 544 a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, result, |
555 var_on_reject.value(), deferred, | 545 var_on_reject.value(), deferred, |
556 a->SmiConstant(kPromiseRejected)); | 546 a->SmiConstant(kPromiseRejected)); |
557 | 547 |
558 a->Goto(&out); | 548 a->Goto(&out); |
559 } | 549 } |
560 } | 550 } |
561 } | 551 } |
562 } | 552 } |
563 | 553 |
564 a->Bind(&out); | 554 a->Bind(&out); |
565 // TODO(gsathya): Protect with debug check. | 555 PromiseSetHasHandler(a, promise); |
566 a->CallRuntime( | |
567 Runtime::kSetProperty, context, promise, | |
568 a->HeapConstant(isolate->factory()->promise_has_handler_symbol()), | |
569 a->TrueConstant(), a->SmiConstant(STRICT)); | |
570 | 556 |
571 // TODO(gsathya): This call will be removed once we don't have to | 557 // TODO(gsathya): This call will be removed once we don't have to |
572 // deal with deferred objects. | 558 // deal with deferred objects. |
573 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | 559 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
574 Node* const key = | 560 Node* const key = |
575 a->HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); | 561 a->HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); |
576 Node* const result = | 562 Node* const result = |
577 a->CallStub(getproperty_callable, context, deferred, key); | 563 a->CallStub(getproperty_callable, context, deferred, key); |
578 | 564 |
579 return result; | 565 return result; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
660 } | 646 } |
661 | 647 |
662 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, | 648 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, |
663 // resultCapability). | 649 // resultCapability). |
664 a.Bind(&perform_promise_then); | 650 a.Bind(&perform_promise_then); |
665 Node* const result = InternalPerformPromiseThen( | 651 Node* const result = InternalPerformPromiseThen( |
666 &a, context, promise, on_resolve, on_reject, var_deferred.value()); | 652 &a, context, promise, on_resolve, on_reject, var_deferred.value()); |
667 a.Return(result); | 653 a.Return(result); |
668 } | 654 } |
669 | 655 |
| 656 namespace { |
| 657 |
| 658 // Promise fast path implementations rely on unmodified JSPromise instances. |
| 659 // We use a fairly coarse granularity for this and simply check whether both |
| 660 // the promise itself is unmodified (i.e. its map has not changed) and its |
| 661 // prototype is unmodified. |
| 662 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp |
| 663 void BranchIfFastPath(CodeStubAssembler* a, compiler::Node* context, |
| 664 compiler::Node* promise, |
| 665 CodeStubAssembler::Label* if_isunmodified, |
| 666 CodeStubAssembler::Label* if_ismodified) { |
| 667 typedef compiler::Node Node; |
| 668 |
| 669 // TODO(gsathya): Assert if promise is receiver |
| 670 Node* const map = a->LoadMap(promise); |
| 671 Node* const native_context = a->LoadNativeContext(context); |
| 672 Node* const promise_fun = |
| 673 a->LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); |
| 674 Node* const initial_map = |
| 675 a->LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); |
| 676 Node* const has_initialmap = a->WordEqual(map, initial_map); |
| 677 |
| 678 a->GotoUnless(has_initialmap, if_ismodified); |
| 679 |
| 680 Node* const initial_proto_initial_map = a->LoadContextElement( |
| 681 native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX); |
| 682 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map)); |
| 683 Node* const proto_has_initialmap = |
| 684 a->WordEqual(proto_map, initial_proto_initial_map); |
| 685 |
| 686 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified); |
| 687 } |
| 688 |
| 689 void InternalResolvePromise(CodeStubAssembler* a, compiler::Node* context, |
| 690 compiler::Node* promise, compiler::Node* result, |
| 691 CodeStubAssembler::Label* out) { |
| 692 typedef CodeStubAssembler::Variable Variable; |
| 693 typedef CodeStubAssembler::Label Label; |
| 694 typedef compiler::Node Node; |
| 695 |
| 696 Isolate* isolate = a->isolate(); |
| 697 |
| 698 Variable var_reason(a, MachineRepresentation::kTagged), |
| 699 var_then(a, MachineRepresentation::kTagged); |
| 700 |
| 701 Label do_enqueue(a), fulfill(a), if_cycle(a, Label::kDeferred), |
| 702 if_rejectpromise(a, Label::kDeferred); |
| 703 |
| 704 // 6. If SameValue(resolution, promise) is true, then |
| 705 a->GotoIf(a->SameValue(promise, result, context), &if_cycle); |
| 706 |
| 707 // 7. If Type(resolution) is not Object, then |
| 708 a->GotoIf(a->TaggedIsSmi(result), &fulfill); |
| 709 a->GotoUnless(a->IsJSReceiver(result), &fulfill); |
| 710 |
| 711 Label if_nativepromise(a), if_notnativepromise(a, Label::kDeferred); |
| 712 BranchIfFastPath(a, context, result, &if_nativepromise, &if_notnativepromise); |
| 713 |
| 714 // Resolution is a native promise and if it's already resolved or |
| 715 // rejected, shortcircuit the resolution procedure by directly |
| 716 // reusing the value from the promise. |
| 717 a->Bind(&if_nativepromise); |
| 718 { |
| 719 Node* const thenable_status = |
| 720 a->LoadObjectField(result, JSPromise::kStatusOffset); |
| 721 Node* const thenable_value = |
| 722 a->LoadObjectField(result, JSPromise::kResultOffset); |
| 723 |
| 724 Label if_isnotpending(a); |
| 725 a->GotoUnless(a->SmiEqual(a->SmiConstant(kPromisePending), thenable_status), |
| 726 &if_isnotpending); |
| 727 |
| 728 // TODO(gsathya): Use a marker here instead of the actual then |
| 729 // callback, and check for the marker in PromiseResolveThenableJob |
| 730 // and perform PromiseThen. |
| 731 Node* const native_context = a->LoadNativeContext(context); |
| 732 Node* const then = |
| 733 a->LoadContextElement(native_context, Context::PROMISE_THEN_INDEX); |
| 734 var_then.Bind(then); |
| 735 a->Goto(&do_enqueue); |
| 736 |
| 737 a->Bind(&if_isnotpending); |
| 738 { |
| 739 Label if_fulfilled(a), if_rejected(a); |
| 740 a->Branch(a->SmiEqual(a->SmiConstant(kPromiseFulfilled), thenable_status), |
| 741 &if_fulfilled, &if_rejected); |
| 742 |
| 743 a->Bind(&if_fulfilled); |
| 744 { |
| 745 a->CallRuntime(Runtime::kPromiseFulfill, context, promise, |
| 746 a->SmiConstant(kPromiseFulfilled), thenable_value); |
| 747 PromiseSetHasHandler(a, promise); |
| 748 a->Goto(out); |
| 749 } |
| 750 |
| 751 a->Bind(&if_rejected); |
| 752 { |
| 753 Label reject(a); |
| 754 Node* const has_handler = PromiseHasHandler(a, result); |
| 755 |
| 756 // Promise has already been rejected, but had no handler. |
| 757 // Revoke previously triggered reject event. |
| 758 a->GotoIf(has_handler, &reject); |
| 759 a->CallRuntime(Runtime::kPromiseRevokeReject, context, result); |
| 760 a->Goto(&reject); |
| 761 |
| 762 a->Bind(&reject); |
| 763 // Don't cause a debug event as this case is forwarding a rejection |
| 764 a->CallRuntime(Runtime::kPromiseReject, context, promise, |
| 765 thenable_value, a->FalseConstant()); |
| 766 PromiseSetHasHandler(a, result); |
| 767 a->Goto(out); |
| 768 } |
| 769 } |
| 770 } |
| 771 |
| 772 a->Bind(&if_notnativepromise); |
| 773 { |
| 774 // 8. Let then be Get(resolution, "then"). |
| 775 Node* const then_str = a->HeapConstant(isolate->factory()->then_string()); |
| 776 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); |
| 777 Node* const then = |
| 778 a->CallStub(getproperty_callable, context, result, then_str); |
| 779 |
| 780 // 9. If then is an abrupt completion, then |
| 781 a->GotoIfException(then, &if_rejectpromise, &var_reason); |
| 782 |
| 783 // 11. If IsCallable(thenAction) is false, then |
| 784 a->GotoIf(a->TaggedIsSmi(then), &fulfill); |
| 785 Node* const then_map = a->LoadMap(then); |
| 786 a->GotoUnless(a->IsCallableMap(then_map), &fulfill); |
| 787 var_then.Bind(then); |
| 788 a->Goto(&do_enqueue); |
| 789 } |
| 790 |
| 791 a->Bind(&do_enqueue); |
| 792 { |
| 793 Label enqueue(a); |
| 794 a->GotoUnless(a->IsDebugActive(), &enqueue); |
| 795 a->GotoIf(a->TaggedIsSmi(result), &enqueue); |
| 796 a->GotoUnless(a->HasInstanceType(result, JS_PROMISE_TYPE), &enqueue); |
| 797 // Mark the dependency of the new promise on the resolution |
| 798 Node* const key = |
| 799 a->HeapConstant(isolate->factory()->promise_handled_by_symbol()); |
| 800 a->CallRuntime(Runtime::kSetProperty, context, result, key, promise, |
| 801 a->SmiConstant(STRICT)); |
| 802 a->Goto(&enqueue); |
| 803 |
| 804 // 12. Perform EnqueueJob("PromiseJobs", |
| 805 // PromiseResolveThenableJob, « promise, resolution, thenAction |
| 806 // »). |
| 807 a->Bind(&enqueue); |
| 808 a->CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, promise, |
| 809 result, var_then.value()); |
| 810 a->Goto(out); |
| 811 } |
| 812 // 7.b Return FulfillPromise(promise, resolution). |
| 813 a->Bind(&fulfill); |
| 814 { |
| 815 a->CallRuntime(Runtime::kPromiseFulfill, context, promise, |
| 816 a->SmiConstant(kPromiseFulfilled), result); |
| 817 a->Goto(out); |
| 818 } |
| 819 |
| 820 a->Bind(&if_cycle); |
| 821 { |
| 822 // 6.a Let selfResolutionError be a newly created TypeError object. |
| 823 Node* const message_id = a->SmiConstant(MessageTemplate::kPromiseCyclic); |
| 824 Node* const error = |
| 825 a->CallRuntime(Runtime::kNewTypeError, context, message_id, result); |
| 826 var_reason.Bind(error); |
| 827 |
| 828 // 6.b Return RejectPromise(promise, selfResolutionError). |
| 829 a->Goto(&if_rejectpromise); |
| 830 } |
| 831 |
| 832 // 9.a Return RejectPromise(promise, then.[[Value]]). |
| 833 a->Bind(&if_rejectpromise); |
| 834 { |
| 835 a->CallRuntime(Runtime::kPromiseReject, context, promise, |
| 836 var_reason.value(), a->TrueConstant()); |
| 837 a->Goto(out); |
| 838 } |
| 839 } |
| 840 |
| 841 } // namespace |
| 842 |
| 843 // ES#sec-promise-resolve-functions |
| 844 // Promise Resolve Functions |
| 845 void Builtins::Generate_PromiseResolveClosure( |
| 846 compiler::CodeAssemblerState* state) { |
| 847 CodeStubAssembler a(state); |
| 848 typedef compiler::Node Node; |
| 849 typedef CodeStubAssembler::Label Label; |
| 850 |
| 851 Node* const value = a.Parameter(1); |
| 852 Node* const context = a.Parameter(4); |
| 853 |
| 854 Label out(&a); |
| 855 |
| 856 // 3. Let alreadyResolved be F.[[AlreadyResolved]]. |
| 857 Node* const has_already_visited_slot = |
| 858 a.IntPtrConstant(PromiseUtils::kAlreadyVisitedSlot); |
| 859 |
| 860 Node* const has_already_visited = |
| 861 a.LoadFixedArrayElement(context, has_already_visited_slot); |
| 862 |
| 863 // 4. If alreadyResolved.[[Value]] is true, return undefined. |
| 864 a.GotoIf(a.SmiEqual(has_already_visited, a.SmiConstant(1)), &out); |
| 865 |
| 866 // 5.Set alreadyResolved.[[Value]] to true. |
| 867 a.StoreFixedArrayElement(context, has_already_visited_slot, a.SmiConstant(1)); |
| 868 |
| 869 // 2. Let promise be F.[[Promise]]. |
| 870 Node* const promise = a.LoadFixedArrayElement( |
| 871 context, a.IntPtrConstant(PromiseUtils::kPromiseSlot)); |
| 872 |
| 873 InternalResolvePromise(&a, context, promise, value, &out); |
| 874 |
| 875 a.Bind(&out); |
| 876 a.Return(a.UndefinedConstant()); |
| 877 } |
| 878 |
| 879 void Builtins::Generate_ResolvePromise(compiler::CodeAssemblerState* state) { |
| 880 CodeStubAssembler a(state); |
| 881 typedef compiler::Node Node; |
| 882 typedef CodeStubAssembler::Label Label; |
| 883 |
| 884 Node* const promise = a.Parameter(1); |
| 885 Node* const result = a.Parameter(2); |
| 886 Node* const context = a.Parameter(5); |
| 887 |
| 888 Label out(&a); |
| 889 InternalResolvePromise(&a, context, promise, result, &out); |
| 890 |
| 891 a.Bind(&out); |
| 892 a.Return(a.UndefinedConstant()); |
| 893 } |
| 894 |
670 } // namespace internal | 895 } // namespace internal |
671 } // namespace v8 | 896 } // namespace v8 |
OLD | NEW |