| 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_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 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 1399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1410 // Generate inline cache check for 'num_args'. | 1410 // Generate inline cache check for 'num_args'. |
| 1411 // ECX: Inline cache data object. | 1411 // ECX: Inline cache data object. |
| 1412 // TOS(0): return address | 1412 // TOS(0): return address |
| 1413 // Control flow: | 1413 // Control flow: |
| 1414 // - If receiver is null -> jump to IC miss. | 1414 // - If receiver is null -> jump to IC miss. |
| 1415 // - If receiver is Smi -> load Smi class. | 1415 // - If receiver is Smi -> load Smi class. |
| 1416 // - If receiver is not-Smi -> load receiver's class. | 1416 // - If receiver is not-Smi -> load receiver's class. |
| 1417 // - Check if 'num_args' (including receiver) match any IC data group. | 1417 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1418 // - Match found -> jump to target. | 1418 // - Match found -> jump to target. |
| 1419 // - Match not found -> jump to IC miss. | 1419 // - Match not found -> jump to IC miss. |
| 1420 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, | 1420 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1421 intptr_t num_args) { | 1421 Assembler* assembler, |
| 1422 intptr_t num_args, |
| 1423 const RuntimeEntry& handle_ic_miss) { |
| 1422 ASSERT(num_args > 0); | 1424 ASSERT(num_args > 0); |
| 1423 #if defined(DEBUG) | 1425 #if defined(DEBUG) |
| 1424 { Label ok; | 1426 { Label ok; |
| 1425 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. | 1427 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. |
| 1426 // 'num_args_tested' is stored as an untagged int. | 1428 // 'num_args_tested' is stored as an untagged int. |
| 1427 __ movl(EBX, FieldAddress(ECX, ICData::num_args_tested_offset())); | 1429 __ movl(EBX, FieldAddress(ECX, ICData::num_args_tested_offset())); |
| 1428 __ cmpl(EBX, Immediate(num_args)); | 1430 __ cmpl(EBX, Immediate(num_args)); |
| 1429 __ j(EQUAL, &ok, Assembler::kNearJump); | 1431 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1430 __ Stop("Incorrect stub for IC data"); | 1432 __ Stop("Incorrect stub for IC data"); |
| 1431 __ Bind(&ok); | 1433 __ Bind(&ok); |
| 1432 } | 1434 } |
| 1433 #endif // DEBUG | 1435 #endif // DEBUG |
| 1434 | 1436 |
| 1435 // Check single stepping. | 1437 // Check single stepping. |
| 1436 Label not_stepping; | 1438 Label not_stepping; |
| 1437 __ movl(EAX, FieldAddress(CTX, Context::isolate_offset())); | 1439 __ movl(EAX, FieldAddress(CTX, Context::isolate_offset())); |
| 1438 __ movzxb(EAX, Address(EAX, Isolate::single_step_offset())); | 1440 __ movzxb(EAX, Address(EAX, Isolate::single_step_offset())); |
| 1439 __ cmpl(EAX, Immediate(0)); | 1441 __ cmpl(EAX, Immediate(0)); |
| 1440 __ j(EQUAL, ¬_stepping, Assembler::kNearJump); | 1442 __ j(EQUAL, ¬_stepping, Assembler::kNearJump); |
| 1441 | 1443 |
| 1442 __ EnterStubFrame(); | 1444 __ EnterStubFrame(); |
| 1443 __ pushl(ECX); | 1445 __ pushl(ECX); |
| 1444 __ CallRuntime(kSingleStepHandlerRuntimeEntry); | 1446 __ CallRuntime(kSingleStepHandlerRuntimeEntry); |
| 1445 __ popl(ECX); | 1447 __ popl(ECX); |
| 1446 __ LeaveFrame(); | 1448 __ LeaveFrame(); |
| 1447 __ Bind(¬_stepping); | 1449 __ Bind(¬_stepping); |
| 1448 | 1450 |
| 1451 // ECX: IC data object (preserved). |
| 1449 // Load arguments descriptor into EDX. | 1452 // Load arguments descriptor into EDX. |
| 1450 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); | 1453 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); |
| 1451 // Loop that checks if there is an IC data match. | 1454 // Loop that checks if there is an IC data match. |
| 1452 Label loop, update, test, found, get_class_id_as_smi; | 1455 Label loop, update, test, found, get_class_id_as_smi; |
| 1453 // ECX: IC data object (preserved). | 1456 // ECX: IC data object (preserved). |
| 1454 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); | 1457 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); |
| 1455 // EBX: ic_data_array with check entries: classes and target functions. | 1458 // EBX: ic_data_array with check entries: classes and target functions. |
| 1456 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); | 1459 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); |
| 1457 // EBX: points directly to the first ic data array element. | 1460 // EBX: points directly to the first ic data array element. |
| 1458 | 1461 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1512 __ EnterStubFrame(); | 1515 __ EnterStubFrame(); |
| 1513 __ pushl(EDX); // Preserve arguments descriptor array. | 1516 __ pushl(EDX); // Preserve arguments descriptor array. |
| 1514 __ pushl(ECX); // Preserve IC data object. | 1517 __ pushl(ECX); // Preserve IC data object. |
| 1515 __ pushl(raw_null); // Setup space on stack for result (target code object). | 1518 __ pushl(raw_null); // Setup space on stack for result (target code object). |
| 1516 // Push call arguments. | 1519 // Push call arguments. |
| 1517 for (intptr_t i = 0; i < num_args; i++) { | 1520 for (intptr_t i = 0; i < num_args; i++) { |
| 1518 __ movl(EBX, Address(EAX, -kWordSize * i)); | 1521 __ movl(EBX, Address(EAX, -kWordSize * i)); |
| 1519 __ pushl(EBX); | 1522 __ pushl(EBX); |
| 1520 } | 1523 } |
| 1521 __ pushl(ECX); // Pass IC data object. | 1524 __ pushl(ECX); // Pass IC data object. |
| 1522 if (num_args == 1) { | 1525 __ CallRuntime(handle_ic_miss); |
| 1523 __ CallRuntime(kInlineCacheMissHandlerOneArgRuntimeEntry); | |
| 1524 } else if (num_args == 2) { | |
| 1525 __ CallRuntime(kInlineCacheMissHandlerTwoArgsRuntimeEntry); | |
| 1526 } else if (num_args == 3) { | |
| 1527 __ CallRuntime(kInlineCacheMissHandlerThreeArgsRuntimeEntry); | |
| 1528 } else { | |
| 1529 UNIMPLEMENTED(); | |
| 1530 } | |
| 1531 // Remove the call arguments pushed earlier, including the IC data object. | 1526 // Remove the call arguments pushed earlier, including the IC data object. |
| 1532 for (intptr_t i = 0; i < num_args + 1; i++) { | 1527 for (intptr_t i = 0; i < num_args + 1; i++) { |
| 1533 __ popl(EAX); | 1528 __ popl(EAX); |
| 1534 } | 1529 } |
| 1535 __ popl(EAX); // Pop returned code object into EAX (null if not found). | 1530 __ popl(EAX); // Pop returned code object into EAX (null if not found). |
| 1536 __ popl(ECX); // Restore IC data array. | 1531 __ popl(ECX); // Restore IC data array. |
| 1537 __ popl(EDX); // Restore arguments descriptor array. | 1532 __ popl(EDX); // Restore arguments descriptor array. |
| 1538 __ LeaveFrame(); | 1533 __ LeaveFrame(); |
| 1539 Label call_target_function; | 1534 Label call_target_function; |
| 1540 __ cmpl(EAX, raw_null); | 1535 __ cmpl(EAX, raw_null); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1583 // ECX: Inline cache data object. | 1578 // ECX: Inline cache data object. |
| 1584 // TOS(0): Return address. | 1579 // TOS(0): Return address. |
| 1585 // Inline cache data object structure: | 1580 // Inline cache data object structure: |
| 1586 // 0: function-name | 1581 // 0: function-name |
| 1587 // 1: N, number of arguments checked. | 1582 // 1: N, number of arguments checked. |
| 1588 // 2 .. (length - 1): group of checks, each check containing: | 1583 // 2 .. (length - 1): group of checks, each check containing: |
| 1589 // - N classes. | 1584 // - N classes. |
| 1590 // - 1 target function. | 1585 // - 1 target function. |
| 1591 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1586 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1592 GenerateUsageCounterIncrement(assembler, EBX); | 1587 GenerateUsageCounterIncrement(assembler, EBX); |
| 1593 GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1588 GenerateNArgsCheckInlineCacheStub( |
| 1589 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1594 } | 1590 } |
| 1595 | 1591 |
| 1596 | 1592 |
| 1597 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1593 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1598 GenerateUsageCounterIncrement(assembler, EBX); | 1594 GenerateUsageCounterIncrement(assembler, EBX); |
| 1599 GenerateNArgsCheckInlineCacheStub(assembler, 2); | 1595 GenerateNArgsCheckInlineCacheStub( |
| 1596 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); |
| 1600 } | 1597 } |
| 1601 | 1598 |
| 1602 | 1599 |
| 1603 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1600 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1604 GenerateUsageCounterIncrement(assembler, EBX); | 1601 GenerateUsageCounterIncrement(assembler, EBX); |
| 1605 GenerateNArgsCheckInlineCacheStub(assembler, 3); | 1602 GenerateNArgsCheckInlineCacheStub( |
| 1603 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); |
| 1606 } | 1604 } |
| 1607 | 1605 |
| 1608 | 1606 |
| 1609 // Use inline cache data array to invoke the target or continue in inline | 1607 // Use inline cache data array to invoke the target or continue in inline |
| 1610 // cache miss handler. Stub for 1-argument check (receiver class). | 1608 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1611 // EDI: function which counter needs to be incremented. | 1609 // EDI: function which counter needs to be incremented. |
| 1612 // ECX: Inline cache data object. | 1610 // ECX: Inline cache data object. |
| 1613 // TOS(0): Return address. | 1611 // TOS(0): Return address. |
| 1614 // Inline cache data object structure: | 1612 // Inline cache data object structure: |
| 1615 // 0: function-name | 1613 // 0: function-name |
| 1616 // 1: N, number of arguments checked. | 1614 // 1: N, number of arguments checked. |
| 1617 // 2 .. (length - 1): group of checks, each check containing: | 1615 // 2 .. (length - 1): group of checks, each check containing: |
| 1618 // - N classes. | 1616 // - N classes. |
| 1619 // - 1 target function. | 1617 // - 1 target function. |
| 1620 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1618 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1621 Assembler* assembler) { | 1619 Assembler* assembler) { |
| 1622 GenerateOptimizedUsageCounterIncrement(assembler); | 1620 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1623 GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1621 GenerateNArgsCheckInlineCacheStub( |
| 1622 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1624 } | 1623 } |
| 1625 | 1624 |
| 1626 | 1625 |
| 1627 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1626 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1628 Assembler* assembler) { | 1627 Assembler* assembler) { |
| 1629 GenerateOptimizedUsageCounterIncrement(assembler); | 1628 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1630 GenerateNArgsCheckInlineCacheStub(assembler, 2); | 1629 GenerateNArgsCheckInlineCacheStub( |
| 1630 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); |
| 1631 } | 1631 } |
| 1632 | 1632 |
| 1633 | 1633 |
| 1634 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( | 1634 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1635 Assembler* assembler) { | 1635 Assembler* assembler) { |
| 1636 GenerateOptimizedUsageCounterIncrement(assembler); | 1636 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1637 GenerateNArgsCheckInlineCacheStub(assembler, 3); | 1637 GenerateNArgsCheckInlineCacheStub( |
| 1638 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); |
| 1638 } | 1639 } |
| 1639 | 1640 |
| 1640 | 1641 |
| 1641 // Do not count as no type feedback is collected. | 1642 // Do not count as no type feedback is collected. |
| 1642 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { | 1643 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1643 GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1644 GenerateNArgsCheckInlineCacheStub( |
| 1645 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1644 } | 1646 } |
| 1645 | 1647 |
| 1646 | 1648 |
| 1647 // Megamorphic call is currently implemented as IC call but through a stub | 1649 // Megamorphic call is currently implemented as IC call but through a stub |
| 1648 // that does not check/count function invocations. | 1650 // that does not check/count function invocations. |
| 1649 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { | 1651 void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) { |
| 1650 GenerateNArgsCheckInlineCacheStub(assembler, 1); | 1652 GenerateNArgsCheckInlineCacheStub( |
| 1653 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1651 } | 1654 } |
| 1652 | 1655 |
| 1653 // Intermediary stub between a static call and its target. ICData contains | 1656 // Intermediary stub between a static call and its target. ICData contains |
| 1654 // the target function and the call count. | 1657 // the target function and the call count. |
| 1655 // ECX: ICData | 1658 // ECX: ICData |
| 1656 void StubCode::GenerateUnoptimizedStaticCallStub(Assembler* assembler) { | 1659 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1657 GenerateUsageCounterIncrement(assembler, EBX); | 1660 GenerateUsageCounterIncrement(assembler, EBX); |
| 1661 |
| 1658 #if defined(DEBUG) | 1662 #if defined(DEBUG) |
| 1659 { Label ok; | 1663 { Label ok; |
| 1660 // Check that the IC data array has NumberOfArgumentsChecked() == 0. | 1664 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. |
| 1661 // 'num_args_tested' is stored as an untagged int. | 1665 // 'num_args_tested' is stored as an untagged int. |
| 1662 __ movl(EBX, FieldAddress(ECX, ICData::num_args_tested_offset())); | 1666 __ movl(EBX, FieldAddress(ECX, ICData::num_args_tested_offset())); |
| 1663 __ cmpl(EBX, Immediate(0)); | 1667 __ cmpl(EBX, Immediate(0)); |
| 1664 __ j(EQUAL, &ok, Assembler::kNearJump); | 1668 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1665 __ Stop("Incorrect IC data for unoptimized static call"); | 1669 __ Stop("Incorrect IC data for unoptimized static call"); |
| 1666 __ Bind(&ok); | 1670 __ Bind(&ok); |
| 1667 } | 1671 } |
| 1668 #endif // DEBUG | 1672 #endif // DEBUG |
| 1669 | |
| 1670 // Check single stepping. | 1673 // Check single stepping. |
| 1671 Label not_stepping; | 1674 Label not_stepping; |
| 1672 __ movl(EAX, FieldAddress(CTX, Context::isolate_offset())); | 1675 __ movl(EAX, FieldAddress(CTX, Context::isolate_offset())); |
| 1673 __ movzxb(EAX, Address(EAX, Isolate::single_step_offset())); | 1676 __ movzxb(EAX, Address(EAX, Isolate::single_step_offset())); |
| 1674 __ cmpl(EAX, Immediate(0)); | 1677 __ cmpl(EAX, Immediate(0)); |
| 1675 __ j(EQUAL, ¬_stepping, Assembler::kNearJump); | 1678 __ j(EQUAL, ¬_stepping, Assembler::kNearJump); |
| 1676 | 1679 |
| 1677 __ EnterStubFrame(); | 1680 __ EnterStubFrame(); |
| 1678 __ pushl(ECX); | 1681 __ pushl(ECX); |
| 1679 __ CallRuntime(kSingleStepHandlerRuntimeEntry); | 1682 __ CallRuntime(kSingleStepHandlerRuntimeEntry); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1718 __ Bind(&target_is_compiled); | 1721 __ Bind(&target_is_compiled); |
| 1719 // EAX: Target code. | 1722 // EAX: Target code. |
| 1720 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); | 1723 __ movl(EAX, FieldAddress(EAX, Code::instructions_offset())); |
| 1721 __ addl(EAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); | 1724 __ addl(EAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| 1722 // Load arguments descriptor into EDX. | 1725 // Load arguments descriptor into EDX. |
| 1723 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); | 1726 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); |
| 1724 __ jmp(EAX); | 1727 __ jmp(EAX); |
| 1725 } | 1728 } |
| 1726 | 1729 |
| 1727 | 1730 |
| 1731 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1732 GenerateUsageCounterIncrement(assembler, EBX); |
| 1733 GenerateNArgsCheckInlineCacheStub( |
| 1734 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry); |
| 1735 } |
| 1736 |
| 1737 |
| 1728 // EDX, EXC: May contain arguments to runtime stub. | 1738 // EDX, EXC: May contain arguments to runtime stub. |
| 1729 void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) { | 1739 void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) { |
| 1730 __ EnterStubFrame(); | 1740 __ EnterStubFrame(); |
| 1731 // Save runtime args. | 1741 // Save runtime args. |
| 1732 __ pushl(ECX); | 1742 __ pushl(ECX); |
| 1733 __ pushl(EDX); | 1743 __ pushl(EDX); |
| 1734 // Room for result. Debugger stub returns address of the | 1744 // Room for result. Debugger stub returns address of the |
| 1735 // unpatched runtime stub. | 1745 // unpatched runtime stub. |
| 1736 const Immediate& raw_null = | 1746 const Immediate& raw_null = |
| 1737 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1747 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| (...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2201 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); | 2211 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
| 2202 __ popl(temp); | 2212 __ popl(temp); |
| 2203 __ popl(right); | 2213 __ popl(right); |
| 2204 __ popl(left); | 2214 __ popl(left); |
| 2205 __ ret(); | 2215 __ ret(); |
| 2206 } | 2216 } |
| 2207 | 2217 |
| 2208 } // namespace dart | 2218 } // namespace dart |
| 2209 | 2219 |
| 2210 #endif // defined TARGET_ARCH_IA32 | 2220 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |