Chromium Code Reviews| 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" |
| (...skipping 1519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1530 // TOS(0): return address | 1530 // TOS(0): return address |
| 1531 // Control flow: | 1531 // Control flow: |
| 1532 // - If receiver is null -> jump to IC miss. | 1532 // - If receiver is null -> jump to IC miss. |
| 1533 // - If receiver is Smi -> load Smi class. | 1533 // - If receiver is Smi -> load Smi class. |
| 1534 // - If receiver is not-Smi -> load receiver's class. | 1534 // - If receiver is not-Smi -> load receiver's class. |
| 1535 // - Check if 'num_args' (including receiver) match any IC data group. | 1535 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1536 // - Match found -> jump to target. | 1536 // - Match found -> jump to target. |
| 1537 // - Match not found -> jump to IC miss. | 1537 // - Match not found -> jump to IC miss. |
| 1538 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, | 1538 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, |
| 1539 intptr_t num_args) { | 1539 intptr_t num_args) { |
| 1540 ASSERT(num_args > 0); | |
| 1541 #if defined(DEBUG) | |
| 1542 { Label ok; | |
| 1543 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. | |
| 1544 // 'num_args_tested' is stored as an untagged int. | |
| 1545 __ movq(RCX, FieldAddress(RBX, ICData::num_args_tested_offset())); | |
| 1546 __ cmpq(RCX, Immediate(num_args)); | |
| 1547 __ j(EQUAL, &ok, Assembler::kNearJump); | |
| 1548 __ Stop("Incorrect stub for IC data"); | |
| 1549 __ Bind(&ok); | |
| 1550 } | |
| 1551 #endif // DEBUG | |
| 1552 | |
| 1540 __ movq(RCX, FieldAddress(RBX, ICData::function_offset())); | 1553 __ movq(RCX, FieldAddress(RBX, ICData::function_offset())); |
| 1541 Label is_hot; | 1554 Label is_hot; |
| 1542 if (FlowGraphCompiler::CanOptimize()) { | 1555 if (FlowGraphCompiler::CanOptimize()) { |
| 1543 ASSERT(FLAG_optimization_counter_threshold > 1); | 1556 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1544 // The usage_counter is always less than FLAG_optimization_counter_threshold | 1557 // The usage_counter is always less than FLAG_optimization_counter_threshold |
| 1545 // except when the function gets optimized. | 1558 // except when the function gets optimized. |
| 1546 __ cmpq(FieldAddress(RCX, Function::usage_counter_offset()), | 1559 __ cmpq(FieldAddress(RCX, Function::usage_counter_offset()), |
| 1547 Immediate(FLAG_optimization_counter_threshold - 1)); | 1560 Immediate(FLAG_optimization_counter_threshold - 1)); |
| 1548 // Do not increment to equality with threshold, since a counter greater | 1561 // Do not increment to equality with threshold, since a counter greater |
| 1549 // than threshold denotes a function that was already optimized. | 1562 // than threshold denotes a function that was already optimized. |
| 1550 // The equality should be reached only at exit of the method | 1563 // The equality should be reached only at exit of the method |
| 1551 // (return instruction). | 1564 // (return instruction). |
| 1552 __ j(EQUAL, &is_hot, Assembler::kNearJump); | 1565 __ j(EQUAL, &is_hot, Assembler::kNearJump); |
| 1553 // As long as VM has no OSR do not optimize in the middle of the function | 1566 // 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 | 1567 // but only at exit so that we have collected all type feedback before |
| 1555 // optimizing. | 1568 // optimizing. |
| 1556 } | 1569 } |
| 1557 __ incq(FieldAddress(RCX, Function::usage_counter_offset())); | 1570 __ incq(FieldAddress(RCX, Function::usage_counter_offset())); |
| 1558 __ Bind(&is_hot); | 1571 __ Bind(&is_hot); |
| 1559 | 1572 |
| 1560 ASSERT(num_args > 0); | |
| 1561 // Get receiver (first read number of arguments from argument descriptor array | |
| 1562 // and then access the receiver from the stack). | |
| 1563 __ movq(RAX, FieldAddress(R10, Array::data_offset())); | |
| 1564 __ movq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX (argument count) is Smi. | |
| 1565 | |
| 1566 Label get_class_id_as_smi, ic_miss; | |
| 1567 // RBX: IC data array. | |
| 1568 | |
| 1569 #if defined(DEBUG) | |
| 1570 { Label ok; | |
| 1571 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. | |
| 1572 // 'num_args_tested' is stored as an untagged int. | |
| 1573 __ movq(RCX, FieldAddress(RBX, ICData::num_args_tested_offset())); | |
| 1574 __ cmpq(RCX, Immediate(num_args)); | |
| 1575 __ j(EQUAL, &ok, Assembler::kNearJump); | |
| 1576 __ Stop("Incorrect stub for IC data"); | |
| 1577 __ Bind(&ok); | |
| 1578 } | |
| 1579 #endif // DEBUG | |
| 1580 | |
| 1581 // Loop that checks if there is an IC data match. | 1573 // Loop that checks if there is an IC data match. |
| 1574 Label loop, update, test, found, get_class_id_as_smi; | |
| 1582 // RBX: IC data object (preserved). | 1575 // RBX: IC data object (preserved). |
| 1583 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset())); | 1576 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset())); |
| 1584 // R12: ic_data_array with check entries: classes and target functions. | 1577 // R12: ic_data_array with check entries: classes and target functions. |
| 1585 __ leaq(R12, FieldAddress(R12, Array::data_offset())); | 1578 __ leaq(R12, FieldAddress(R12, Array::data_offset())); |
| 1586 // R12: points directly to the first ic data array element. | 1579 // R12: points directly to the first ic data array element. |
| 1587 const Immediate raw_null = | 1580 |
| 1588 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1581 // Get the receiver's class ID (first read number of arguments from |
| 1589 Label loop, found; | 1582 // argument descriptor array and then access the receiver from the stack). |
| 1590 if (num_args == 1) { | 1583 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 1591 __ call(&get_class_id_as_smi); | 1584 __ movq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX (argument count) is Smi. |
| 1592 // RAX: receiver's class id as Smi. | 1585 __ call(&get_class_id_as_smi); |
| 1593 __ Bind(&loop); | 1586 // RAX: receiver's class ID as smi. |
| 1594 __ movq(R13, Address(R12, 0)); // Get class if (Smi) to check. | 1587 __ movq(R13, Address(R12, 0)); // First class ID (Smi) to check. |
| 1595 __ cmpq(RAX, R13); // Match? | 1588 __ jmp(&test); |
| 1596 __ j(EQUAL, &found, Assembler::kNearJump); | 1589 |
| 1597 __ addq(R12, Immediate(kWordSize * 2)); // Next element (class + target). | 1590 __ Bind(&loop); |
| 1598 __ cmpq(R13, Immediate(Smi::RawValue(kIllegalCid))); // Done? | 1591 for (int i = 0; i < num_args; i++) { |
| 1599 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); | 1592 if (i > 0) { |
| 1600 } else { | 1593 // If not the first, load the next argument's class ID. |
| 1601 Label no_match; | |
| 1602 __ Bind(&loop); | |
| 1603 for (int i = 0; i < num_args; i++) { | |
| 1604 __ movq(RAX, FieldAddress(R10, Array::data_offset())); | 1594 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 1605 __ movq(RAX, Address(RSP, RAX, TIMES_4, - i * kWordSize)); | 1595 __ movq(RAX, Address(RSP, RAX, TIMES_4, - i * kWordSize)); |
| 1606 __ call(&get_class_id_as_smi); | 1596 __ call(&get_class_id_as_smi); |
| 1597 // RAX: next argument class ID (smi). | |
| 1607 __ movq(R13, Address(R12, i * kWordSize)); | 1598 __ movq(R13, Address(R12, i * kWordSize)); |
| 1608 __ cmpq(RAX, R13); // Class id match? | 1599 // R13: next class ID to check (smi). |
| 1609 if (i < (num_args - 1)) { | |
| 1610 __ j(NOT_EQUAL, &no_match); | |
| 1611 } else { | |
| 1612 // Last check, all checks before matched. | |
| 1613 __ j(EQUAL, &found); | |
| 1614 } | |
| 1615 } | 1600 } |
| 1616 __ Bind(&no_match); | 1601 __ cmpq(RAX, R13); // Class id match? |
| 1617 // Each test entry has (1 + num_args) array elements. | 1602 if (i < (num_args - 1)) { |
| 1618 __ addq(R12, Immediate(kWordSize * (1 + num_args))); // Next element. | 1603 __ j(NOT_EQUAL, &update); // Continue. |
| 1619 __ cmpq(R13, Immediate(Smi::RawValue(kIllegalCid))); // Done? | 1604 } else { |
| 1620 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); | 1605 // Last check, all checks before matched. |
| 1606 __ j(EQUAL, &found); // Break. | |
| 1607 } | |
| 1621 } | 1608 } |
| 1609 __ Bind(&update); | |
| 1610 // Reload receiver class ID. It has not been destroyed when num_args == 1. | |
| 1611 if (num_args > 1) { | |
| 1612 __ movq(RAX, FieldAddress(R10, Array::data_offset())); | |
|
Florian Schneider
2012/10/25 12:41:31
Could you keep FieldAddress(R10, Array::data_offse
| |
| 1613 __ movq(RAX, Address(RSP, RAX, TIMES_4, 0)); | |
| 1614 __ call(&get_class_id_as_smi); | |
| 1615 } | |
| 1616 // Each test entry has (1 + num_args) array elements. | |
| 1617 const intptr_t entry_size = (num_args + 1) * kWordSize; | |
| 1618 __ addq(R12, Immediate(entry_size)); // Next entry. | |
| 1619 __ movq(R13, Address(R12, 0)); // Next class ID. | |
| 1622 | 1620 |
| 1623 __ Bind(&ic_miss); | 1621 __ Bind(&test); |
| 1624 // Compute address of arguments (first read number of arguments from argument | 1622 __ cmpq(R13, Immediate(Smi::RawValue(kIllegalCid))); // Done? |
| 1625 // descriptor array and then compute address on the stack). | 1623 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 1624 | |
| 1625 // IC miss. | |
| 1626 const Immediate raw_null = | |
| 1627 Immediate(reinterpret_cast<intptr_t>(Object::null())); | |
| 1628 // Compute address of arguments (first read number of arguments from | |
| 1629 // argument descriptor array and then compute address on the stack). | |
| 1626 __ movq(RAX, FieldAddress(R10, Array::data_offset())); | 1630 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 1627 __ leaq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi. | 1631 __ leaq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi. |
| 1628 AssemblerMacros::EnterStubFrame(assembler); | 1632 AssemblerMacros::EnterStubFrame(assembler); |
| 1629 __ pushq(R10); // Preserve arguments array. | 1633 __ pushq(R10); // Preserve arguments array. |
| 1630 __ pushq(RBX); // Preserve IC data array | 1634 __ pushq(RBX); // Preserve IC data array |
| 1631 __ pushq(raw_null); // Setup space on stack for result (target code object). | 1635 __ pushq(raw_null); // Setup space on stack for result (target code object). |
| 1632 // Push call arguments. | 1636 // Push call arguments. |
| 1633 for (intptr_t i = 0; i < num_args; i++) { | 1637 for (intptr_t i = 0; i < num_args; i++) { |
| 1634 __ movq(R10, Address(RAX, -kWordSize * i)); | 1638 __ movq(R10, Address(RAX, -kWordSize * i)); |
| 1635 __ pushq(R10); | 1639 __ pushq(R10); |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2013 __ CallRuntime(kUpdateICDataTwoArgsRuntimeEntry); | 2017 __ CallRuntime(kUpdateICDataTwoArgsRuntimeEntry); |
| 2014 __ Drop(4); | 2018 __ Drop(4); |
| 2015 __ LeaveFrame(); | 2019 __ LeaveFrame(); |
| 2016 | 2020 |
| 2017 __ jmp(&compute_result, Assembler::kNearJump); | 2021 __ jmp(&compute_result, Assembler::kNearJump); |
| 2018 } | 2022 } |
| 2019 | 2023 |
| 2020 } // namespace dart | 2024 } // namespace dart |
| 2021 | 2025 |
| 2022 #endif // defined TARGET_ARCH_X64 | 2026 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |