| 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" |
| (...skipping 1525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1536 __ popl(EAX); | 1536 __ popl(EAX); |
| 1537 __ popl(EAX); | 1537 __ popl(EAX); |
| 1538 __ popl(EAX); // Get result into EAX. | 1538 __ popl(EAX); // Get result into EAX. |
| 1539 | 1539 |
| 1540 // Remove the stub frame as we are about to return. | 1540 // Remove the stub frame as we are about to return. |
| 1541 __ LeaveFrame(); | 1541 __ LeaveFrame(); |
| 1542 __ ret(); | 1542 __ ret(); |
| 1543 } | 1543 } |
| 1544 | 1544 |
| 1545 | 1545 |
| 1546 // Loads function into 'temp_reg', preserves 'ic_reg'. |
| 1547 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 1548 Register ic_reg, |
| 1549 Register temp_reg) { |
| 1550 __ movl(temp_reg, FieldAddress(ic_reg, ICData::function_offset())); |
| 1551 Label is_hot; |
| 1552 if (FlowGraphCompiler::CanOptimize()) { |
| 1553 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1554 // The usage_counter is always less than FLAG_optimization_counter_threshold |
| 1555 // except when the function gets optimized. |
| 1556 __ cmpl(FieldAddress(temp_reg, Function::usage_counter_offset()), |
| 1557 Immediate(FLAG_optimization_counter_threshold - 1)); |
| 1558 // Do not increment to equality with threshold, since a counter greater |
| 1559 // than threshold denotes a function that was already optimized. |
| 1560 // The equality should be reached only at exit of the method |
| 1561 // (return instruction). |
| 1562 __ j(EQUAL, &is_hot, Assembler::kNearJump); |
| 1563 // As long as VM has no OSR do not optimize in the middle of the function |
| 1564 // but only at exit so that we have collected all type feedback before |
| 1565 // optimizing. |
| 1566 } |
| 1567 __ incl(FieldAddress(temp_reg, Function::usage_counter_offset())); |
| 1568 __ Bind(&is_hot); |
| 1569 } |
| 1570 |
| 1546 | 1571 |
| 1547 // Generate inline cache check for 'num_args'. | 1572 // Generate inline cache check for 'num_args'. |
| 1548 // ECX: Inline cache data object. | 1573 // ECX: Inline cache data object. |
| 1549 // EDX: Arguments descriptor array. | 1574 // EDX: Arguments descriptor array. |
| 1550 // TOS(0): return address | 1575 // TOS(0): return address |
| 1551 // Control flow: | 1576 // Control flow: |
| 1552 // - If receiver is null -> jump to IC miss. | 1577 // - If receiver is null -> jump to IC miss. |
| 1553 // - If receiver is Smi -> load Smi class. | 1578 // - If receiver is Smi -> load Smi class. |
| 1554 // - If receiver is not-Smi -> load receiver's class. | 1579 // - If receiver is not-Smi -> load receiver's class. |
| 1555 // - Check if 'num_args' (including receiver) match any IC data group. | 1580 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1556 // - Match found -> jump to target. | 1581 // - Match found -> jump to target. |
| 1557 // - Match not found -> jump to IC miss. | 1582 // - Match not found -> jump to IC miss. |
| 1558 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, | 1583 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, |
| 1559 intptr_t num_args) { | 1584 intptr_t num_args) { |
| 1560 ASSERT(num_args > 0); | 1585 ASSERT(num_args > 0); |
| 1561 #if defined(DEBUG) | 1586 #if defined(DEBUG) |
| 1562 { Label ok; | 1587 { Label ok; |
| 1563 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. | 1588 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. |
| 1564 // 'num_args_tested' is stored as an untagged int. | 1589 // 'num_args_tested' is stored as an untagged int. |
| 1565 __ movl(EBX, FieldAddress(ECX, ICData::num_args_tested_offset())); | 1590 __ movl(EBX, FieldAddress(ECX, ICData::num_args_tested_offset())); |
| 1566 __ cmpl(EBX, Immediate(num_args)); | 1591 __ cmpl(EBX, Immediate(num_args)); |
| 1567 __ j(EQUAL, &ok, Assembler::kNearJump); | 1592 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1568 __ Stop("Incorrect stub for IC data"); | 1593 __ Stop("Incorrect stub for IC data"); |
| 1569 __ Bind(&ok); | 1594 __ Bind(&ok); |
| 1570 } | 1595 } |
| 1571 #endif // DEBUG | 1596 #endif // DEBUG |
| 1572 | 1597 |
| 1573 __ movl(EBX, FieldAddress(ECX, ICData::function_offset())); | |
| 1574 Label is_hot; | |
| 1575 if (FlowGraphCompiler::CanOptimize()) { | |
| 1576 ASSERT(FLAG_optimization_counter_threshold > 1); | |
| 1577 // The usage_counter is always less than FLAG_optimization_counter_threshold | |
| 1578 // except when the function gets optimized. | |
| 1579 __ cmpl(FieldAddress(EBX, Function::usage_counter_offset()), | |
| 1580 Immediate(FLAG_optimization_counter_threshold - 1)); | |
| 1581 // Do not increment to equality with threshold, since a counter greater | |
| 1582 // than threshold denotes a function that was already optimized. | |
| 1583 // The equality should be reached only at exit of the method | |
| 1584 // (return instruction). | |
| 1585 __ j(EQUAL, &is_hot, Assembler::kNearJump); | |
| 1586 // As long as VM has no OSR do not optimize in the middle of the function | |
| 1587 // but only at exit so that we have collected all type feedback before | |
| 1588 // optimizing. | |
| 1589 } | |
| 1590 __ incl(FieldAddress(EBX, Function::usage_counter_offset())); | |
| 1591 __ Bind(&is_hot); | |
| 1592 | |
| 1593 // Loop that checks if there is an IC data match. | 1598 // Loop that checks if there is an IC data match. |
| 1594 Label loop, update, test, found, get_class_id_as_smi; | 1599 Label loop, update, test, found, get_class_id_as_smi; |
| 1595 // ECX: IC data object (preserved). | 1600 // ECX: IC data object (preserved). |
| 1596 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); | 1601 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); |
| 1597 // EBX: ic_data_array with check entries: classes and target functions. | 1602 // EBX: ic_data_array with check entries: classes and target functions. |
| 1598 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); | 1603 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); |
| 1599 // EBX: points directly to the first ic data array element. | 1604 // EBX: points directly to the first ic data array element. |
| 1600 | 1605 |
| 1601 // Get the receiver's class ID (first read number of arguments from | 1606 // Get the receiver's class ID (first read number of arguments from |
| 1602 // argument descriptor array and then access the receiver from the stack). | 1607 // argument descriptor array and then access the receiver from the stack). |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1705 | 1710 |
| 1706 __ Bind(¬_smi); | 1711 __ Bind(¬_smi); |
| 1707 __ LoadClassId(EAX, EAX); | 1712 __ LoadClassId(EAX, EAX); |
| 1708 __ SmiTag(EAX); | 1713 __ SmiTag(EAX); |
| 1709 __ ret(); | 1714 __ ret(); |
| 1710 } | 1715 } |
| 1711 | 1716 |
| 1712 | 1717 |
| 1713 // Use inline cache data array to invoke the target or continue in inline | 1718 // Use inline cache data array to invoke the target or continue in inline |
| 1714 // cache miss handler. Stub for 1-argument check (receiver class). | 1719 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1715 // ECX: Inline cache data array | 1720 // ECX: Inline cache data object. |
| 1716 // EDX: Arguments array | 1721 // EDX: Arguments array. |
| 1717 // TOS(0): return address | 1722 // TOS(0): Return address. |
| 1718 // Inline cache data array structure: | 1723 // Inline cache data object structure: |
| 1719 // 0: function-name | 1724 // 0: function-name |
| 1720 // 1: N, number of arguments checked. | 1725 // 1: N, number of arguments checked. |
| 1721 // 2 .. (length - 1): group of checks, each check containing: | 1726 // 2 .. (length - 1): group of checks, each check containing: |
| 1722 // - N classes. | 1727 // - N classes. |
| 1723 // - 1 target function. | 1728 // - 1 target function. |
| 1724 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1729 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1730 GenerateUsageCounterIncrement(assembler, ECX, EBX); |
| 1725 return GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1731 return GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1726 } | 1732 } |
| 1727 | 1733 |
| 1728 | 1734 |
| 1729 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1735 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1736 GenerateUsageCounterIncrement(assembler, ECX, EBX); |
| 1730 return GenerateNArgsCheckInlineCacheStub(assembler, 2); | 1737 return GenerateNArgsCheckInlineCacheStub(assembler, 2); |
| 1731 } | 1738 } |
| 1732 | 1739 |
| 1733 | 1740 |
| 1734 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1741 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1742 GenerateUsageCounterIncrement(assembler, ECX, EBX); |
| 1735 return GenerateNArgsCheckInlineCacheStub(assembler, 3); | 1743 return GenerateNArgsCheckInlineCacheStub(assembler, 3); |
| 1736 } | 1744 } |
| 1737 | 1745 |
| 1738 | 1746 |
| 1747 // Megamorphic call is currently implemented as IC call but through a stub |
| 1748 // that does not check/count function invocations. |
| 1749 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { |
| 1750 return GenerateNArgsCheckInlineCacheStub(assembler, 1); |
| 1751 } |
| 1752 |
| 1753 |
| 1739 // ECX: Function object. | 1754 // ECX: Function object. |
| 1740 // EDX: Arguments array. | 1755 // EDX: Arguments array. |
| 1741 // TOS(0): return address (Dart code). | 1756 // TOS(0): return address (Dart code). |
| 1742 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { | 1757 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { |
| 1743 // Create a stub frame as we are pushing some objects on the stack before | 1758 // Create a stub frame as we are pushing some objects on the stack before |
| 1744 // calling into the runtime. | 1759 // calling into the runtime. |
| 1745 AssemblerMacros::EnterStubFrame(assembler); | 1760 AssemblerMacros::EnterStubFrame(assembler); |
| 1746 __ pushl(EDX); | 1761 __ pushl(EDX); |
| 1747 __ pushl(ECX); | 1762 __ pushl(ECX); |
| 1748 __ CallRuntime(kBreakpointStaticHandlerRuntimeEntry); | 1763 __ CallRuntime(kBreakpointStaticHandlerRuntimeEntry); |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2053 __ Drop(4); | 2068 __ Drop(4); |
| 2054 __ LeaveFrame(); | 2069 __ LeaveFrame(); |
| 2055 | 2070 |
| 2056 __ jmp(&compute_result, Assembler::kNearJump); | 2071 __ jmp(&compute_result, Assembler::kNearJump); |
| 2057 } | 2072 } |
| 2058 | 2073 |
| 2059 | 2074 |
| 2060 } // namespace dart | 2075 } // namespace dart |
| 2061 | 2076 |
| 2062 #endif // defined TARGET_ARCH_IA32 | 2077 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |