| 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_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 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 // RSP : points to return address. | 31 // RSP : points to return address. |
| 31 // RSP + 8 : address of last argument in argument array. | 32 // RSP + 8 : address of last argument in argument array. |
| 32 // RSP + 8*R10 : address of first argument in argument array. | 33 // RSP + 8*R10 : address of first argument in argument array. |
| 33 // RSP + 8*R10 + 8 : address of return value. | 34 // RSP + 8*R10 + 8 : address of return value. |
| 34 // RBX : address of the runtime function to call. | 35 // RBX : address of the runtime function to call. |
| 35 // R10 : number of arguments to the call. | 36 // R10 : number of arguments to the call. |
| 36 // Must preserve callee saved registers R12 and R13. | 37 // Must preserve callee saved registers R12 and R13. |
| 37 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 38 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| (...skipping 1479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1517 __ popq(RAX); | 1518 __ popq(RAX); |
| 1518 __ popq(RAX); | 1519 __ popq(RAX); |
| 1519 __ popq(RAX); // Get result into RAX. | 1520 __ popq(RAX); // Get result into RAX. |
| 1520 | 1521 |
| 1521 // Remove the stub frame as we are about to return. | 1522 // Remove the stub frame as we are about to return. |
| 1522 __ LeaveFrame(); | 1523 __ LeaveFrame(); |
| 1523 __ ret(); | 1524 __ ret(); |
| 1524 } | 1525 } |
| 1525 | 1526 |
| 1526 | 1527 |
| 1528 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 1529 Register argdesc_reg = R10; |
| 1530 Register ic_reg = RBX; |
| 1531 Register func_reg = RDI; |
| 1532 if (FLAG_trace_optimized_ic_calls) { |
| 1533 AssemblerMacros::EnterStubFrame(assembler); |
| 1534 __ pushq(func_reg); // Preserve |
| 1535 __ pushq(argdesc_reg); // Preserve. |
| 1536 __ pushq(ic_reg); // Preserve. |
| 1537 __ pushq(ic_reg); // Argument. |
| 1538 __ pushq(func_reg); // Argument. |
| 1539 __ CallRuntime(kTraceICCallRuntimeEntry); |
| 1540 __ popq(RAX); // Discard argument; |
| 1541 __ popq(RAX); // Discard argument; |
| 1542 __ popq(ic_reg); // Restore. |
| 1543 __ popq(argdesc_reg); // Restore. |
| 1544 __ popq(func_reg); // Restore. |
| 1545 __ LeaveFrame(); |
| 1546 } |
| 1547 Label is_hot; |
| 1548 if (FlowGraphCompiler::CanOptimize()) { |
| 1549 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1550 __ cmpq(FieldAddress(func_reg, Function::usage_counter_offset()), |
| 1551 Immediate(FLAG_optimization_counter_threshold)); |
| 1552 __ j(GREATER_EQUAL, &is_hot, Assembler::kNearJump); |
| 1553 // As long as VM has no OSR do not optimize in the middle of the function |
| 1554 // but only at exit so that we have collected all type feedback before |
| 1555 // optimizing. |
| 1556 } |
| 1557 __ incq(FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1558 __ Bind(&is_hot); |
| 1559 } |
| 1560 |
| 1561 |
| 1527 // Loads function into 'temp_reg', preserves 'ic_reg'. | 1562 // Loads function into 'temp_reg', preserves 'ic_reg'. |
| 1528 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 1563 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 1529 Register ic_reg, | |
| 1530 Register temp_reg) { | 1564 Register temp_reg) { |
| 1531 __ movq(temp_reg, FieldAddress(ic_reg, ICData::function_offset())); | 1565 Register ic_reg = RBX; |
| 1566 Register func_reg = temp_reg; |
| 1567 ASSERT(ic_reg != func_reg); |
| 1568 __ movq(func_reg, FieldAddress(ic_reg, ICData::function_offset())); |
| 1532 Label is_hot; | 1569 Label is_hot; |
| 1533 if (FlowGraphCompiler::CanOptimize()) { | 1570 if (FlowGraphCompiler::CanOptimize()) { |
| 1534 ASSERT(FLAG_optimization_counter_threshold > 1); | 1571 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1535 // The usage_counter is always less than FLAG_optimization_counter_threshold | 1572 // The usage_counter is always less than FLAG_optimization_counter_threshold |
| 1536 // except when the function gets optimized. | 1573 // except when the function gets optimized. |
| 1537 __ cmpq(FieldAddress(temp_reg, Function::usage_counter_offset()), | 1574 __ cmpq(FieldAddress(func_reg, Function::usage_counter_offset()), |
| 1538 Immediate(FLAG_optimization_counter_threshold)); | 1575 Immediate(FLAG_optimization_counter_threshold)); |
| 1539 __ j(EQUAL, &is_hot, Assembler::kNearJump); | 1576 __ j(EQUAL, &is_hot, Assembler::kNearJump); |
| 1540 // As long as VM has no OSR do not optimize in the middle of the function | 1577 // As long as VM has no OSR do not optimize in the middle of the function |
| 1541 // but only at exit so that we have collected all type feedback before | 1578 // but only at exit so that we have collected all type feedback before |
| 1542 // optimizing. | 1579 // optimizing. |
| 1543 } | 1580 } |
| 1544 __ incq(FieldAddress(temp_reg, Function::usage_counter_offset())); | 1581 __ incq(FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1545 __ Bind(&is_hot); | 1582 __ Bind(&is_hot); |
| 1546 } | 1583 } |
| 1547 | 1584 |
| 1548 // Generate inline cache check for 'num_args'. | 1585 // Generate inline cache check for 'num_args'. |
| 1549 // RBX: Inline cache data object. | 1586 // RBX: Inline cache data object. |
| 1550 // R10: Arguments descriptor array. | 1587 // R10: Arguments descriptor array. |
| 1551 // TOS(0): return address | 1588 // TOS(0): return address |
| 1552 // Control flow: | 1589 // Control flow: |
| 1553 // - If receiver is null -> jump to IC miss. | 1590 // - If receiver is null -> jump to IC miss. |
| 1554 // - If receiver is Smi -> load Smi class. | 1591 // - If receiver is Smi -> load Smi class. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1653 __ popq(RAX); | 1690 __ popq(RAX); |
| 1654 } | 1691 } |
| 1655 __ popq(RAX); // Pop returned code object into RAX (null if not found). | 1692 __ popq(RAX); // Pop returned code object into RAX (null if not found). |
| 1656 __ popq(RBX); // Restore IC data array. | 1693 __ popq(RBX); // Restore IC data array. |
| 1657 __ popq(R10); // Restore arguments array. | 1694 __ popq(R10); // Restore arguments array. |
| 1658 __ LeaveFrame(); | 1695 __ LeaveFrame(); |
| 1659 Label call_target_function; | 1696 Label call_target_function; |
| 1660 __ cmpq(RAX, raw_null); | 1697 __ cmpq(RAX, raw_null); |
| 1661 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); | 1698 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); |
| 1662 // NoSuchMethod or closure. | 1699 // NoSuchMethod or closure. |
| 1700 // Mark IC call that it may be a closure call that does not collect |
| 1701 // type feedback. |
| 1702 __ movb(FieldAddress(RBX, ICData::is_closure_call_offset()), Immediate(1)); |
| 1663 __ jmp(&StubCode::InstanceFunctionLookupLabel()); | 1703 __ jmp(&StubCode::InstanceFunctionLookupLabel()); |
| 1664 | 1704 |
| 1665 __ Bind(&found); | 1705 __ Bind(&found); |
| 1666 // R12: Pointer to an IC data check group (classes + target) | 1706 // R12: Pointer to an IC data check group (classes + target) |
| 1667 __ movq(RAX, Address(R12, kWordSize * num_args)); // Target function. | 1707 __ movq(RAX, Address(R12, kWordSize * num_args)); // Target function. |
| 1668 | 1708 |
| 1669 __ Bind(&call_target_function); | 1709 __ Bind(&call_target_function); |
| 1670 // RAX: Target function. | 1710 // RAX: Target function. |
| 1671 __ movq(RAX, FieldAddress(RAX, Function::code_offset())); | 1711 __ movq(RAX, FieldAddress(RAX, Function::code_offset())); |
| 1672 __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); | 1712 __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1693 // RBX: Inline cache data object. | 1733 // RBX: Inline cache data object. |
| 1694 // RDX: Arguments array. | 1734 // RDX: Arguments array. |
| 1695 // TOS(0): Return address. | 1735 // TOS(0): Return address. |
| 1696 // Inline cache data object structure: | 1736 // Inline cache data object structure: |
| 1697 // 0: function-name | 1737 // 0: function-name |
| 1698 // 1: N, number of arguments checked. | 1738 // 1: N, number of arguments checked. |
| 1699 // 2 .. (length - 1): group of checks, each check containing: | 1739 // 2 .. (length - 1): group of checks, each check containing: |
| 1700 // - N classes. | 1740 // - N classes. |
| 1701 // - 1 target function. | 1741 // - 1 target function. |
| 1702 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1742 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1703 GenerateUsageCounterIncrement(assembler, RBX, RCX); | 1743 GenerateUsageCounterIncrement(assembler, RCX); |
| 1704 return GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1744 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1705 } | 1745 } |
| 1706 | 1746 |
| 1707 | 1747 |
| 1708 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1748 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1709 GenerateUsageCounterIncrement(assembler, RBX, RCX); | 1749 GenerateUsageCounterIncrement(assembler, RCX); |
| 1710 return GenerateNArgsCheckInlineCacheStub(assembler, 2); | 1750 GenerateNArgsCheckInlineCacheStub(assembler, 2); |
| 1711 } | 1751 } |
| 1712 | 1752 |
| 1713 | 1753 |
| 1714 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1754 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1715 GenerateUsageCounterIncrement(assembler, RBX, RCX); | 1755 GenerateUsageCounterIncrement(assembler, RCX); |
| 1716 return GenerateNArgsCheckInlineCacheStub(assembler, 3); | 1756 GenerateNArgsCheckInlineCacheStub(assembler, 3); |
| 1717 } | 1757 } |
| 1718 | 1758 |
| 1759 // Use inline cache data array to invoke the target or continue in inline |
| 1760 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1761 // RDI: function which counter needs to be incremented. |
| 1762 // RBX: Inline cache data object. |
| 1763 // RDX: Arguments array. |
| 1764 // TOS(0): Return address. |
| 1765 // Inline cache data object structure: |
| 1766 // 0: function-name |
| 1767 // 1: N, number of arguments checked. |
| 1768 // 2 .. (length - 1): group of checks, each check containing: |
| 1769 // - N classes. |
| 1770 // - 1 target function. |
| 1771 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1772 Assembler* assembler) { |
| 1773 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1774 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1775 } |
| 1776 |
| 1777 |
| 1778 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1779 Assembler* assembler) { |
| 1780 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1781 GenerateNArgsCheckInlineCacheStub(assembler, 2); |
| 1782 } |
| 1783 |
| 1784 |
| 1785 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1786 Assembler* assembler) { |
| 1787 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1788 GenerateNArgsCheckInlineCacheStub(assembler, 3); |
| 1789 } |
| 1790 |
| 1791 |
| 1792 // Do not count as no type feedback is collected. |
| 1793 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1794 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1795 } |
| 1796 |
| 1797 |
| 1719 // Megamorphic call is currently implemented as IC call but through a stub | 1798 // Megamorphic call is currently implemented as IC call but through a stub |
| 1720 // that does not check/count function invocations. | 1799 // that does not check/count function invocations. |
| 1721 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { | 1800 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { |
| 1722 return GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1801 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1723 } | 1802 } |
| 1724 | 1803 |
| 1725 // RBX: Function object. | 1804 // RBX: Function object. |
| 1726 // R10: Arguments array. | 1805 // R10: Arguments array. |
| 1727 // TOS(0): return address (Dart code). | 1806 // TOS(0): return address (Dart code). |
| 1728 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { | 1807 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { |
| 1729 AssemblerMacros::EnterStubFrame(assembler); | 1808 AssemblerMacros::EnterStubFrame(assembler); |
| 1730 __ pushq(R10); | 1809 __ pushq(R10); |
| 1731 __ pushq(RBX); | 1810 __ pushq(RBX); |
| 1732 __ CallRuntime(kBreakpointStaticHandlerRuntimeEntry); | 1811 __ CallRuntime(kBreakpointStaticHandlerRuntimeEntry); |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2040 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); | 2119 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); |
| 2041 __ popq(RDX); | 2120 __ popq(RDX); |
| 2042 __ popq(RAX); | 2121 __ popq(RAX); |
| 2043 __ LeaveFrame(); | 2122 __ LeaveFrame(); |
| 2044 __ ret(); | 2123 __ ret(); |
| 2045 } | 2124 } |
| 2046 | 2125 |
| 2047 } // namespace dart | 2126 } // namespace dart |
| 2048 | 2127 |
| 2049 #endif // defined TARGET_ARCH_X64 | 2128 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |