Chromium Code Reviews| 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::kHasHandlerOffset, 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 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 373 | 350 |
| 374 Node* elements = a->LoadObjectField(promise, offset); | 351 Node* elements = a->LoadObjectField(promise, offset); |
| 375 Node* length = a->LoadFixedArrayBaseLength(elements); | 352 Node* length = a->LoadFixedArrayBaseLength(elements); |
| 376 CodeStubAssembler::ParameterMode mode = a->OptimalParameterMode(); | 353 CodeStubAssembler::ParameterMode mode = a->OptimalParameterMode(); |
| 377 length = a->UntagParameter(length, mode); | 354 length = a->UntagParameter(length, mode); |
| 378 | 355 |
| 379 Node* delta = a->IntPtrOrSmiConstant(1, mode); | 356 Node* delta = a->IntPtrOrSmiConstant(1, mode); |
| 380 Node* new_capacity = a->IntPtrAdd(length, delta); | 357 Node* new_capacity = a->IntPtrAdd(length, delta); |
| 381 ElementsKind kind = FAST_ELEMENTS; | 358 ElementsKind kind = FAST_ELEMENTS; |
| 382 | 359 |
| 383 Node* new_elements = a->AllocateFixedArray(kind, new_capacity, mode); | 360 Node* new_elements = a->AllocateFixedArray(kind, new_capacity, mode); |
|
jgruber
2016/12/07 12:59:38
Do you think we need to handle LO space allocation
gsathya
2016/12/08 05:18:14
This is handled in https://codereview.chromium.org
| |
| 384 | 361 |
| 385 a->CopyFixedArrayElements(kind, elements, new_elements, length, | 362 a->CopyFixedArrayElements(kind, elements, new_elements, length, |
| 386 UPDATE_WRITE_BARRIER, mode); | 363 UPDATE_WRITE_BARRIER, mode); |
| 387 a->StoreFixedArrayElement(new_elements, length, value, UPDATE_WRITE_BARRIER, | 364 a->StoreFixedArrayElement(new_elements, length, value, UPDATE_WRITE_BARRIER, |
| 388 0, mode); | 365 0, mode); |
| 389 | 366 |
| 390 a->StoreObjectField(promise, offset, new_elements); | 367 a->StoreObjectField(promise, offset, new_elements); |
| 391 } | 368 } |
| 392 | 369 |
| 393 compiler::Node* InternalPerformPromiseThen(CodeStubAssembler* a, | 370 compiler::Node* InternalPerformPromiseThen(CodeStubAssembler* a, |
| 394 compiler::Node* context, | 371 compiler::Node* context, |
| 395 compiler::Node* promise, | 372 compiler::Node* promise, |
| 396 compiler::Node* on_resolve, | 373 compiler::Node* on_resolve, |
| 397 compiler::Node* on_reject, | 374 compiler::Node* on_reject, |
| 398 compiler::Node* deferred) { | 375 compiler::Node* deferred) { |
| 399 typedef CodeStubAssembler::Variable Variable; | 376 typedef CodeStubAssembler::Variable Variable; |
| 400 typedef CodeStubAssembler::Label Label; | 377 typedef CodeStubAssembler::Label Label; |
| 401 typedef compiler::Node Node; | 378 typedef compiler::Node Node; |
| 402 | |
| 403 Isolate* isolate = a->isolate(); | 379 Isolate* isolate = a->isolate(); |
| 404 Node* const native_context = a->LoadNativeContext(context); | 380 Node* const native_context = a->LoadNativeContext(context); |
| 405 | 381 |
| 406 Variable var_on_resolve(a, MachineRepresentation::kTagged), | 382 Variable var_on_resolve(a, MachineRepresentation::kTagged), |
| 407 var_on_reject(a, MachineRepresentation::kTagged); | 383 var_on_reject(a, MachineRepresentation::kTagged); |
| 408 | 384 |
| 409 var_on_resolve.Bind(on_resolve); | 385 var_on_resolve.Bind(on_resolve); |
| 410 var_on_reject.Bind(on_reject); | 386 var_on_reject.Bind(on_reject); |
| 411 | 387 |
| 412 Label out(a), if_onresolvenotcallable(a), onrejectcheck(a), | 388 Label out(a), if_onresolvenotcallable(a), onrejectcheck(a), |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 525 &reject); | 501 &reject); |
| 526 | 502 |
| 527 // TODO(gsathya): Move this to TF. | 503 // TODO(gsathya): Move this to TF. |
| 528 a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, result, | 504 a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, result, |
| 529 var_on_resolve.value(), deferred, | 505 var_on_resolve.value(), deferred, |
| 530 a->SmiConstant(kPromiseFulfilled)); | 506 a->SmiConstant(kPromiseFulfilled)); |
| 531 a->Goto(&out); | 507 a->Goto(&out); |
| 532 | 508 |
| 533 a->Bind(&reject); | 509 a->Bind(&reject); |
| 534 { | 510 { |
| 535 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | |
| 536 Node* const key = | |
| 537 a->HeapConstant(isolate->factory()->promise_has_handler_symbol()); | |
| 538 Node* const has_handler = | 511 Node* const has_handler = |
| 539 a->CallStub(getproperty_callable, context, promise, key); | 512 a->LoadObjectField(promise, JSPromise::kHasHandlerOffset); |
| 540 | |
| 541 Label enqueue(a); | 513 Label enqueue(a); |
| 542 | 514 |
| 543 // TODO(gsathya): Fold these runtime calls and move to TF. | 515 // TODO(gsathya): Fold these runtime calls and move to TF. |
| 544 a->GotoIf(a->WordEqual(has_handler, a->TrueConstant()), &enqueue); | 516 a->GotoIf(a->SmiEqual(has_handler, a->SmiConstant(1)), &enqueue); |
| 545 a->CallRuntime(Runtime::kPromiseRevokeReject, context, promise); | 517 a->CallRuntime(Runtime::kPromiseRevokeReject, context, promise); |
| 546 a->Goto(&enqueue); | 518 a->Goto(&enqueue); |
| 547 | 519 |
| 548 a->Bind(&enqueue); | 520 a->Bind(&enqueue); |
| 549 { | 521 { |
| 550 a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, result, | 522 a->CallRuntime(Runtime::kEnqueuePromiseReactionJob, context, result, |
| 551 var_on_reject.value(), deferred, | 523 var_on_reject.value(), deferred, |
| 552 a->SmiConstant(kPromiseRejected)); | 524 a->SmiConstant(kPromiseRejected)); |
| 553 | 525 |
| 554 a->Goto(&out); | 526 a->Goto(&out); |
| 555 } | 527 } |
| 556 } | 528 } |
| 557 } | 529 } |
| 558 } | 530 } |
| 559 | 531 |
| 560 a->Bind(&out); | 532 a->Bind(&out); |
| 561 // TODO(gsathya): Protect with debug check. | 533 a->StoreObjectField(promise, JSPromise::kHasHandlerOffset, a->SmiConstant(1)); |
| 562 a->CallRuntime( | |
| 563 Runtime::kSetProperty, context, promise, | |
| 564 a->HeapConstant(isolate->factory()->promise_has_handler_symbol()), | |
| 565 a->TrueConstant(), a->SmiConstant(STRICT)); | |
| 566 | 534 |
| 567 // TODO(gsathya): This call will be removed once we don't have to | 535 // TODO(gsathya): This call will be removed once we don't have to |
| 568 // deal with deferred objects. | 536 // deal with deferred objects. |
| 569 Callable getproperty_callable = CodeFactory::GetProperty(isolate); | 537 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| 570 Node* const key = | 538 Node* const key = |
| 571 a->HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); | 539 a->HeapConstant(isolate->factory()->NewStringFromAsciiChecked("promise")); |
| 572 Node* const result = | 540 Node* const result = |
| 573 a->CallStub(getproperty_callable, context, deferred, key); | 541 a->CallStub(getproperty_callable, context, deferred, key); |
| 574 | 542 |
| 575 return result; | 543 return result; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 656 } | 624 } |
| 657 | 625 |
| 658 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, | 626 // 5. Return PerformPromiseThen(promise, onFulfilled, onRejected, |
| 659 // resultCapability). | 627 // resultCapability). |
| 660 a.Bind(&perform_promise_then); | 628 a.Bind(&perform_promise_then); |
| 661 Node* const result = InternalPerformPromiseThen( | 629 Node* const result = InternalPerformPromiseThen( |
| 662 &a, context, promise, on_resolve, on_reject, var_deferred.value()); | 630 &a, context, promise, on_resolve, on_reject, var_deferred.value()); |
| 663 a.Return(result); | 631 a.Return(result); |
| 664 } | 632 } |
| 665 | 633 |
| 634 namespace { | |
| 635 // Promise fast path implementations rely on unmodified JSPromise instances. | |
| 636 // We use a fairly coarse granularity for this and simply check whether both | |
| 637 // the promise itself is unmodified (i.e. its map has not changed) and its | |
| 638 // prototype is unmodified. | |
| 639 // TODO(gsathya): Refactor this out to prevent code dupe with builtins-regexp | |
| 640 void BranchIfFastPath(CodeStubAssembler* a, compiler::Node* context, | |
| 641 compiler::Node* promise, | |
| 642 CodeStubAssembler::Label* if_isunmodified, | |
| 643 CodeStubAssembler::Label* if_ismodified) { | |
| 644 typedef compiler::Node Node; | |
| 645 | |
| 646 // TODO(gsathya): Assert if promise is receiver | |
| 647 Node* const map = a->LoadMap(promise); | |
| 648 Node* const native_context = a->LoadNativeContext(context); | |
| 649 Node* const promise_fun = | |
| 650 a->LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX); | |
| 651 Node* const initial_map = | |
| 652 a->LoadObjectField(promise_fun, JSFunction::kPrototypeOrInitialMapOffset); | |
| 653 Node* const has_initialmap = a->WordEqual(map, initial_map); | |
| 654 | |
| 655 a->GotoUnless(has_initialmap, if_ismodified); | |
| 656 | |
| 657 Node* const initial_proto_initial_map = a->LoadContextElement( | |
| 658 native_context, Context::PROMISE_PROTOTYPE_MAP_INDEX); | |
| 659 Node* const proto_map = a->LoadMap(a->LoadMapPrototype(map)); | |
| 660 Node* const proto_has_initialmap = | |
| 661 a->WordEqual(proto_map, initial_proto_initial_map); | |
| 662 | |
| 663 a->Branch(proto_has_initialmap, if_isunmodified, if_ismodified); | |
| 664 } | |
| 665 } // namespace | |
| 666 | |
| 667 void InternalResolvePromise(CodeStubAssembler* a, compiler::Node* context, | |
| 668 compiler::Node* promise, compiler::Node* result, | |
| 669 CodeStubAssembler::Label* out) { | |
|
jgruber
2016/12/07 12:59:38
I don't think you gain much through the style
IRP
gsathya
2016/12/08 05:18:14
I use this here in the follow on patch --
https://
| |
| 670 typedef CodeStubAssembler::Variable Variable; | |
| 671 typedef CodeStubAssembler::Label Label; | |
| 672 typedef compiler::Node Node; | |
| 673 | |
| 674 Isolate* isolate = a->isolate(); | |
| 675 | |
| 676 Variable var_reason(a, MachineRepresentation::kTagged), | |
| 677 var_then(a, MachineRepresentation::kTagged); | |
| 678 | |
| 679 Label do_enqueue(a), fulfill(a), if_cycle(a, Label::kDeferred), | |
| 680 if_rejectpromise(a, Label::kDeferred); | |
| 681 | |
| 682 // 6. If SameValue(resolution, promise) is true, then | |
| 683 a->GotoIf(a->SameValue(promise, result, context), &if_cycle); | |
| 684 | |
| 685 // 7. If Type(resolution) is not Object, then | |
| 686 a->GotoIf(a->TaggedIsSmi(result), &fulfill); | |
| 687 a->GotoUnless(a->IsJSReceiver(result), &fulfill); | |
| 688 | |
| 689 Label if_nativepromise(a), if_notnativepromise(a, Label::kDeferred); | |
| 690 BranchIfFastPath(a, context, result, &if_nativepromise, &if_notnativepromise); | |
| 691 | |
| 692 // Resolution is a native promise and if it's already resolved or | |
| 693 // rejected, shortcircuit the resolution procedure by directly | |
| 694 // reusing the value from the promise. | |
| 695 a->Bind(&if_nativepromise); | |
| 696 { | |
| 697 Node* const thenable_status = | |
| 698 a->LoadObjectField(result, JSPromise::kStatusOffset); | |
| 699 Node* const thenable_value = | |
| 700 a->LoadObjectField(result, JSPromise::kResultOffset); | |
| 701 | |
| 702 Label if_isnotpending(a); | |
| 703 a->GotoUnless(a->SmiEqual(a->SmiConstant(kPromisePending), thenable_status), | |
| 704 &if_isnotpending); | |
| 705 | |
| 706 // TODO(gsathya): Use a marker here instead of the actual then | |
| 707 // callback, and check for the marker in PromiseResolveThenableJob | |
| 708 // and perform PromiseThen. | |
| 709 Node* const native_context = a->LoadNativeContext(context); | |
| 710 Node* const then = | |
| 711 a->LoadContextElement(native_context, Context::PROMISE_THEN_INDEX); | |
| 712 var_then.Bind(then); | |
| 713 a->Goto(&do_enqueue); | |
| 714 | |
| 715 a->Bind(&if_isnotpending); | |
| 716 { | |
| 717 Label if_fulfilled(a), if_rejected(a); | |
| 718 a->Branch(a->SmiEqual(a->SmiConstant(kPromiseFulfilled), thenable_status), | |
| 719 &if_fulfilled, &if_rejected); | |
| 720 | |
| 721 a->Bind(&if_fulfilled); | |
| 722 { | |
| 723 a->CallRuntime(Runtime::kPromiseFulfill, context, promise, | |
| 724 a->SmiConstant(kPromiseFulfilled), thenable_value); | |
| 725 a->StoreObjectField(promise, JSPromise::kHasHandlerOffset, | |
| 726 a->SmiConstant(1)); | |
| 727 a->Goto(out); | |
| 728 } | |
| 729 | |
| 730 a->Bind(&if_rejected); | |
| 731 { | |
| 732 Label reject(a); | |
| 733 Node* const has_handler = | |
| 734 a->LoadObjectField(promise, JSPromise::kHasHandlerOffset); | |
| 735 | |
| 736 // Promise has already been rejected, but had no handler. | |
| 737 // Revoke previously triggered reject event. | |
| 738 a->GotoIf(a->SmiEqual(has_handler, a->SmiConstant(1)), &reject); | |
| 739 a->CallRuntime(Runtime::kPromiseRevokeReject, context, result); | |
| 740 a->Goto(&reject); | |
| 741 | |
| 742 a->Bind(&reject); | |
| 743 // Don't cause a debug event as this case is forwarding a rejection | |
| 744 a->CallRuntime(Runtime::kPromiseReject, context, promise, | |
| 745 thenable_value, a->FalseConstant()); | |
| 746 a->StoreObjectField(result, JSPromise::kHasHandlerOffset, | |
| 747 a->SmiConstant(1)); | |
| 748 a->Goto(out); | |
| 749 } | |
| 750 } | |
| 751 } | |
| 752 | |
| 753 a->Bind(&if_notnativepromise); | |
| 754 { | |
| 755 // 8. Let then be Get(resolution, "then"). | |
| 756 Node* const then_str = a->HeapConstant(isolate->factory()->then_string()); | |
| 757 Callable getproperty_callable = CodeFactory::GetProperty(a->isolate()); | |
| 758 Node* const then = | |
| 759 a->CallStub(getproperty_callable, context, result, then_str); | |
| 760 | |
| 761 // 9. If then is an abrupt completion, then | |
| 762 a->GotoIfException(then, &if_rejectpromise, &var_reason); | |
| 763 | |
| 764 // 11. If IsCallable(thenAction) is false, then | |
| 765 a->GotoIf(a->TaggedIsSmi(then), &fulfill); | |
| 766 Node* const then_map = a->LoadMap(then); | |
| 767 a->GotoUnless(a->IsCallableMap(then_map), &fulfill); | |
| 768 var_then.Bind(then); | |
| 769 a->Goto(&do_enqueue); | |
| 770 } | |
| 771 | |
| 772 a->Bind(&do_enqueue); | |
| 773 { | |
| 774 Label enqueue(a); | |
| 775 a->GotoUnless(a->IsDebugActive(), &enqueue); | |
| 776 a->GotoIf(a->TaggedIsSmi(result), &enqueue); | |
| 777 Node* const is_promise = | |
| 778 a->SelectBooleanConstant(a->HasInstanceType(result, JS_PROMISE_TYPE)); | |
| 779 a->GotoUnless(is_promise, &enqueue); | |
|
jgruber
2016/12/07 12:59:38
This will always evaluate to true (even if you pas
gsathya
2016/12/08 05:18:14
Done.
| |
| 780 Node* const key = | |
| 781 a->HeapConstant(isolate->factory()->promise_handled_by_symbol()); | |
| 782 a->CallRuntime(Runtime::kSetProperty, context, result, key, promise, | |
| 783 a->SmiConstant(STRICT)); | |
| 784 a->Goto(&enqueue); | |
| 785 | |
| 786 // 12. Perform EnqueueJob("PromiseJobs", | |
| 787 // PromiseResolveThenableJob, « promise, resolution, thenAction | |
| 788 // »). | |
| 789 a->Bind(&enqueue); | |
| 790 a->CallRuntime(Runtime::kEnqueuePromiseResolveThenableJob, context, promise, | |
| 791 result, var_then.value()); | |
| 792 a->Goto(out); | |
| 793 } | |
| 794 // 7.b Return FulfillPromise(promise, resolution). | |
| 795 a->Bind(&fulfill); | |
| 796 { | |
| 797 a->CallRuntime(Runtime::kPromiseFulfill, context, promise, | |
| 798 a->SmiConstant(kPromiseFulfilled), result); | |
| 799 a->Goto(out); | |
| 800 } | |
| 801 | |
| 802 a->Bind(&if_cycle); | |
| 803 { | |
| 804 // 6.a Let selfResolutionError be a newly created TypeError object. | |
| 805 Node* const message_id = a->SmiConstant(MessageTemplate::kPromiseCyclic); | |
| 806 Node* const error = | |
| 807 a->CallRuntime(Runtime::kNewTypeError, context, message_id, result); | |
| 808 var_reason.Bind(error); | |
| 809 | |
| 810 // 6.b Return RejectPromise(promise, selfResolutionError). | |
| 811 a->Goto(&if_rejectpromise); | |
| 812 } | |
| 813 | |
| 814 // 9.a Return RejectPromise(promise, then.[[Value]]). | |
| 815 a->Bind(&if_rejectpromise); | |
| 816 { | |
| 817 a->CallRuntime(Runtime::kPromiseReject, context, promise, | |
| 818 var_reason.value(), a->TrueConstant()); | |
| 819 a->Goto(out); | |
| 820 } | |
| 821 } | |
| 822 | |
| 823 // ES#sec-promise-resolve-functions | |
| 824 // Promise Resolve Functions | |
| 825 void Builtins::Generate_PromiseResolveClosure( | |
| 826 compiler::CodeAssemblerState* state) { | |
| 827 CodeStubAssembler a(state); | |
| 828 typedef compiler::Node Node; | |
| 829 typedef CodeStubAssembler::Label Label; | |
| 830 | |
| 831 Node* const value = a.Parameter(1); | |
| 832 Node* const context = a.Parameter(4); | |
| 833 | |
| 834 Label out(&a); | |
| 835 | |
| 836 // 3. Let alreadyResolved be F.[[AlreadyResolved]]. | |
| 837 Node* const has_already_visited_slot = | |
| 838 a.IntPtrConstant(PromiseUtils::kAlreadyVisitedSlot); | |
| 839 | |
| 840 Node* const has_already_visited = | |
| 841 a.LoadFixedArrayElement(context, has_already_visited_slot); | |
| 842 | |
| 843 // 4. If alreadyResolved.[[Value]] is true, return undefined. | |
| 844 a.GotoIf(a.SmiEqual(has_already_visited, a.SmiConstant(1)), &out); | |
| 845 | |
| 846 // 5.Set alreadyResolved.[[Value]] to true. | |
| 847 a.StoreFixedArrayElement(context, has_already_visited_slot, a.SmiConstant(1)); | |
| 848 | |
| 849 // 2. Let promise be F.[[Promise]]. | |
| 850 Node* const promise = a.LoadFixedArrayElement( | |
| 851 context, a.IntPtrConstant(PromiseUtils::kPromiseSlot)); | |
| 852 | |
| 853 InternalResolvePromise(&a, context, promise, value, &out); | |
| 854 | |
| 855 a.Bind(&out); | |
| 856 a.Return(a.UndefinedConstant()); | |
| 857 } | |
| 858 | |
| 859 void Builtins::Generate_ResolvePromise(compiler::CodeAssemblerState* state) { | |
| 860 CodeStubAssembler a(state); | |
| 861 typedef compiler::Node Node; | |
| 862 typedef CodeStubAssembler::Label Label; | |
| 863 | |
| 864 Node* const promise = a.Parameter(1); | |
| 865 Node* const result = a.Parameter(2); | |
| 866 Node* const context = a.Parameter(5); | |
| 867 | |
| 868 Label out(&a); | |
| 869 InternalResolvePromise(&a, context, promise, result, &out); | |
| 870 | |
| 871 a.Bind(&out); | |
| 872 a.Return(a.UndefinedConstant()); | |
| 873 } | |
| 874 | |
| 666 } // namespace internal | 875 } // namespace internal |
| 667 } // namespace v8 | 876 } // namespace v8 |
| OLD | NEW |