| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/assembler_macros.h" | 9 #include "vm/assembler_macros.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| 11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/instructions.h" | 12 #include "vm/instructions.h" |
| 13 #include "vm/object_store.h" | 13 #include "vm/object_store.h" |
| 14 #include "vm/pages.h" | 14 #include "vm/pages.h" |
| 15 #include "vm/resolver.h" | 15 #include "vm/resolver.h" |
| 16 #include "vm/scavenger.h" | 16 #include "vm/scavenger.h" |
| 17 #include "vm/stub_code.h" | 17 #include "vm/stub_code.h" |
| 18 | 18 |
| 19 | 19 |
| 20 #define __ assembler-> | 20 #define __ assembler-> |
| 21 | 21 |
| 22 namespace dart { | 22 namespace dart { |
| 23 | 23 |
| 24 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); | 24 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); |
| 25 DEFINE_FLAG(bool, use_slow_path, false, | 25 DEFINE_FLAG(bool, use_slow_path, false, |
| 26 "Set to true for debugging & verifying the slow paths."); | 26 "Set to true for debugging & verifying the slow paths."); |
| 27 DECLARE_FLAG(int, optimization_counter_threshold); | 27 DECLARE_FLAG(int, optimization_counter_threshold); |
| 28 DECLARE_FLAG(bool, trace_optimized_ic_calls); |
| 28 | 29 |
| 29 // Input parameters: | 30 // Input parameters: |
| 30 // ESP : points to return address. | 31 // ESP : points to return address. |
| 31 // ESP + 4 : address of last argument in argument array. | 32 // ESP + 4 : address of last argument in argument array. |
| 32 // ESP + 4*EDX : address of first argument in argument array. | 33 // ESP + 4*EDX : address of first argument in argument array. |
| 33 // ESP + 4*EDX + 4 : address of return value. | 34 // ESP + 4*EDX + 4 : address of return value. |
| 34 // ECX : address of the runtime function to call. | 35 // ECX : address of the runtime function to call. |
| 35 // EDX : number of arguments to the call. | 36 // EDX : number of arguments to the call. |
| 36 // Must preserve callee saved registers EDI and EBX. | 37 // Must preserve callee saved registers EDI and EBX. |
| 37 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 38 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| (...skipping 1500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1538 __ popl(EAX); | 1539 __ popl(EAX); |
| 1539 __ popl(EAX); | 1540 __ popl(EAX); |
| 1540 __ popl(EAX); // Get result into EAX. | 1541 __ popl(EAX); // Get result into EAX. |
| 1541 | 1542 |
| 1542 // Remove the stub frame as we are about to return. | 1543 // Remove the stub frame as we are about to return. |
| 1543 __ LeaveFrame(); | 1544 __ LeaveFrame(); |
| 1544 __ ret(); | 1545 __ ret(); |
| 1545 } | 1546 } |
| 1546 | 1547 |
| 1547 | 1548 |
| 1548 // Loads function into 'temp_reg', preserves 'ic_reg'. | 1549 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 1550 Register argdesc_reg = EDX; |
| 1551 Register ic_reg = ECX; |
| 1552 Register func_reg = EDI; |
| 1553 if (FLAG_trace_optimized_ic_calls) { |
| 1554 AssemblerMacros::EnterStubFrame(assembler); |
| 1555 __ pushl(func_reg); // Preserve |
| 1556 __ pushl(argdesc_reg); // Preserve. |
| 1557 __ pushl(ic_reg); // Preserve. |
| 1558 __ pushl(ic_reg); // Argument. |
| 1559 __ pushl(func_reg); // Argument. |
| 1560 __ CallRuntime(kTraceICCallRuntimeEntry); |
| 1561 __ popl(EAX); // Discard argument; |
| 1562 __ popl(EAX); // Discard argument; |
| 1563 __ popl(ic_reg); // Restore. |
| 1564 __ popl(argdesc_reg); // Restore. |
| 1565 __ popl(func_reg); // Restore. |
| 1566 __ LeaveFrame(); |
| 1567 } |
| 1568 Label is_hot; |
| 1569 if (FlowGraphCompiler::CanOptimize()) { |
| 1570 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1571 __ cmpl(FieldAddress(func_reg, Function::usage_counter_offset()), |
| 1572 Immediate(FLAG_optimization_counter_threshold)); |
| 1573 __ j(GREATER_EQUAL, &is_hot, Assembler::kNearJump); |
| 1574 // As long as VM has no OSR do not optimize in the middle of the function |
| 1575 // but only at exit so that we have collected all type feedback before |
| 1576 // optimizing. |
| 1577 } |
| 1578 __ incl(FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1579 __ Bind(&is_hot); |
| 1580 } |
| 1581 |
| 1582 |
| 1583 |
| 1584 // Loads function into 'temp_reg'. |
| 1549 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 1585 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 1550 Register ic_reg, | |
| 1551 Register temp_reg) { | 1586 Register temp_reg) { |
| 1552 __ movl(temp_reg, FieldAddress(ic_reg, ICData::function_offset())); | 1587 Register ic_reg = ECX; |
| 1588 Register func_reg = temp_reg; |
| 1589 ASSERT(ic_reg != func_reg); |
| 1590 __ movl(func_reg, FieldAddress(ic_reg, ICData::function_offset())); |
| 1553 Label is_hot; | 1591 Label is_hot; |
| 1554 if (FlowGraphCompiler::CanOptimize()) { | 1592 if (FlowGraphCompiler::CanOptimize()) { |
| 1555 ASSERT(FLAG_optimization_counter_threshold > 1); | 1593 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1556 // The usage_counter is always less than FLAG_optimization_counter_threshold | 1594 // The usage_counter is always less than FLAG_optimization_counter_threshold |
| 1557 // except when the function gets optimized. | 1595 // except when the function gets optimized. |
| 1558 __ cmpl(FieldAddress(temp_reg, Function::usage_counter_offset()), | 1596 __ cmpl(FieldAddress(func_reg, Function::usage_counter_offset()), |
| 1559 Immediate(FLAG_optimization_counter_threshold)); | 1597 Immediate(FLAG_optimization_counter_threshold)); |
| 1560 __ j(EQUAL, &is_hot, Assembler::kNearJump); | 1598 __ j(EQUAL, &is_hot, Assembler::kNearJump); |
| 1561 // As long as VM has no OSR do not optimize in the middle of the function | 1599 // As long as VM has no OSR do not optimize in the middle of the function |
| 1562 // but only at exit so that we have collected all type feedback before | 1600 // but only at exit so that we have collected all type feedback before |
| 1563 // optimizing. | 1601 // optimizing. |
| 1564 } | 1602 } |
| 1565 __ incl(FieldAddress(temp_reg, Function::usage_counter_offset())); | 1603 __ incl(FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1566 __ Bind(&is_hot); | 1604 __ Bind(&is_hot); |
| 1567 } | 1605 } |
| 1568 | 1606 |
| 1569 | 1607 |
| 1570 // Generate inline cache check for 'num_args'. | 1608 // Generate inline cache check for 'num_args'. |
| 1571 // ECX: Inline cache data object. | 1609 // ECX: Inline cache data object. |
| 1572 // EDX: Arguments descriptor array. | 1610 // EDX: Arguments descriptor array. |
| 1573 // TOS(0): return address | 1611 // TOS(0): return address |
| 1574 // Control flow: | 1612 // Control flow: |
| 1575 // - If receiver is null -> jump to IC miss. | 1613 // - If receiver is null -> jump to IC miss. |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1677 __ popl(EAX); | 1715 __ popl(EAX); |
| 1678 } | 1716 } |
| 1679 __ popl(EAX); // Pop returned code object into EAX (null if not found). | 1717 __ popl(EAX); // Pop returned code object into EAX (null if not found). |
| 1680 __ popl(ECX); // Restore IC data array. | 1718 __ popl(ECX); // Restore IC data array. |
| 1681 __ popl(EDX); // Restore arguments array. | 1719 __ popl(EDX); // Restore arguments array. |
| 1682 __ LeaveFrame(); | 1720 __ LeaveFrame(); |
| 1683 Label call_target_function; | 1721 Label call_target_function; |
| 1684 __ cmpl(EAX, raw_null); | 1722 __ cmpl(EAX, raw_null); |
| 1685 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); | 1723 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); |
| 1686 // NoSuchMethod or closure. | 1724 // NoSuchMethod or closure. |
| 1725 // Mark IC call that it may be a closure call that does not collect |
| 1726 // type feedback. |
| 1727 __ movb(FieldAddress(ECX, ICData::is_closure_call_offset()), Immediate(1)); |
| 1687 __ jmp(&StubCode::InstanceFunctionLookupLabel()); | 1728 __ jmp(&StubCode::InstanceFunctionLookupLabel()); |
| 1688 | 1729 |
| 1689 __ Bind(&found); | 1730 __ Bind(&found); |
| 1690 // EBX: Pointer to an IC data check group (classes + target) | 1731 // EBX: Pointer to an IC data check group (classes + target) |
| 1691 __ movl(EAX, Address(EBX, kWordSize * num_args)); // Target function. | 1732 __ movl(EAX, Address(EBX, kWordSize * num_args)); // Target function. |
| 1692 | 1733 |
| 1693 __ Bind(&call_target_function); | 1734 __ Bind(&call_target_function); |
| 1694 // EAX: Target function. | 1735 // EAX: Target function. |
| 1695 __ movl(EAX, FieldAddress(EAX, Function::code_offset())); | 1736 __ movl(EAX, FieldAddress(EAX, Function::code_offset())); |
| 1696 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); | 1737 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1718 // ECX: Inline cache data object. | 1759 // ECX: Inline cache data object. |
| 1719 // EDX: Arguments array. | 1760 // EDX: Arguments array. |
| 1720 // TOS(0): Return address. | 1761 // TOS(0): Return address. |
| 1721 // Inline cache data object structure: | 1762 // Inline cache data object structure: |
| 1722 // 0: function-name | 1763 // 0: function-name |
| 1723 // 1: N, number of arguments checked. | 1764 // 1: N, number of arguments checked. |
| 1724 // 2 .. (length - 1): group of checks, each check containing: | 1765 // 2 .. (length - 1): group of checks, each check containing: |
| 1725 // - N classes. | 1766 // - N classes. |
| 1726 // - 1 target function. | 1767 // - 1 target function. |
| 1727 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1768 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1728 GenerateUsageCounterIncrement(assembler, ECX, EBX); | 1769 GenerateUsageCounterIncrement(assembler, EBX); |
| 1729 return GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1770 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1730 } | 1771 } |
| 1731 | 1772 |
| 1732 | 1773 |
| 1733 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1774 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1734 GenerateUsageCounterIncrement(assembler, ECX, EBX); | 1775 GenerateUsageCounterIncrement(assembler, EBX); |
| 1735 return GenerateNArgsCheckInlineCacheStub(assembler, 2); | 1776 GenerateNArgsCheckInlineCacheStub(assembler, 2); |
| 1736 } | 1777 } |
| 1737 | 1778 |
| 1738 | 1779 |
| 1739 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1780 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1740 GenerateUsageCounterIncrement(assembler, ECX, EBX); | 1781 GenerateUsageCounterIncrement(assembler, EBX); |
| 1741 return GenerateNArgsCheckInlineCacheStub(assembler, 3); | 1782 GenerateNArgsCheckInlineCacheStub(assembler, 3); |
| 1783 } |
| 1784 |
| 1785 |
| 1786 |
| 1787 // Use inline cache data array to invoke the target or continue in inline |
| 1788 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1789 // EDI: function which counter needs to be incremented. |
| 1790 // ECX: Inline cache data object. |
| 1791 // EDX: Arguments array. |
| 1792 // TOS(0): Return address. |
| 1793 // Inline cache data object structure: |
| 1794 // 0: function-name |
| 1795 // 1: N, number of arguments checked. |
| 1796 // 2 .. (length - 1): group of checks, each check containing: |
| 1797 // - N classes. |
| 1798 // - 1 target function. |
| 1799 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1800 Assembler* assembler) { |
| 1801 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1802 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1803 } |
| 1804 |
| 1805 |
| 1806 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1807 Assembler* assembler) { |
| 1808 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1809 GenerateNArgsCheckInlineCacheStub(assembler, 2); |
| 1810 } |
| 1811 |
| 1812 |
| 1813 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1814 Assembler* assembler) { |
| 1815 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1816 GenerateNArgsCheckInlineCacheStub(assembler, 3); |
| 1817 } |
| 1818 |
| 1819 |
| 1820 // Do not count as no type feedback is collected. |
| 1821 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1822 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1742 } | 1823 } |
| 1743 | 1824 |
| 1744 | 1825 |
| 1745 // Megamorphic call is currently implemented as IC call but through a stub | 1826 // Megamorphic call is currently implemented as IC call but through a stub |
| 1746 // that does not check/count function invocations. | 1827 // that does not check/count function invocations. |
| 1747 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { | 1828 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { |
| 1748 return GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1829 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1749 } | 1830 } |
| 1750 | 1831 |
| 1751 | 1832 |
| 1752 // ECX: Function object. | 1833 // ECX: Function object. |
| 1753 // EDX: Arguments array. | 1834 // EDX: Arguments array. |
| 1754 // TOS(0): return address (Dart code). | 1835 // TOS(0): return address (Dart code). |
| 1755 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { | 1836 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { |
| 1756 // Create a stub frame as we are pushing some objects on the stack before | 1837 // Create a stub frame as we are pushing some objects on the stack before |
| 1757 // calling into the runtime. | 1838 // calling into the runtime. |
| 1758 AssemblerMacros::EnterStubFrame(assembler); | 1839 AssemblerMacros::EnterStubFrame(assembler); |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2080 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); | 2161 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); |
| 2081 __ popl(EDX); | 2162 __ popl(EDX); |
| 2082 __ popl(EAX); | 2163 __ popl(EAX); |
| 2083 __ LeaveFrame(); | 2164 __ LeaveFrame(); |
| 2084 __ ret(); | 2165 __ ret(); |
| 2085 } | 2166 } |
| 2086 | 2167 |
| 2087 } // namespace dart | 2168 } // namespace dart |
| 2088 | 2169 |
| 2089 #endif // defined TARGET_ARCH_IA32 | 2170 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |