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