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" // Needed here to get TARGET_ARCH_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
7 | 7 |
8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
9 | 9 |
10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
(...skipping 1239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1250 const Array& arguments_descriptor = | 1250 const Array& arguments_descriptor = |
1251 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1251 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
1252 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1252 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
1253 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( | 1253 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
1254 zone(), | 1254 zone(), |
1255 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); | 1255 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); |
1256 | 1256 |
1257 __ Comment("MegamorphicCall"); | 1257 __ Comment("MegamorphicCall"); |
1258 // Load receiver into T0, | 1258 // Load receiver into T0, |
1259 __ lw(T0, Address(SP, (argument_count - 1) * kWordSize)); | 1259 __ lw(T0, Address(SP, (argument_count - 1) * kWordSize)); |
1260 Label done; | |
1261 if (ShouldInlineSmiStringHashCode(ic_data)) { | |
1262 Label megamorphic_call; | |
1263 __ Comment("Inlined get:hashCode for Smi and OneByteString"); | |
1264 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); | |
1265 __ beq(CMPRES1, ZR, &done); // Is Smi. | |
1266 __ delay_slot()->mov(V0, T0); // Move Smi hashcode to V0. | |
1267 | |
1268 __ LoadClassId(CMPRES1, T0); // Class ID check. | |
1269 __ BranchNotEqual(CMPRES1, Immediate(kOneByteStringCid), &megamorphic_call); | |
1270 | |
1271 __ lw(V0, FieldAddress(T0, String::hash_offset())); | |
1272 __ bne(V0, ZR, &done); | |
1273 | |
1274 __ Bind(&megamorphic_call); | |
1275 __ Comment("Slow case: megamorphic call"); | |
1276 } | |
1277 __ LoadObject(S5, cache); | 1260 __ LoadObject(S5, cache); |
1278 __ lw(T9, Address(THR, Thread::megamorphic_call_checked_entry_offset())); | 1261 __ lw(T9, Address(THR, Thread::megamorphic_call_checked_entry_offset())); |
1279 __ jalr(T9); | 1262 __ jalr(T9); |
1280 | 1263 |
1281 __ Bind(&done); | |
1282 RecordSafepoint(locs, slow_path_argument_count); | 1264 RecordSafepoint(locs, slow_path_argument_count); |
1283 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1265 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1284 if (FLAG_precompiled_mode) { | 1266 if (FLAG_precompiled_mode) { |
1285 // Megamorphic calls may occur in slow path stubs. | 1267 // Megamorphic calls may occur in slow path stubs. |
1286 // If valid use try_index argument. | 1268 // If valid use try_index argument. |
1287 if (try_index == CatchClauseNode::kInvalidTryIndex) { | 1269 if (try_index == CatchClauseNode::kInvalidTryIndex) { |
1288 try_index = CurrentTryIndex(); | 1270 try_index = CurrentTryIndex(); |
1289 } | 1271 } |
1290 AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(), | 1272 AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(), |
1291 Thread::kNoDeoptId, token_pos, try_index); | 1273 Thread::kNoDeoptId, token_pos, try_index); |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1540 | 1522 |
1541 | 1523 |
1542 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 1524 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
1543 intptr_t argument_count, | 1525 intptr_t argument_count, |
1544 const Array& argument_names, | 1526 const Array& argument_names, |
1545 Label* failed, | 1527 Label* failed, |
1546 Label* match_found, | 1528 Label* match_found, |
1547 intptr_t deopt_id, | 1529 intptr_t deopt_id, |
1548 TokenPosition token_index, | 1530 TokenPosition token_index, |
1549 LocationSummary* locs, | 1531 LocationSummary* locs, |
1550 bool complete) { | 1532 bool complete, |
| 1533 intptr_t total_ic_calls) { |
1551 ASSERT(is_optimizing()); | 1534 ASSERT(is_optimizing()); |
1552 __ Comment("EmitTestAndCall"); | 1535 __ Comment("EmitTestAndCall"); |
1553 const Array& arguments_descriptor = Array::ZoneHandle( | 1536 const Array& arguments_descriptor = Array::ZoneHandle( |
1554 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); | 1537 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); |
1555 | 1538 |
1556 // Load receiver into T0. | 1539 // Load receiver into T0. |
1557 __ LoadFromOffset(T0, SP, (argument_count - 1) * kWordSize); | 1540 __ LoadFromOffset(T0, SP, (argument_count - 1) * kWordSize); |
1558 __ LoadObject(S4, arguments_descriptor); | 1541 __ LoadObject(S4, arguments_descriptor); |
1559 | 1542 |
1560 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1543 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
(...skipping 25 matching lines...) Expand all Loading... |
1586 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1569 // Receiver is Smi, but Smi is not a valid class therefore fail. |
1587 // (Smi class must be first in the list). | 1570 // (Smi class must be first in the list). |
1588 if (!complete) { | 1571 if (!complete) { |
1589 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); | 1572 __ andi(CMPRES1, T0, Immediate(kSmiTagMask)); |
1590 __ beq(CMPRES1, ZR, failed); | 1573 __ beq(CMPRES1, ZR, failed); |
1591 } | 1574 } |
1592 } | 1575 } |
1593 | 1576 |
1594 __ Bind(&after_smi_test); | 1577 __ Bind(&after_smi_test); |
1595 | 1578 |
1596 GrowableArray<CidTarget> sorted(num_checks); | 1579 ASSERT(!ic_data.IsNull() && (num_checks > 0)); |
| 1580 GrowableArray<CidRangeTarget> sorted(num_checks); |
1597 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true); | 1581 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true); |
1598 | 1582 |
| 1583 const intptr_t sorted_len = sorted.length(); |
| 1584 // If sorted_len is 0 then only a Smi check was needed; the Smi check above |
| 1585 // will fail if there was only one check and receiver is not Smi. |
| 1586 if (sorted_len == 0) return; |
| 1587 |
1599 // Value is not Smi, | 1588 // Value is not Smi, |
1600 const intptr_t kSortedLen = sorted.length(); | 1589 __ LoadClassId(T2, T0); |
1601 // If kSortedLen is 0 then only a Smi check was needed; the Smi check above | |
1602 // will fail if there was only one check and receiver is not Smi. | |
1603 if (kSortedLen == 0) return; | |
1604 | 1590 |
1605 __ LoadClassId(T2, T0); | 1591 bool add_megamorphic_call = false; |
1606 for (intptr_t i = 0; i < kSortedLen; i++) { | 1592 int bias = 0; |
1607 const bool kIsLastCheck = (i == (kSortedLen - 1)); | 1593 |
1608 ASSERT(sorted[i].cid != kSmiCid); | 1594 for (intptr_t i = 0; i < sorted_len; i++) { |
| 1595 const bool is_last_check = (i == (sorted_len - 1)); |
| 1596 int cid_start = sorted[i].cid_start; |
| 1597 int cid_end = sorted[i].cid_end; |
| 1598 int count = sorted[i].count; |
| 1599 if (!is_last_check && !complete && count < (total_ic_calls >> 5)) { |
| 1600 // This case is hit too rarely to be worth writing class-id checks inline |
| 1601 // for. |
| 1602 add_megamorphic_call = true; |
| 1603 break; |
| 1604 } |
| 1605 ASSERT(cid_start > kSmiCid || cid_end < kSmiCid); |
1609 Label next_test; | 1606 Label next_test; |
1610 if (!complete) { | 1607 Condition no_match; |
1611 if (kIsLastCheck) { | 1608 if (!complete || !is_last_check) { |
1612 __ BranchNotEqual(T2, Immediate(sorted[i].cid), failed); | 1609 Label* next_label = is_last_check ? failed : &next_test; |
| 1610 if (cid_start == cid_end) { |
| 1611 __ BranchNotEqual(T2, Immediate(cid_start - bias), next_label); |
1613 } else { | 1612 } else { |
1614 __ BranchNotEqual(T2, Immediate(sorted[i].cid), &next_test); | 1613 __ AddImmediate(T2, T2, bias - cid_start); |
1615 } | 1614 bias = cid_start; |
1616 } else { | 1615 // TODO(erikcorry): We should use sltiu instead of the temporary TMP if |
1617 if (!kIsLastCheck) { | 1616 // the range is small enough. |
1618 __ BranchNotEqual(T2, Immediate(sorted[i].cid), &next_test); | 1617 __ LoadImmediate(TMP, cid_end - cid_end); |
| 1618 // Reverse comparison so we get 1 if biased cid > tmp ie cid is out of |
| 1619 // range. |
| 1620 __ sltu(TMP, TMP, T2); |
| 1621 __ bne(TMP, ZR, next_label); |
1619 } | 1622 } |
1620 } | 1623 } |
1621 // Do not use the code from the function, but let the code be patched so | 1624 // Do not use the code from the function, but let the code be patched so |
1622 // that we can record the outgoing edges to other code. | 1625 // that we can record the outgoing edges to other code. |
1623 const Function& function = *sorted[i].target; | 1626 const Function& function = *sorted[i].target; |
1624 GenerateStaticDartCall(deopt_id, token_index, | 1627 GenerateStaticDartCall(deopt_id, token_index, |
1625 *StubCode::CallStaticFunction_entry(), | 1628 *StubCode::CallStaticFunction_entry(), |
1626 RawPcDescriptors::kOther, locs, function); | 1629 RawPcDescriptors::kOther, locs, function); |
1627 __ Drop(argument_count); | 1630 __ Drop(argument_count); |
1628 if (!kIsLastCheck) { | 1631 if (!is_last_check) { |
1629 __ b(match_found); | 1632 __ b(match_found); |
1630 } | 1633 } |
1631 __ Bind(&next_test); | 1634 __ Bind(&next_test); |
1632 } | 1635 } |
| 1636 if (add_megamorphic_call) { |
| 1637 int try_index = CatchClauseNode::kInvalidTryIndex; |
| 1638 EmitMegamorphicInstanceCall(ic_data, argument_count, deopt_id, token_index, |
| 1639 locs, try_index, argument_count); |
| 1640 } |
1633 } | 1641 } |
1634 | 1642 |
1635 | 1643 |
1636 #undef __ | 1644 #undef __ |
1637 #define __ compiler_->assembler()-> | 1645 #define __ compiler_->assembler()-> |
1638 | 1646 |
1639 | 1647 |
1640 void ParallelMoveResolver::EmitMove(int index) { | 1648 void ParallelMoveResolver::EmitMove(int index) { |
1641 MoveOperands* move = moves_[index]; | 1649 MoveOperands* move = moves_[index]; |
1642 const Location source = move->src(); | 1650 const Location source = move->src(); |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1869 __ AddImmediate(SP, kDoubleSize); | 1877 __ AddImmediate(SP, kDoubleSize); |
1870 } | 1878 } |
1871 | 1879 |
1872 | 1880 |
1873 #undef __ | 1881 #undef __ |
1874 | 1882 |
1875 | 1883 |
1876 } // namespace dart | 1884 } // namespace dart |
1877 | 1885 |
1878 #endif // defined TARGET_ARCH_MIPS | 1886 #endif // defined TARGET_ARCH_MIPS |
OLD | NEW |