Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(649)

Side by Side Diff: src/builtins/builtins-promise.cc

Issue 2695753002: [ESnext] Implement Promise.prototype.finally (Closed)
Patch Set: add comments Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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-constructor.h" 6 #include "src/builtins/builtins-constructor.h"
7 #include "src/builtins/builtins-utils.h" 7 #include "src/builtins/builtins-utils.h"
8 #include "src/builtins/builtins.h" 8 #include "src/builtins/builtins.h"
9 #include "src/code-factory.h" 9 #include "src/code-factory.h"
10 #include "src/code-stub-assembler.h" 10 #include "src/code-stub-assembler.h"
(...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 append_callbacks(this); 431 append_callbacks(this);
432 GotoIf(TaggedIsSmi(on_resolve), &if_onresolvenotcallable); 432 GotoIf(TaggedIsSmi(on_resolve), &if_onresolvenotcallable);
433 433
434 Isolate* isolate = this->isolate(); 434 Isolate* isolate = this->isolate();
435 Node* const on_resolve_map = LoadMap(on_resolve); 435 Node* const on_resolve_map = LoadMap(on_resolve);
436 Branch(IsCallableMap(on_resolve_map), &onrejectcheck, 436 Branch(IsCallableMap(on_resolve_map), &onrejectcheck,
437 &if_onresolvenotcallable); 437 &if_onresolvenotcallable);
438 438
439 Bind(&if_onresolvenotcallable); 439 Bind(&if_onresolvenotcallable);
440 { 440 {
441 Isolate* isolate = this->isolate();
442 Node* const default_resolve_handler_symbol = HeapConstant( 441 Node* const default_resolve_handler_symbol = HeapConstant(
443 isolate->factory()->promise_default_resolve_handler_symbol()); 442 isolate->factory()->promise_default_resolve_handler_symbol());
444 var_on_resolve.Bind(default_resolve_handler_symbol); 443 var_on_resolve.Bind(default_resolve_handler_symbol);
445 Goto(&onrejectcheck); 444 Goto(&onrejectcheck);
446 } 445 }
447 446
448 Bind(&onrejectcheck); 447 Bind(&onrejectcheck);
449 { 448 {
450 Label if_onrejectnotcallable(this); 449 Label if_onrejectnotcallable(this);
451 GotoIf(TaggedIsSmi(on_reject), &if_onrejectnotcallable); 450 GotoIf(TaggedIsSmi(on_reject), &if_onrejectnotcallable);
(...skipping 1105 matching lines...) Expand 10 before | Expand all | Expand 10 after
1557 TF_BUILTIN(InternalPromiseReject, PromiseBuiltinsAssembler) { 1556 TF_BUILTIN(InternalPromiseReject, PromiseBuiltinsAssembler) {
1558 Node* const promise = Parameter(1); 1557 Node* const promise = Parameter(1);
1559 Node* const reason = Parameter(2); 1558 Node* const reason = Parameter(2);
1560 Node* const debug_event = Parameter(3); 1559 Node* const debug_event = Parameter(3);
1561 Node* const context = Parameter(6); 1560 Node* const context = Parameter(6);
1562 1561
1563 InternalPromiseReject(context, promise, reason, debug_event); 1562 InternalPromiseReject(context, promise, reason, debug_event);
1564 Return(UndefinedConstant()); 1563 Return(UndefinedConstant());
1565 } 1564 }
1566 1565
1566 Node* PromiseBuiltinsAssembler::CreatePromiseFinallyContext(
1567 Node* on_finally, Node* native_context) {
1568 Node* const context =
1569 CreatePromiseContext(native_context, kOnFinallyContextLength);
1570 StoreContextElementNoWriteBarrier(context, kOnFinallySlot, on_finally);
1571 return context;
1572 }
1573
1574 std::pair<Node*, Node*> PromiseBuiltinsAssembler::CreatePromiseFinallyFunctions(
1575 Node* on_finally, Node* native_context) {
1576 Node* const promise_context =
1577 CreatePromiseFinallyContext(on_finally, native_context);
1578 Node* const map = LoadContextElement(
1579 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1580 Node* const then_finally_info = LoadContextElement(
1581 native_context, Context::PROMISE_THEN_FINALLY_SHARED_FUN);
1582 Node* const then_finally = AllocateFunctionWithMapAndContext(
1583 map, then_finally_info, promise_context);
1584 Node* const catch_finally_info = LoadContextElement(
1585 native_context, Context::PROMISE_CATCH_FINALLY_SHARED_FUN);
1586 Node* const catch_finally = AllocateFunctionWithMapAndContext(
1587 map, catch_finally_info, promise_context);
1588 return std::make_pair(then_finally, catch_finally);
1589 }
1590
1591 TF_BUILTIN(PromiseValueThunkFinally, PromiseBuiltinsAssembler) {
1592 Node* const context = Parameter(3);
1593
1594 Node* const value = LoadContextElement(context, kOnFinallySlot);
1595 Return(value);
1596 }
1597
1598 Node* PromiseBuiltinsAssembler::CreateValueThunkFunctionContext(
1599 Node* value, Node* native_context) {
1600 Node* const context =
1601 CreatePromiseContext(native_context, kOnFinallyContextLength);
1602 StoreContextElementNoWriteBarrier(context, kOnFinallySlot, value);
1603 return context;
1604 }
1605
1606 Node* PromiseBuiltinsAssembler::CreateValueThunkFunction(Node* value,
neis 2017/02/15 12:40:39 nit: s/Function//
gsathya 2017/02/16 15:05:29 Leaving as such to be consistent with CreatePromis
1607 Node* native_context) {
1608 Node* const value_thunk_context =
1609 CreateValueThunkFunctionContext(value, native_context);
1610 Node* const map = LoadContextElement(
1611 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1612 Node* const value_thunk_info = LoadContextElement(
1613 native_context, Context::PROMISE_VALUE_THUNK_FINALLY_SHARED_FUN);
1614 Node* const value_thunk = AllocateFunctionWithMapAndContext(
1615 map, value_thunk_info, value_thunk_context);
1616 return value_thunk;
1617 }
1618
1619 TF_BUILTIN(PromiseThenFinally, PromiseBuiltinsAssembler) {
1620 Node* const parent = Parameter(0);
neis 2017/02/15 12:40:39 This will typically be undefined.
gsathya 2017/02/16 15:05:29 Done.
1621 Node* const value = Parameter(1);
1622 Node* const context = Parameter(4);
neis 2017/02/15 12:40:39 Maybe use CSA_ASSERT_JS_ARGC_EQ here and elsewhere
gsathya 2017/02/16 15:05:30 Done.
1623
1624 Node* const on_finally = LoadContextElement(context, kOnFinallySlot);
1625
1626 // 2.a Let result be ? Call(onFinally, undefined).
1627 Callable call_callable = CodeFactory::Call(isolate());
1628 Node* result =
1629 CallJS(call_callable, context, on_finally, UndefinedConstant());
1630
1631 // 2.b Let promise be ! PromiseResolve( %Promise%, result).
1632 Node* const promise = AllocateAndInitJSPromise(context, parent);
1633 InternalResolvePromise(context, promise, result);
1634
1635 // 2.c Let valueThunk be equivalent to a function that returns value.
1636 Node* native_context = LoadNativeContext(context);
1637 Node* const value_thunk = CreateValueThunkFunction(value, native_context);
1638
1639 // 2.d Let promiseCapability be ! NewPromiseCapability( %Promise%).
1640 Node* const promise_capability = AllocateAndInitJSPromise(context, promise);
1641
1642 // 2.e Return PerformPromiseThen(promise, valueThunk, undefined,
1643 // promiseCapability).
1644 InternalPerformPromiseThen(context, promise, value_thunk, UndefinedConstant(),
1645 promise_capability, UndefinedConstant(),
1646 UndefinedConstant());
1647 Return(promise_capability);
1648 }
1649
1650 TF_BUILTIN(PromiseThrowerFinally, PromiseBuiltinsAssembler) {
1651 Node* const context = Parameter(3);
1652
1653 Node* const reason = LoadContextElement(context, kOnFinallySlot);
1654 CallRuntime(Runtime::kThrow, context, reason);
1655 Return(UndefinedConstant());
1656 }
1657
1658 Node* PromiseBuiltinsAssembler::CreateThrowerFunctionContext(
1659 Node* reason, Node* native_context) {
1660 Node* const context =
1661 CreatePromiseContext(native_context, kOnFinallyContextLength);
1662 StoreContextElementNoWriteBarrier(context, kOnFinallySlot, reason);
1663 return context;
1664 }
1665
1666 Node* PromiseBuiltinsAssembler::CreateThrowerFunction(Node* reason,
1667 Node* native_context) {
neis 2017/02/15 12:40:39 nit: s/Function//
gsathya 2017/02/16 15:05:29 Same as CreateValueThunkFunction
1668 Node* const thrower_context =
1669 CreateThrowerFunctionContext(reason, native_context);
1670 Node* const map = LoadContextElement(
1671 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
1672 Node* const thrower_info = LoadContextElement(
1673 native_context, Context::PROMISE_THROWER_FINALLY_SHARED_FUN);
1674 Node* const thrower =
1675 AllocateFunctionWithMapAndContext(map, thrower_info, thrower_context);
1676 return thrower;
1677 }
1678
1679 TF_BUILTIN(PromiseCatchFinally, PromiseBuiltinsAssembler) {
1680 Node* const parent = Parameter(0);
1681 Node* const value = Parameter(1);
neis 2017/02/15 12:40:39 nit: s/value/reason/
gsathya 2017/02/16 15:05:30 Done.
1682 Node* const context = Parameter(4);
1683
1684 Node* const on_finally = LoadContextElement(context, kOnFinallySlot);
1685
1686 // 2.a Let result be ? Call(onFinally, undefined).
1687 Callable call_callable = CodeFactory::Call(isolate());
1688 Node* result =
1689 CallJS(call_callable, context, on_finally, UndefinedConstant());
1690
1691 // 2.b Let promise be ! PromiseResolve( %Promise%, result).
1692 Node* const promise = AllocateAndInitJSPromise(context, parent);
1693 InternalResolvePromise(context, promise, result);
1694
1695 // 2.c Let thrower be equivalent to a function that throws reason.
1696 Node* native_context = LoadNativeContext(context);
1697 Node* const thrower = CreateThrowerFunction(value, native_context);
1698
1699 // 2.d Let promiseCapability be ! NewPromiseCapability( %Promise%).
1700 Node* const promise_capability = AllocateAndInitJSPromise(context, promise);
1701
1702 // 2.e Return PerformPromiseThen(promise, thrower, undefined,
1703 // promiseCapability).
1704 InternalPerformPromiseThen(context, promise, thrower, UndefinedConstant(),
1705 promise_capability, UndefinedConstant(),
1706 UndefinedConstant());
1707 Return(result);
neis 2017/02/15 12:40:39 Ouch! Return(promise_capability) This suggests a
gsathya 2017/02/16 15:05:29 Done.
1708 }
1709
1710 TF_BUILTIN(PromiseFinally, PromiseBuiltinsAssembler) {
1711 // 1. Let promise be the this value.
1712 Node* const promise = Parameter(0);
1713 Node* const on_finally = Parameter(1);
1714 Node* const context = Parameter(4);
1715
1716 // 2. If IsPromise(promise) is false, throw a TypeError exception.
1717 ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE,
1718 "Promise.prototype.finally");
1719
1720 Variable var_then_finally(this, MachineRepresentation::kTagged),
1721 var_catch_finally(this, MachineRepresentation::kTagged);
1722
1723 Label if_notcallable(this, Label::kDeferred), perform_finally(this);
1724
1725 GotoIf(TaggedIsSmi(on_finally), &if_notcallable);
1726 Node* const on_finally_map = LoadMap(on_finally);
1727 GotoUnless(IsCallableMap(on_finally_map), &if_notcallable);
1728
1729 // 3. Let thenFinally be ! CreateThenFinally(onFinally).
neis 2017/02/15 12:40:39 The few lines above are already part of steps 3 an
gsathya 2017/02/16 15:05:29 Done.
1730 // 4. Let catchFinally be ! CreateCatchFinally(onFinally).
1731 Node* const native_context = LoadNativeContext(context);
1732 Node* then_finally = nullptr;
1733 Node* catch_finally = nullptr;
1734 std::tie(then_finally, catch_finally) =
1735 CreatePromiseFinallyFunctions(on_finally, native_context);
1736 var_then_finally.Bind(then_finally);
1737 var_catch_finally.Bind(catch_finally);
1738 Goto(&perform_finally);
1739
1740 Bind(&if_notcallable);
1741 {
1742 // 1. If IsCallable(onFinally) is not true, return onFinally.
1743 var_then_finally.Bind(on_finally);
1744 // 1. If IsCallable(onFinally) is not true, return onFinally.
neis 2017/02/15 12:40:39 I find these comments here confusing, since they a
gsathya 2017/02/16 15:05:29 Yeah, that's fair. Removed
1745 var_catch_finally.Bind(on_finally);
1746 Goto(&perform_finally);
1747 }
1748
1749 Bind(&perform_finally);
1750 Label if_nativepromise(this), if_custompromise(this, Label::kDeferred);
1751 GotoIf(TaggedIsSmi(promise), &if_custompromise);
neis 2017/02/15 12:40:39 We already know that promise is a JS_PROMISE objec
gsathya 2017/02/16 15:05:29 Done.
1752 BranchIfFastPath(context, promise, &if_nativepromise, &if_custompromise);
1753
neis 2017/02/15 12:40:39 The step 5 comment should appear here.
gsathya 2017/02/16 15:05:29 Done.
1754 Bind(&if_nativepromise);
1755 {
1756 Node* deferred_promise = AllocateAndInitJSPromise(context, promise);
1757 InternalPerformPromiseThen(context, promise, var_then_finally.value(),
1758 var_catch_finally.value(), deferred_promise,
1759 UndefinedConstant(), UndefinedConstant());
1760 Return(deferred_promise);
1761 }
1762
1763 Bind(&if_custompromise);
1764 {
1765 Isolate* isolate = this->isolate();
1766 Node* const then_str = HeapConstant(isolate->factory()->then_string());
1767 Callable getproperty_callable = CodeFactory::GetProperty(isolate);
1768 Node* const then =
1769 CallStub(getproperty_callable, context, promise, then_str);
1770 Callable call_callable = CodeFactory::Call(isolate);
1771 // 5. Return ? Invoke(promise, "then", « thenFinally, catchFinally »).
1772 Node* const result =
1773 CallJS(call_callable, context, then, promise, var_then_finally.value(),
1774 var_catch_finally.value());
1775 Return(result);
1776 }
1777 }
1778
1567 } // namespace internal 1779 } // namespace internal
1568 } // namespace v8 1780 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698