| 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 1459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1497 __ popq(RAX); | 1498 __ popq(RAX); |
| 1498 __ popq(RAX); | 1499 __ popq(RAX); |
| 1499 __ popq(RAX); // Get result into RAX. | 1500 __ popq(RAX); // Get result into RAX. |
| 1500 | 1501 |
| 1501 // Remove the stub frame as we are about to return. | 1502 // Remove the stub frame as we are about to return. |
| 1502 __ LeaveFrame(); | 1503 __ LeaveFrame(); |
| 1503 __ ret(); | 1504 __ ret(); |
| 1504 } | 1505 } |
| 1505 | 1506 |
| 1506 | 1507 |
| 1508 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 1509 Register argdesc_reg = R10; |
| 1510 Register ic_reg = RBX; |
| 1511 Register func_reg = RDI; |
| 1512 if (FLAG_trace_optimized_ic_calls) { |
| 1513 AssemblerMacros::EnterStubFrame(assembler); |
| 1514 __ pushq(func_reg); // Preserve |
| 1515 __ pushq(argdesc_reg); // Preserve. |
| 1516 __ pushq(ic_reg); // Preserve. |
| 1517 __ pushq(ic_reg); // Argument. |
| 1518 __ pushq(func_reg); // Argument. |
| 1519 __ CallRuntime(kTraceICCallRuntimeEntry); |
| 1520 __ popq(RAX); // Discard argument; |
| 1521 __ popq(RAX); // Discard argument; |
| 1522 __ popq(ic_reg); // Restore. |
| 1523 __ popq(argdesc_reg); // Restore. |
| 1524 __ popq(func_reg); // Restore. |
| 1525 __ LeaveFrame(); |
| 1526 } |
| 1527 Label is_hot; |
| 1528 if (FlowGraphCompiler::CanOptimize()) { |
| 1529 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1530 __ cmpq(FieldAddress(func_reg, Function::usage_counter_offset()), |
| 1531 Immediate(FLAG_optimization_counter_threshold)); |
| 1532 __ j(GREATER_EQUAL, &is_hot, Assembler::kNearJump); |
| 1533 // As long as VM has no OSR do not optimize in the middle of the function |
| 1534 // but only at exit so that we have collected all type feedback before |
| 1535 // optimizing. |
| 1536 } |
| 1537 __ incq(FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1538 __ Bind(&is_hot); |
| 1539 } |
| 1540 |
| 1541 |
| 1507 // Loads function into 'temp_reg', preserves 'ic_reg'. | 1542 // Loads function into 'temp_reg', preserves 'ic_reg'. |
| 1508 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 1543 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 1509 Register ic_reg, | |
| 1510 Register temp_reg) { | 1544 Register temp_reg) { |
| 1511 __ movq(temp_reg, FieldAddress(ic_reg, ICData::function_offset())); | 1545 Register ic_reg = RBX; |
| 1546 Register func_reg = temp_reg; |
| 1547 ASSERT(ic_reg != func_reg); |
| 1548 __ movq(func_reg, FieldAddress(ic_reg, ICData::function_offset())); |
| 1512 Label is_hot; | 1549 Label is_hot; |
| 1513 if (FlowGraphCompiler::CanOptimize()) { | 1550 if (FlowGraphCompiler::CanOptimize()) { |
| 1514 ASSERT(FLAG_optimization_counter_threshold > 1); | 1551 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1515 // The usage_counter is always less than FLAG_optimization_counter_threshold | 1552 // The usage_counter is always less than FLAG_optimization_counter_threshold |
| 1516 // except when the function gets optimized. | 1553 // except when the function gets optimized. |
| 1517 __ cmpq(FieldAddress(temp_reg, Function::usage_counter_offset()), | 1554 __ cmpq(FieldAddress(func_reg, Function::usage_counter_offset()), |
| 1518 Immediate(FLAG_optimization_counter_threshold)); | 1555 Immediate(FLAG_optimization_counter_threshold)); |
| 1519 __ j(EQUAL, &is_hot, Assembler::kNearJump); | 1556 __ j(EQUAL, &is_hot, Assembler::kNearJump); |
| 1520 // As long as VM has no OSR do not optimize in the middle of the function | 1557 // As long as VM has no OSR do not optimize in the middle of the function |
| 1521 // but only at exit so that we have collected all type feedback before | 1558 // but only at exit so that we have collected all type feedback before |
| 1522 // optimizing. | 1559 // optimizing. |
| 1523 } | 1560 } |
| 1524 __ incq(FieldAddress(temp_reg, Function::usage_counter_offset())); | 1561 __ incq(FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1525 __ Bind(&is_hot); | 1562 __ Bind(&is_hot); |
| 1526 } | 1563 } |
| 1527 | 1564 |
| 1528 // Generate inline cache check for 'num_args'. | 1565 // Generate inline cache check for 'num_args'. |
| 1529 // RBX: Inline cache data object. | 1566 // RBX: Inline cache data object. |
| 1530 // R10: Arguments descriptor array. | 1567 // R10: Arguments descriptor array. |
| 1531 // TOS(0): return address | 1568 // TOS(0): return address |
| 1532 // Control flow: | 1569 // Control flow: |
| 1533 // - If receiver is null -> jump to IC miss. | 1570 // - If receiver is null -> jump to IC miss. |
| 1534 // - If receiver is Smi -> load Smi class. | 1571 // - If receiver is Smi -> load Smi class. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1633 __ popq(RAX); | 1670 __ popq(RAX); |
| 1634 } | 1671 } |
| 1635 __ popq(RAX); // Pop returned code object into RAX (null if not found). | 1672 __ popq(RAX); // Pop returned code object into RAX (null if not found). |
| 1636 __ popq(RBX); // Restore IC data array. | 1673 __ popq(RBX); // Restore IC data array. |
| 1637 __ popq(R10); // Restore arguments array. | 1674 __ popq(R10); // Restore arguments array. |
| 1638 __ LeaveFrame(); | 1675 __ LeaveFrame(); |
| 1639 Label call_target_function; | 1676 Label call_target_function; |
| 1640 __ cmpq(RAX, raw_null); | 1677 __ cmpq(RAX, raw_null); |
| 1641 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); | 1678 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); |
| 1642 // NoSuchMethod or closure. | 1679 // NoSuchMethod or closure. |
| 1680 // Mark IC call that it may be a closure call that does not collect |
| 1681 // type feedback. |
| 1682 __ movb(FieldAddress(RBX, ICData::is_closure_call_offset()), Immediate(1)); |
| 1643 __ jmp(&StubCode::InstanceFunctionLookupLabel()); | 1683 __ jmp(&StubCode::InstanceFunctionLookupLabel()); |
| 1644 | 1684 |
| 1645 __ Bind(&found); | 1685 __ Bind(&found); |
| 1646 // R12: Pointer to an IC data check group (classes + target) | 1686 // R12: Pointer to an IC data check group (classes + target) |
| 1647 __ movq(RAX, Address(R12, kWordSize * num_args)); // Target function. | 1687 __ movq(RAX, Address(R12, kWordSize * num_args)); // Target function. |
| 1648 | 1688 |
| 1649 __ Bind(&call_target_function); | 1689 __ Bind(&call_target_function); |
| 1650 // RAX: Target function. | 1690 // RAX: Target function. |
| 1651 __ movq(RAX, FieldAddress(RAX, Function::code_offset())); | 1691 __ movq(RAX, FieldAddress(RAX, Function::code_offset())); |
| 1652 __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); | 1692 __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1673 // RBX: Inline cache data object. | 1713 // RBX: Inline cache data object. |
| 1674 // RDX: Arguments array. | 1714 // RDX: Arguments array. |
| 1675 // TOS(0): Return address. | 1715 // TOS(0): Return address. |
| 1676 // Inline cache data object structure: | 1716 // Inline cache data object structure: |
| 1677 // 0: function-name | 1717 // 0: function-name |
| 1678 // 1: N, number of arguments checked. | 1718 // 1: N, number of arguments checked. |
| 1679 // 2 .. (length - 1): group of checks, each check containing: | 1719 // 2 .. (length - 1): group of checks, each check containing: |
| 1680 // - N classes. | 1720 // - N classes. |
| 1681 // - 1 target function. | 1721 // - 1 target function. |
| 1682 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1722 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1683 GenerateUsageCounterIncrement(assembler, RBX, RCX); | 1723 GenerateUsageCounterIncrement(assembler, RCX); |
| 1684 return GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1724 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1685 } | 1725 } |
| 1686 | 1726 |
| 1687 | 1727 |
| 1688 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1728 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1689 GenerateUsageCounterIncrement(assembler, RBX, RCX); | 1729 GenerateUsageCounterIncrement(assembler, RCX); |
| 1690 return GenerateNArgsCheckInlineCacheStub(assembler, 2); | 1730 GenerateNArgsCheckInlineCacheStub(assembler, 2); |
| 1691 } | 1731 } |
| 1692 | 1732 |
| 1693 | 1733 |
| 1694 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1734 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1695 GenerateUsageCounterIncrement(assembler, RBX, RCX); | 1735 GenerateUsageCounterIncrement(assembler, RCX); |
| 1696 return GenerateNArgsCheckInlineCacheStub(assembler, 3); | 1736 GenerateNArgsCheckInlineCacheStub(assembler, 3); |
| 1697 } | 1737 } |
| 1698 | 1738 |
| 1739 // Use inline cache data array to invoke the target or continue in inline |
| 1740 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1741 // RDI: function which counter needs to be incremented. |
| 1742 // RBX: Inline cache data object. |
| 1743 // RDX: Arguments array. |
| 1744 // TOS(0): Return address. |
| 1745 // Inline cache data object structure: |
| 1746 // 0: function-name |
| 1747 // 1: N, number of arguments checked. |
| 1748 // 2 .. (length - 1): group of checks, each check containing: |
| 1749 // - N classes. |
| 1750 // - 1 target function. |
| 1751 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1752 Assembler* assembler) { |
| 1753 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1754 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1755 } |
| 1756 |
| 1757 |
| 1758 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1759 Assembler* assembler) { |
| 1760 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1761 GenerateNArgsCheckInlineCacheStub(assembler, 2); |
| 1762 } |
| 1763 |
| 1764 |
| 1765 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1766 Assembler* assembler) { |
| 1767 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1768 GenerateNArgsCheckInlineCacheStub(assembler, 3); |
| 1769 } |
| 1770 |
| 1771 |
| 1772 // Do not count as no type feedback is collected. |
| 1773 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1774 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1775 } |
| 1776 |
| 1777 |
| 1699 // Megamorphic call is currently implemented as IC call but through a stub | 1778 // Megamorphic call is currently implemented as IC call but through a stub |
| 1700 // that does not check/count function invocations. | 1779 // that does not check/count function invocations. |
| 1701 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { | 1780 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { |
| 1702 return GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1781 GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1703 } | 1782 } |
| 1704 | 1783 |
| 1705 // RBX: Function object. | 1784 // RBX: Function object. |
| 1706 // R10: Arguments array. | 1785 // R10: Arguments array. |
| 1707 // TOS(0): return address (Dart code). | 1786 // TOS(0): return address (Dart code). |
| 1708 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { | 1787 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { |
| 1709 AssemblerMacros::EnterStubFrame(assembler); | 1788 AssemblerMacros::EnterStubFrame(assembler); |
| 1710 __ pushq(R10); | 1789 __ pushq(R10); |
| 1711 __ pushq(RBX); | 1790 __ pushq(RBX); |
| 1712 __ CallRuntime(kBreakpointStaticHandlerRuntimeEntry); | 1791 __ CallRuntime(kBreakpointStaticHandlerRuntimeEntry); |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2020 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); | 2099 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry); |
| 2021 __ popq(RDX); | 2100 __ popq(RDX); |
| 2022 __ popq(RAX); | 2101 __ popq(RAX); |
| 2023 __ LeaveFrame(); | 2102 __ LeaveFrame(); |
| 2024 __ ret(); | 2103 __ ret(); |
| 2025 } | 2104 } |
| 2026 | 2105 |
| 2027 } // namespace dart | 2106 } // namespace dart |
| 2028 | 2107 |
| 2029 #endif // defined TARGET_ARCH_X64 | 2108 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |