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-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 Loading... |
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 1104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1556 TF_BUILTIN(InternalPromiseReject, PromiseBuiltinsAssembler) { | 1555 TF_BUILTIN(InternalPromiseReject, PromiseBuiltinsAssembler) { |
1557 Node* const promise = Parameter(1); | 1556 Node* const promise = Parameter(1); |
1558 Node* const reason = Parameter(2); | 1557 Node* const reason = Parameter(2); |
1559 Node* const debug_event = Parameter(3); | 1558 Node* const debug_event = Parameter(3); |
1560 Node* const context = Parameter(6); | 1559 Node* const context = Parameter(6); |
1561 | 1560 |
1562 InternalPromiseReject(context, promise, reason, debug_event); | 1561 InternalPromiseReject(context, promise, reason, debug_event); |
1563 Return(UndefinedConstant()); | 1562 Return(UndefinedConstant()); |
1564 } | 1563 } |
1565 | 1564 |
| 1565 Node* PromiseBuiltinsAssembler::CreatePromiseFinallyContext( |
| 1566 Node* on_finally, Node* native_context) { |
| 1567 Node* const context = |
| 1568 CreatePromiseContext(native_context, kOnFinallyContextLength); |
| 1569 StoreContextElementNoWriteBarrier(context, kOnFinallySlot, on_finally); |
| 1570 return context; |
| 1571 } |
| 1572 |
| 1573 std::pair<Node*, Node*> PromiseBuiltinsAssembler::CreatePromiseFinallyFunctions( |
| 1574 Node* on_finally, Node* native_context) { |
| 1575 Node* const promise_context = |
| 1576 CreatePromiseFinallyContext(on_finally, native_context); |
| 1577 Node* const map = LoadContextElement( |
| 1578 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); |
| 1579 Node* const then_finally_info = LoadContextElement( |
| 1580 native_context, Context::PROMISE_THEN_FINALLY_SHARED_FUN); |
| 1581 Node* const then_finally = AllocateFunctionWithMapAndContext( |
| 1582 map, then_finally_info, promise_context); |
| 1583 Node* const catch_finally_info = LoadContextElement( |
| 1584 native_context, Context::PROMISE_CATCH_FINALLY_SHARED_FUN); |
| 1585 Node* const catch_finally = AllocateFunctionWithMapAndContext( |
| 1586 map, catch_finally_info, promise_context); |
| 1587 return std::make_pair(then_finally, catch_finally); |
| 1588 } |
| 1589 |
| 1590 TF_BUILTIN(PromiseValueThunkFinally, PromiseBuiltinsAssembler) { |
| 1591 Node* const context = Parameter(3); |
| 1592 |
| 1593 Node* const value = LoadContextElement(context, kOnFinallySlot); |
| 1594 Return(value); |
| 1595 } |
| 1596 |
| 1597 Node* PromiseBuiltinsAssembler::CreateValueThunkFunctionContext( |
| 1598 Node* value, Node* native_context) { |
| 1599 Node* const context = |
| 1600 CreatePromiseContext(native_context, kOnFinallyContextLength); |
| 1601 StoreContextElementNoWriteBarrier(context, kOnFinallySlot, value); |
| 1602 return context; |
| 1603 } |
| 1604 |
| 1605 Node* PromiseBuiltinsAssembler::CreateValueThunkFunction(Node* value, |
| 1606 Node* native_context) { |
| 1607 Node* const value_thunk_context = |
| 1608 CreateValueThunkFunctionContext(value, native_context); |
| 1609 Node* const map = LoadContextElement( |
| 1610 native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX); |
| 1611 Node* const value_thunk_info = LoadContextElement( |
| 1612 native_context, Context::PROMISE_VALUE_THUNK_FINALLY_SHARED_FUN); |
| 1613 Node* const value_thunk = AllocateFunctionWithMapAndContext( |
| 1614 map, value_thunk_info, value_thunk_context); |
| 1615 return value_thunk; |
| 1616 } |
| 1617 |
| 1618 TF_BUILTIN(PromiseThenFinally, PromiseBuiltinsAssembler) { |
| 1619 CSA_ASSERT_JS_ARGC_EQ(this, 1); |
| 1620 |
| 1621 Node* const value = Parameter(1); |
| 1622 Node* const context = Parameter(4); |
| 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); |
| 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) { |
| 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 CSA_ASSERT_JS_ARGC_EQ(this, 1); |
| 1681 |
| 1682 Node* const reason = Parameter(1); |
| 1683 Node* const context = Parameter(4); |
| 1684 |
| 1685 Node* const on_finally = LoadContextElement(context, kOnFinallySlot); |
| 1686 |
| 1687 // 2.a Let result be ? Call(onFinally, undefined). |
| 1688 Callable call_callable = CodeFactory::Call(isolate()); |
| 1689 Node* result = |
| 1690 CallJS(call_callable, context, on_finally, UndefinedConstant()); |
| 1691 |
| 1692 // 2.b Let promise be ! PromiseResolve( %Promise%, result). |
| 1693 Node* const promise = AllocateAndInitJSPromise(context); |
| 1694 InternalResolvePromise(context, promise, result); |
| 1695 |
| 1696 // 2.c Let thrower be equivalent to a function that throws reason. |
| 1697 Node* native_context = LoadNativeContext(context); |
| 1698 Node* const thrower = CreateThrowerFunction(reason, native_context); |
| 1699 |
| 1700 // 2.d Let promiseCapability be ! NewPromiseCapability( %Promise%). |
| 1701 Node* const promise_capability = AllocateAndInitJSPromise(context, promise); |
| 1702 |
| 1703 // 2.e Return PerformPromiseThen(promise, thrower, undefined, |
| 1704 // promiseCapability). |
| 1705 InternalPerformPromiseThen(context, promise, thrower, UndefinedConstant(), |
| 1706 promise_capability, UndefinedConstant(), |
| 1707 UndefinedConstant()); |
| 1708 Return(promise_capability); |
| 1709 } |
| 1710 |
| 1711 TF_BUILTIN(PromiseFinally, PromiseBuiltinsAssembler) { |
| 1712 CSA_ASSERT_JS_ARGC_EQ(this, 1); |
| 1713 |
| 1714 // 1. Let promise be the this value. |
| 1715 Node* const promise = Parameter(0); |
| 1716 Node* const on_finally = Parameter(1); |
| 1717 Node* const context = Parameter(4); |
| 1718 |
| 1719 // 2. If IsPromise(promise) is false, throw a TypeError exception. |
| 1720 ThrowIfNotInstanceType(context, promise, JS_PROMISE_TYPE, |
| 1721 "Promise.prototype.finally"); |
| 1722 |
| 1723 Variable var_then_finally(this, MachineRepresentation::kTagged), |
| 1724 var_catch_finally(this, MachineRepresentation::kTagged); |
| 1725 |
| 1726 Label if_notcallable(this, Label::kDeferred), perform_finally(this); |
| 1727 |
| 1728 // 3. Let thenFinally be ! CreateThenFinally(onFinally). |
| 1729 // 4. Let catchFinally be ! CreateCatchFinally(onFinally). |
| 1730 GotoIf(TaggedIsSmi(on_finally), &if_notcallable); |
| 1731 Node* const on_finally_map = LoadMap(on_finally); |
| 1732 GotoIfNot(IsCallableMap(on_finally_map), &if_notcallable); |
| 1733 |
| 1734 Node* const native_context = LoadNativeContext(context); |
| 1735 Node* then_finally = nullptr; |
| 1736 Node* catch_finally = nullptr; |
| 1737 std::tie(then_finally, catch_finally) = |
| 1738 CreatePromiseFinallyFunctions(on_finally, native_context); |
| 1739 var_then_finally.Bind(then_finally); |
| 1740 var_catch_finally.Bind(catch_finally); |
| 1741 Goto(&perform_finally); |
| 1742 |
| 1743 Bind(&if_notcallable); |
| 1744 { |
| 1745 var_then_finally.Bind(on_finally); |
| 1746 var_catch_finally.Bind(on_finally); |
| 1747 Goto(&perform_finally); |
| 1748 } |
| 1749 |
| 1750 // 5. Return PerformPromiseThen(promise, valueThunk, undefined, |
| 1751 // promiseCapability). |
| 1752 Bind(&perform_finally); |
| 1753 Label if_nativepromise(this), if_custompromise(this, Label::kDeferred); |
| 1754 BranchIfFastPath(context, promise, &if_nativepromise, &if_custompromise); |
| 1755 |
| 1756 Bind(&if_nativepromise); |
| 1757 { |
| 1758 Node* deferred_promise = AllocateAndInitJSPromise(context, promise); |
| 1759 InternalPerformPromiseThen(context, promise, var_then_finally.value(), |
| 1760 var_catch_finally.value(), deferred_promise, |
| 1761 UndefinedConstant(), UndefinedConstant()); |
| 1762 Return(deferred_promise); |
| 1763 } |
| 1764 |
| 1765 Bind(&if_custompromise); |
| 1766 { |
| 1767 Isolate* isolate = this->isolate(); |
| 1768 Node* const then_str = HeapConstant(isolate->factory()->then_string()); |
| 1769 Callable getproperty_callable = CodeFactory::GetProperty(isolate); |
| 1770 Node* const then = |
| 1771 CallStub(getproperty_callable, context, promise, then_str); |
| 1772 Callable call_callable = CodeFactory::Call(isolate); |
| 1773 // 5. Return ? Invoke(promise, "then", « thenFinally, catchFinally »). |
| 1774 Node* const result = |
| 1775 CallJS(call_callable, context, then, promise, var_then_finally.value(), |
| 1776 var_catch_finally.value()); |
| 1777 Return(result); |
| 1778 } |
| 1779 } |
| 1780 |
1566 } // namespace internal | 1781 } // namespace internal |
1567 } // namespace v8 | 1782 } // namespace v8 |
OLD | NEW |