| 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 1480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1518 __ popl(EAX); | 1519 __ popl(EAX); |
| 1519 __ popl(EAX); | 1520 __ popl(EAX); |
| 1520 __ popl(EAX); // Get result into EAX. | 1521 __ popl(EAX); // Get result into EAX. |
| 1521 | 1522 |
| 1522 // Remove the stub frame as we are about to return. | 1523 // Remove the stub frame as we are about to return. |
| 1523 __ LeaveFrame(); | 1524 __ LeaveFrame(); |
| 1524 __ ret(); | 1525 __ ret(); |
| 1525 } | 1526 } |
| 1526 | 1527 |
| 1527 | 1528 |
| 1528 // Loads function into 'temp_reg', preserves 'ic_reg'. | 1529 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 1530 Register argdesc_reg = EDX; |
| 1531 Register ic_reg = ECX; |
| 1532 Register func_reg = EDI; |
| 1533 if (FLAG_trace_optimized_ic_calls) { |
| 1534 AssemblerMacros::EnterStubFrame(assembler); |
| 1535 __ pushl(func_reg); // Preserve |
| 1536 __ pushl(argdesc_reg); // Preserve. |
| 1537 __ pushl(ic_reg); // Preserve. |
| 1538 __ pushl(ic_reg); // Argument. |
| 1539 __ pushl(func_reg); // Argument. |
| 1540 __ CallRuntime(kTraceICCallRuntimeEntry); |
| 1541 __ popl(EAX); // Discard argument; |
| 1542 __ popl(EAX); // Discard argument; |
| 1543 __ popl(ic_reg); // Restore. |
| 1544 __ popl(argdesc_reg); // Restore. |
| 1545 __ popl(func_reg); // Restore. |
| 1546 __ LeaveFrame(); |
| 1547 } |
| 1548 Label is_hot; |
| 1549 if (FlowGraphCompiler::CanOptimize()) { |
| 1550 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1551 __ cmpl(FieldAddress(func_reg, Function::usage_counter_offset()), |
| 1552 Immediate(FLAG_optimization_counter_threshold)); |
| 1553 __ j(GREATER_EQUAL, &is_hot, Assembler::kNearJump); |
| 1554 // As long as VM has no OSR do not optimize in the middle of the function |
| 1555 // but only at exit so that we have collected all type feedback before |
| 1556 // optimizing. |
| 1557 } |
| 1558 __ incl(FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1559 __ Bind(&is_hot); |
| 1560 } |
| 1561 |
| 1562 |
| 1563 |
| 1564 // Loads function into 'temp_reg'. |
| 1529 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 1565 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 1530 Register ic_reg, | |
| 1531 Register temp_reg) { | 1566 Register temp_reg) { |
| 1532 __ movl(temp_reg, FieldAddress(ic_reg, ICData::function_offset())); | 1567 Register ic_reg = ECX; |
| 1568 Register func_reg = temp_reg; |
| 1569 ASSERT(ic_reg != func_reg); |
| 1570 __ movl(func_reg, FieldAddress(ic_reg, ICData::function_offset())); |
| 1533 Label is_hot; | 1571 Label is_hot; |
| 1534 if (FlowGraphCompiler::CanOptimize()) { | 1572 if (FlowGraphCompiler::CanOptimize()) { |
| 1535 ASSERT(FLAG_optimization_counter_threshold > 1); | 1573 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1536 // The usage_counter is always less than FLAG_optimization_counter_threshold | 1574 // The usage_counter is always less than FLAG_optimization_counter_threshold |
| 1537 // except when the function gets optimized. | 1575 // except when the function gets optimized. |
| 1538 __ cmpl(FieldAddress(temp_reg, Function::usage_counter_offset()), | 1576 __ cmpl(FieldAddress(func_reg, Function::usage_counter_offset()), |
| 1539 Immediate(FLAG_optimization_counter_threshold)); | 1577 Immediate(FLAG_optimization_counter_threshold)); |
| 1540 __ j(EQUAL, &is_hot, Assembler::kNearJump); | 1578 __ j(EQUAL, &is_hot, Assembler::kNearJump); |
| 1541 // As long as VM has no OSR do not optimize in the middle of the function | 1579 // As long as VM has no OSR do not optimize in the middle of the function |
| 1542 // but only at exit so that we have collected all type feedback before | 1580 // but only at exit so that we have collected all type feedback before |
| 1543 // optimizing. | 1581 // optimizing. |
| 1544 } | 1582 } |
| 1545 __ incl(FieldAddress(temp_reg, Function::usage_counter_offset())); | 1583 __ incl(FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1546 __ Bind(&is_hot); | 1584 __ Bind(&is_hot); |
| 1547 } | 1585 } |
| 1548 | 1586 |
| 1549 | 1587 |
| 1550 // Generate inline cache check for 'num_args'. | 1588 // Generate inline cache check for 'num_args'. |
| 1551 // ECX: Inline cache data object. | 1589 // ECX: Inline cache data object. |
| 1552 // EDX: Arguments descriptor array. | 1590 // EDX: Arguments descriptor array. |
| 1553 // TOS(0): return address | 1591 // TOS(0): return address |
| 1554 // Control flow: | 1592 // Control flow: |
| 1555 // - If receiver is null -> jump to IC miss. | 1593 // - If receiver is null -> jump to IC miss. |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1657 __ popl(EAX); | 1695 __ popl(EAX); |
| 1658 } | 1696 } |
| 1659 __ popl(EAX); // Pop returned code object into EAX (null if not found). | 1697 __ popl(EAX); // Pop returned code object into EAX (null if not found). |
| 1660 __ popl(ECX); // Restore IC data array. | 1698 __ popl(ECX); // Restore IC data array. |
| 1661 __ popl(EDX); // Restore arguments array. | 1699 __ popl(EDX); // Restore arguments array. |
| 1662 __ LeaveFrame(); | 1700 __ LeaveFrame(); |
| 1663 Label call_target_function; | 1701 Label call_target_function; |
| 1664 __ cmpl(EAX, raw_null); | 1702 __ cmpl(EAX, raw_null); |
| 1665 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); | 1703 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); |
| 1666 // NoSuchMethod or closure. | 1704 // NoSuchMethod or closure. |
| 1705 // Mark IC call that it may be a closure call that does not collect |
| 1706 // type feedback. |
| 1707 __ movb(FieldAddress(ECX, ICData::is_closure_call_offset()), Immediate(1)); |
| 1667 __ jmp(&StubCode::InstanceFunctionLookupLabel()); | 1708 __ jmp(&StubCode::InstanceFunctionLookupLabel()); |
| 1668 | 1709 |
| 1669 __ Bind(&found); | 1710 __ Bind(&found); |
| 1670 // EBX: Pointer to an IC data check group (classes + target) | 1711 // EBX: Pointer to an IC data check group (classes + target) |
| 1671 __ movl(EAX, Address(EBX, kWordSize * num_args)); // Target function. | 1712 __ movl(EAX, Address(EBX, kWordSize * num_args)); // Target function. |
| 1672 | 1713 |
| 1673 __ Bind(&call_target_function); | 1714 __ Bind(&call_target_function); |
| 1674 // EAX: Target function. | 1715 // EAX: Target function. |
| 1675 __ movl(EAX, FieldAddress(EAX, Function::code_offset())); | 1716 __ movl(EAX, FieldAddress(EAX, Function::code_offset())); |
| 1676 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); | 1717 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1698 // ECX: Inline cache data object. | 1739 // ECX: Inline cache data object. |
| 1699 // EDX: Arguments array. | 1740 // EDX: Arguments array. |
| 1700 // TOS(0): Return address. | 1741 // TOS(0): Return address. |
| 1701 // Inline cache data object structure: | 1742 // Inline cache data object structure: |
| 1702 // 0: function-name | 1743 // 0: function-name |
| 1703 // 1: N, number of arguments checked. | 1744 // 1: N, number of arguments checked. |
| 1704 // 2 .. (length - 1): group of checks, each check containing: | 1745 // 2 .. (length - 1): group of checks, each check containing: |
| 1705 // - N classes. | 1746 // - N classes. |
| 1706 // - 1 target function. | 1747 // - 1 target function. |
| 1707 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1748 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1708 GenerateUsageCounterIncrement(assembler, ECX, EBX); | 1749 GenerateUsageCounterIncrement(assembler, EBX); |
| 1709 return GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1750 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1710 } | 1751 } |
| 1711 | 1752 |
| 1712 | 1753 |
| 1713 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1754 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1714 GenerateUsageCounterIncrement(assembler, ECX, EBX); | 1755 GenerateUsageCounterIncrement(assembler, EBX); |
| 1715 return GenerateNArgsCheckInlineCacheStub(assembler, 2); | 1756 GenerateNArgsCheckInlineCacheStub(assembler, 2); |
| 1716 } | 1757 } |
| 1717 | 1758 |
| 1718 | 1759 |
| 1719 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1760 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1720 GenerateUsageCounterIncrement(assembler, ECX, EBX); | 1761 GenerateUsageCounterIncrement(assembler, EBX); |
| 1721 return GenerateNArgsCheckInlineCacheStub(assembler, 3); | 1762 GenerateNArgsCheckInlineCacheStub(assembler, 3); |
| 1763 } |
| 1764 |
| 1765 |
| 1766 |
| 1767 // Use inline cache data array to invoke the target or continue in inline |
| 1768 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1769 // EDI: function which counter needs to be incremented. |
| 1770 // ECX: Inline cache data object. |
| 1771 // EDX: Arguments array. |
| 1772 // TOS(0): Return address. |
| 1773 // Inline cache data object structure: |
| 1774 // 0: function-name |
| 1775 // 1: N, number of arguments checked. |
| 1776 // 2 .. (length - 1): group of checks, each check containing: |
| 1777 // - N classes. |
| 1778 // - 1 target function. |
| 1779 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1780 Assembler* assembler) { |
| 1781 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1782 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1783 } |
| 1784 |
| 1785 |
| 1786 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1787 Assembler* assembler) { |
| 1788 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1789 GenerateNArgsCheckInlineCacheStub(assembler, 2); |
| 1790 } |
| 1791 |
| 1792 |
| 1793 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1794 Assembler* assembler) { |
| 1795 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1796 GenerateNArgsCheckInlineCacheStub(assembler, 3); |
| 1797 } |
| 1798 |
| 1799 |
| 1800 // Do not count as no type feedback is collected. |
| 1801 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1802 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1722 } | 1803 } |
| 1723 | 1804 |
| 1724 | 1805 |
| 1725 // Megamorphic call is currently implemented as IC call but through a stub | 1806 // Megamorphic call is currently implemented as IC call but through a stub |
| 1726 // that does not check/count function invocations. | 1807 // that does not check/count function invocations. |
| 1727 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { | 1808 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { |
| 1728 return GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1809 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1729 } | 1810 } |
| 1730 | 1811 |
| 1731 | 1812 |
| 1732 // ECX: Function object. | 1813 // ECX: Function object. |
| 1733 // EDX: Arguments array. | 1814 // EDX: Arguments array. |
| 1734 // TOS(0): return address (Dart code). | 1815 // TOS(0): return address (Dart code). |
| 1735 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { | 1816 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { |
| 1736 // Create a stub frame as we are pushing some objects on the stack before | 1817 // Create a stub frame as we are pushing some objects on the stack before |
| 1737 // calling into the runtime. | 1818 // calling into the runtime. |
| 1738 AssemblerMacros::EnterStubFrame(assembler); | 1819 AssemblerMacros::EnterStubFrame(assembler); |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2060 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); | 2141 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); |
| 2061 __ popl(EDX); | 2142 __ popl(EDX); |
| 2062 __ popl(EAX); | 2143 __ popl(EAX); |
| 2063 __ LeaveFrame(); | 2144 __ LeaveFrame(); |
| 2064 __ ret(); | 2145 __ ret(); |
| 2065 } | 2146 } |
| 2066 | 2147 |
| 2067 } // namespace dart | 2148 } // namespace dart |
| 2068 | 2149 |
| 2069 #endif // defined TARGET_ARCH_IA32 | 2150 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |