| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 1383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1394 // Generate inline cache check for 'num_args'. | 1394 // Generate inline cache check for 'num_args'. |
| 1395 // RBX: Inline cache data object. | 1395 // RBX: Inline cache data object. |
| 1396 // TOS(0): return address | 1396 // TOS(0): return address |
| 1397 // Control flow: | 1397 // Control flow: |
| 1398 // - If receiver is null -> jump to IC miss. | 1398 // - If receiver is null -> jump to IC miss. |
| 1399 // - If receiver is Smi -> load Smi class. | 1399 // - If receiver is Smi -> load Smi class. |
| 1400 // - If receiver is not-Smi -> load receiver's class. | 1400 // - If receiver is not-Smi -> load receiver's class. |
| 1401 // - Check if 'num_args' (including receiver) match any IC data group. | 1401 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1402 // - Match found -> jump to target. | 1402 // - Match found -> jump to target. |
| 1403 // - Match not found -> jump to IC miss. | 1403 // - Match not found -> jump to IC miss. |
| 1404 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, | 1404 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1405 intptr_t num_args) { | 1405 Assembler* assembler, |
| 1406 intptr_t num_args, |
| 1407 const RuntimeEntry& handle_ic_miss) { |
| 1406 ASSERT(num_args > 0); | 1408 ASSERT(num_args > 0); |
| 1407 #if defined(DEBUG) | 1409 #if defined(DEBUG) |
| 1408 { Label ok; | 1410 { Label ok; |
| 1409 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. | 1411 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. |
| 1410 // 'num_args_tested' is stored as an untagged int. | 1412 // 'num_args_tested' is stored as an untagged int. |
| 1411 __ movq(RCX, FieldAddress(RBX, ICData::num_args_tested_offset())); | 1413 __ movq(RCX, FieldAddress(RBX, ICData::num_args_tested_offset())); |
| 1412 __ cmpq(RCX, Immediate(num_args)); | 1414 __ cmpq(RCX, Immediate(num_args)); |
| 1413 __ j(EQUAL, &ok, Assembler::kNearJump); | 1415 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1414 __ Stop("Incorrect stub for IC data"); | 1416 __ Stop("Incorrect stub for IC data"); |
| 1415 __ Bind(&ok); | 1417 __ Bind(&ok); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1493 __ EnterStubFrame(); | 1495 __ EnterStubFrame(); |
| 1494 __ pushq(R10); // Preserve arguments descriptor array. | 1496 __ pushq(R10); // Preserve arguments descriptor array. |
| 1495 __ pushq(RBX); // Preserve IC data object. | 1497 __ pushq(RBX); // Preserve IC data object. |
| 1496 __ pushq(raw_null); // Setup space on stack for result (target code object). | 1498 __ pushq(raw_null); // Setup space on stack for result (target code object). |
| 1497 // Push call arguments. | 1499 // Push call arguments. |
| 1498 for (intptr_t i = 0; i < num_args; i++) { | 1500 for (intptr_t i = 0; i < num_args; i++) { |
| 1499 __ movq(RCX, Address(RAX, -kWordSize * i)); | 1501 __ movq(RCX, Address(RAX, -kWordSize * i)); |
| 1500 __ pushq(RCX); | 1502 __ pushq(RCX); |
| 1501 } | 1503 } |
| 1502 __ pushq(RBX); // Pass IC data object. | 1504 __ pushq(RBX); // Pass IC data object. |
| 1503 if (num_args == 1) { | 1505 __ CallRuntime(handle_ic_miss); |
| 1504 __ CallRuntime(kInlineCacheMissHandlerOneArgRuntimeEntry); | |
| 1505 } else if (num_args == 2) { | |
| 1506 __ CallRuntime(kInlineCacheMissHandlerTwoArgsRuntimeEntry); | |
| 1507 } else if (num_args == 3) { | |
| 1508 __ CallRuntime(kInlineCacheMissHandlerThreeArgsRuntimeEntry); | |
| 1509 } else { | |
| 1510 UNIMPLEMENTED(); | |
| 1511 } | |
| 1512 // Remove the call arguments pushed earlier, including the IC data object. | 1506 // Remove the call arguments pushed earlier, including the IC data object. |
| 1513 for (intptr_t i = 0; i < num_args + 1; i++) { | 1507 for (intptr_t i = 0; i < num_args + 1; i++) { |
| 1514 __ popq(RAX); | 1508 __ popq(RAX); |
| 1515 } | 1509 } |
| 1516 __ popq(RAX); // Pop returned code object into RAX (null if not found). | 1510 __ popq(RAX); // Pop returned code object into RAX (null if not found). |
| 1517 __ popq(RBX); // Restore IC data array. | 1511 __ popq(RBX); // Restore IC data array. |
| 1518 __ popq(R10); // Restore arguments descriptor array. | 1512 __ popq(R10); // Restore arguments descriptor array. |
| 1519 __ LeaveFrame(); | 1513 __ LeaveFrame(); |
| 1520 Label call_target_function; | 1514 Label call_target_function; |
| 1521 __ cmpq(RAX, raw_null); | 1515 __ cmpq(RAX, raw_null); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1563 // RBX: Inline cache data object. | 1557 // RBX: Inline cache data object. |
| 1564 // TOS(0): Return address. | 1558 // TOS(0): Return address. |
| 1565 // Inline cache data object structure: | 1559 // Inline cache data object structure: |
| 1566 // 0: function-name | 1560 // 0: function-name |
| 1567 // 1: N, number of arguments checked. | 1561 // 1: N, number of arguments checked. |
| 1568 // 2 .. (length - 1): group of checks, each check containing: | 1562 // 2 .. (length - 1): group of checks, each check containing: |
| 1569 // - N classes. | 1563 // - N classes. |
| 1570 // - 1 target function. | 1564 // - 1 target function. |
| 1571 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1565 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1572 GenerateUsageCounterIncrement(assembler, RCX); | 1566 GenerateUsageCounterIncrement(assembler, RCX); |
| 1573 GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1567 GenerateNArgsCheckInlineCacheStub( |
| 1568 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1574 } | 1569 } |
| 1575 | 1570 |
| 1576 | 1571 |
| 1577 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1572 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1578 GenerateUsageCounterIncrement(assembler, RCX); | 1573 GenerateUsageCounterIncrement(assembler, RCX); |
| 1579 GenerateNArgsCheckInlineCacheStub(assembler, 2); | 1574 GenerateNArgsCheckInlineCacheStub( |
| 1575 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); |
| 1580 } | 1576 } |
| 1581 | 1577 |
| 1582 | 1578 |
| 1583 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1579 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1584 GenerateUsageCounterIncrement(assembler, RCX); | 1580 GenerateUsageCounterIncrement(assembler, RCX); |
| 1585 GenerateNArgsCheckInlineCacheStub(assembler, 3); | 1581 GenerateNArgsCheckInlineCacheStub( |
| 1582 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); |
| 1586 } | 1583 } |
| 1587 | 1584 |
| 1588 // Use inline cache data array to invoke the target or continue in inline | 1585 // Use inline cache data array to invoke the target or continue in inline |
| 1589 // cache miss handler. Stub for 1-argument check (receiver class). | 1586 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1590 // RDI: function which counter needs to be incremented. | 1587 // RDI: function which counter needs to be incremented. |
| 1591 // RBX: Inline cache data object. | 1588 // RBX: Inline cache data object. |
| 1592 // TOS(0): Return address. | 1589 // TOS(0): Return address. |
| 1593 // Inline cache data object structure: | 1590 // Inline cache data object structure: |
| 1594 // 0: function-name | 1591 // 0: function-name |
| 1595 // 1: N, number of arguments checked. | 1592 // 1: N, number of arguments checked. |
| 1596 // 2 .. (length - 1): group of checks, each check containing: | 1593 // 2 .. (length - 1): group of checks, each check containing: |
| 1597 // - N classes. | 1594 // - N classes. |
| 1598 // - 1 target function. | 1595 // - 1 target function. |
| 1599 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1596 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1600 Assembler* assembler) { | 1597 Assembler* assembler) { |
| 1601 GenerateOptimizedUsageCounterIncrement(assembler); | 1598 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1602 GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1599 GenerateNArgsCheckInlineCacheStub( |
| 1600 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1603 } | 1601 } |
| 1604 | 1602 |
| 1605 | 1603 |
| 1606 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1604 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1607 Assembler* assembler) { | 1605 Assembler* assembler) { |
| 1608 GenerateOptimizedUsageCounterIncrement(assembler); | 1606 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1609 GenerateNArgsCheckInlineCacheStub(assembler, 2); | 1607 GenerateNArgsCheckInlineCacheStub( |
| 1608 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); |
| 1610 } | 1609 } |
| 1611 | 1610 |
| 1612 | 1611 |
| 1613 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( | 1612 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1614 Assembler* assembler) { | 1613 Assembler* assembler) { |
| 1615 GenerateOptimizedUsageCounterIncrement(assembler); | 1614 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1616 GenerateNArgsCheckInlineCacheStub(assembler, 3); | 1615 GenerateNArgsCheckInlineCacheStub( |
| 1616 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); |
| 1617 } | 1617 } |
| 1618 | 1618 |
| 1619 | 1619 |
| 1620 // Do not count as no type feedback is collected. | 1620 // Do not count as no type feedback is collected. |
| 1621 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { | 1621 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1622 GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1622 GenerateNArgsCheckInlineCacheStub( |
| 1623 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1623 } | 1624 } |
| 1624 | 1625 |
| 1625 | 1626 |
| 1626 // Megamorphic call is currently implemented as IC call but through a stub | 1627 // Megamorphic call is currently implemented as IC call but through a stub |
| 1627 // that does not check/count function invocations. | 1628 // that does not check/count function invocations. |
| 1628 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { | 1629 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { |
| 1629 GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1630 GenerateNArgsCheckInlineCacheStub( |
| 1631 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1630 } | 1632 } |
| 1631 | 1633 |
| 1632 | 1634 |
| 1633 // Intermediary stub between a static call and its target. ICData contains | 1635 // Intermediary stub between a static call and its target. ICData contains |
| 1634 // the target function and the call count. | 1636 // the target function and the call count. |
| 1635 // RBX: ICData | 1637 // RBX: ICData |
| 1636 void StubCode::GenerateUnoptimizedStaticCallStub(Assembler* assembler) { | 1638 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1637 GenerateUsageCounterIncrement(assembler, RCX); | 1639 GenerateUsageCounterIncrement(assembler, RCX); |
| 1638 #if defined(DEBUG) | 1640 #if defined(DEBUG) |
| 1639 { Label ok; | 1641 { Label ok; |
| 1640 // Check that the IC data array has NumberOfArgumentsChecked() == 0. | 1642 // Check that the IC data array has NumberOfArgumentsChecked() == 0. |
| 1641 // 'num_args_tested' is stored as an untagged int. | 1643 // 'num_args_tested' is stored as an untagged int. |
| 1642 __ movq(RCX, FieldAddress(RBX, ICData::num_args_tested_offset())); | 1644 __ movq(RCX, FieldAddress(RBX, ICData::num_args_tested_offset())); |
| 1643 __ cmpq(RCX, Immediate(0)); | 1645 __ cmpq(RCX, Immediate(0)); |
| 1644 __ j(EQUAL, &ok, Assembler::kNearJump); | 1646 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1645 __ Stop("Incorrect IC data for unoptimized static call"); | 1647 __ Stop("Incorrect IC data for unoptimized static call"); |
| 1646 __ Bind(&ok); | 1648 __ Bind(&ok); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1699 __ Bind(&target_is_compiled); | 1701 __ Bind(&target_is_compiled); |
| 1700 // RAX: Target code. | 1702 // RAX: Target code. |
| 1701 __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); | 1703 __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); |
| 1702 __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); | 1704 __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| 1703 // Load arguments descriptor into R10. | 1705 // Load arguments descriptor into R10. |
| 1704 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset())); | 1706 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset())); |
| 1705 __ jmp(RAX); | 1707 __ jmp(RAX); |
| 1706 } | 1708 } |
| 1707 | 1709 |
| 1708 | 1710 |
| 1711 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1712 GenerateUsageCounterIncrement(assembler, RCX); |
| 1713 GenerateNArgsCheckInlineCacheStub( |
| 1714 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry); |
| 1715 } |
| 1716 |
| 1717 |
| 1709 // RBX, R10: May contain arguments to runtime stub. | 1718 // RBX, R10: May contain arguments to runtime stub. |
| 1710 // TOS(0): return address (Dart code). | 1719 // TOS(0): return address (Dart code). |
| 1711 void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) { | 1720 void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) { |
| 1712 __ EnterStubFrame(); | 1721 __ EnterStubFrame(); |
| 1713 // Preserve runtime args. | 1722 // Preserve runtime args. |
| 1714 __ pushq(RBX); | 1723 __ pushq(RBX); |
| 1715 __ pushq(R10); | 1724 __ pushq(R10); |
| 1716 // Room for result. Debugger stub returns address of the | 1725 // Room for result. Debugger stub returns address of the |
| 1717 // unpatched runtime stub. | 1726 // unpatched runtime stub. |
| 1718 const Immediate& raw_null = | 1727 const Immediate& raw_null = |
| (...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2160 __ movq(right, Address(RSP, 3 * kWordSize)); | 2169 __ movq(right, Address(RSP, 3 * kWordSize)); |
| 2161 GenerateIdenticalWithNumberCheckStub(assembler, left, right); | 2170 GenerateIdenticalWithNumberCheckStub(assembler, left, right); |
| 2162 __ popq(right); | 2171 __ popq(right); |
| 2163 __ popq(left); | 2172 __ popq(left); |
| 2164 __ ret(); | 2173 __ ret(); |
| 2165 } | 2174 } |
| 2166 | 2175 |
| 2167 } // namespace dart | 2176 } // namespace dart |
| 2168 | 2177 |
| 2169 #endif // defined TARGET_ARCH_X64 | 2178 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |