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_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
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 1229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1240 const Array& arguments_descriptor = | 1240 const Array& arguments_descriptor = |
1241 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1241 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
1242 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1242 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
1243 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( | 1243 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
1244 zone(), | 1244 zone(), |
1245 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); | 1245 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); |
1246 | 1246 |
1247 __ Comment("MegamorphicCall"); | 1247 __ Comment("MegamorphicCall"); |
1248 // Load receiver into R0. | 1248 // Load receiver into R0. |
1249 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); | 1249 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); |
1250 Label done; | |
1251 if (ShouldInlineSmiStringHashCode(ic_data)) { | |
1252 Label megamorphic_call; | |
1253 __ Comment("Inlined get:hashCode for Smi and OneByteString"); | |
1254 __ tst(R0, Operand(kSmiTagMask)); | |
1255 __ b(&done, EQ); // Is Smi (result is receiver). | |
1256 | |
1257 // Use R9 (cache for megamorphic call) as scratch. | |
1258 __ CompareClassId(R0, kOneByteStringCid, R9); | |
1259 __ b(&megamorphic_call, NE); | |
1260 | |
1261 __ mov(R9, Operand(R0)); // Preserve receiver in R9. | |
1262 __ ldr(R0, FieldAddress(R0, String::hash_offset())); | |
1263 ASSERT(Smi::New(0) == 0); | |
1264 __ cmp(R0, Operand(0)); | |
1265 | |
1266 __ b(&done, NE); // Return if already computed. | |
1267 __ mov(R0, Operand(R9)); // Restore receiver in R0. | |
1268 | |
1269 __ Bind(&megamorphic_call); | |
1270 __ Comment("Slow case: megamorphic call"); | |
1271 } | |
1272 __ LoadObject(R9, cache); | 1250 __ LoadObject(R9, cache); |
1273 __ ldr(LR, Address(THR, Thread::megamorphic_call_checked_entry_offset())); | 1251 __ ldr(LR, Address(THR, Thread::megamorphic_call_checked_entry_offset())); |
1274 __ blx(LR); | 1252 __ blx(LR); |
1275 | 1253 |
1276 __ Bind(&done); | |
1277 RecordSafepoint(locs, slow_path_argument_count); | 1254 RecordSafepoint(locs, slow_path_argument_count); |
1278 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1255 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1279 if (FLAG_precompiled_mode) { | 1256 if (FLAG_precompiled_mode) { |
1280 // Megamorphic calls may occur in slow path stubs. | 1257 // Megamorphic calls may occur in slow path stubs. |
1281 // If valid use try_index argument. | 1258 // If valid use try_index argument. |
1282 if (try_index == CatchClauseNode::kInvalidTryIndex) { | 1259 if (try_index == CatchClauseNode::kInvalidTryIndex) { |
1283 try_index = CurrentTryIndex(); | 1260 try_index = CurrentTryIndex(); |
1284 } | 1261 } |
1285 AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(), | 1262 AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(), |
1286 Thread::kNoDeoptId, token_pos, try_index); | 1263 Thread::kNoDeoptId, token_pos, try_index); |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1519 | 1496 |
1520 | 1497 |
1521 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 1498 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
1522 intptr_t argument_count, | 1499 intptr_t argument_count, |
1523 const Array& argument_names, | 1500 const Array& argument_names, |
1524 Label* failed, | 1501 Label* failed, |
1525 Label* match_found, | 1502 Label* match_found, |
1526 intptr_t deopt_id, | 1503 intptr_t deopt_id, |
1527 TokenPosition token_index, | 1504 TokenPosition token_index, |
1528 LocationSummary* locs, | 1505 LocationSummary* locs, |
1529 bool complete) { | 1506 bool complete, |
1507 intptr_t total_ic_calls) { | |
1530 ASSERT(is_optimizing()); | 1508 ASSERT(is_optimizing()); |
1531 __ Comment("EmitTestAndCall"); | 1509 __ Comment("EmitTestAndCall"); |
1532 const Array& arguments_descriptor = Array::ZoneHandle( | 1510 const Array& arguments_descriptor = Array::ZoneHandle( |
1533 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); | 1511 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); |
1534 | 1512 |
1535 // Load receiver into R0. | 1513 // Load receiver into R0. |
1536 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); | 1514 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); |
1537 __ LoadObject(R4, arguments_descriptor); | 1515 __ LoadObject(R4, arguments_descriptor); |
1538 | 1516 |
1539 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1517 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
(...skipping 25 matching lines...) Expand all Loading... | |
1565 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1543 // Receiver is Smi, but Smi is not a valid class therefore fail. |
1566 // (Smi class must be first in the list). | 1544 // (Smi class must be first in the list). |
1567 if (!complete) { | 1545 if (!complete) { |
1568 __ tst(R0, Operand(kSmiTagMask)); | 1546 __ tst(R0, Operand(kSmiTagMask)); |
1569 __ b(failed, EQ); | 1547 __ b(failed, EQ); |
1570 } | 1548 } |
1571 } | 1549 } |
1572 __ Bind(&after_smi_test); | 1550 __ Bind(&after_smi_test); |
1573 | 1551 |
1574 ASSERT(!ic_data.IsNull() && (num_checks > 0)); | 1552 ASSERT(!ic_data.IsNull() && (num_checks > 0)); |
1575 GrowableArray<CidTarget> sorted(num_checks); | 1553 GrowableArray<CidRangeTarget> sorted(num_checks); |
1576 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true); | 1554 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true); |
1577 | 1555 |
1556 const intptr_t sorted_len = sorted.length(); | |
1557 // If sorted_len is 0 then only a Smi check was needed; the Smi check above | |
1558 // will fail if there was only one check and receiver is not Smi. | |
1559 if (sorted_len == 0) return; | |
1560 | |
1578 // Value is not Smi, | 1561 // Value is not Smi, |
1579 const intptr_t kSortedLen = sorted.length(); | 1562 __ LoadClassId(R2, R0); |
1580 // If kSortedLen is 0 then only a Smi check was needed; the Smi check above | |
1581 // will fail if there was only one check and receiver is not Smi. | |
1582 if (kSortedLen == 0) return; | |
1583 | 1563 |
1584 __ LoadClassId(R2, R0); | 1564 bool add_megamorphic_call = false; |
1585 for (intptr_t i = 0; i < kSortedLen; i++) { | 1565 int bias = GetGoodBias(sorted, 256); |
1586 const bool kIsLastCheck = (i == (kSortedLen - 1)); | 1566 if (bias != 0) __ AddImmediate(R2, R2, -bias); |
1587 ASSERT(sorted[i].cid != kSmiCid); | 1567 |
1568 for (intptr_t i = 0; i < sorted_len; i++) { | |
1569 const bool is_last_check = (i == (sorted_len - 1)); | |
1570 int cid_start = sorted[i].cid_start; | |
1571 int cid_end = sorted[i].cid_end; | |
1572 int count = sorted[i].count; | |
1573 if (!is_last_check && !complete && count < (total_ic_calls >> 5)) { | |
Vyacheslav Egorov (Google)
2017/03/10 10:31:30
Magic constants!
This is a suspect optimization b
erikcorry
2017/03/10 13:30:01
Previous behaviour:
* If there are only a few cid
| |
1574 // This case is hit too rarely to be worth writing class-id checks inline | |
1575 // for. | |
1576 add_megamorphic_call = true; | |
1577 break; | |
1578 } | |
1579 ASSERT(cid_start > kSmiCid || cid_end < kSmiCid); | |
1588 Label next_test; | 1580 Label next_test; |
1589 if (!complete) { | 1581 if (!complete || !is_last_check) { |
1590 __ CompareImmediate(R2, sorted[i].cid); | 1582 Label* next_label = is_last_check ? failed : &next_test; |
1591 if (kIsLastCheck) { | 1583 if (cid_start == cid_end) { |
1592 __ b(failed, NE); | 1584 __ CompareImmediate(R2, cid_start - bias); |
1585 __ b(next_label, NE); | |
1593 } else { | 1586 } else { |
1594 __ b(&next_test, NE); | 1587 __ AddImmediate(R2, R2, bias - cid_start); |
1595 } | 1588 bias = cid_start; |
1596 } else { | 1589 __ CompareImmediate(R2, cid_end - cid_start); |
1597 if (!kIsLastCheck) { | 1590 __ b(next_label, HI); // Unsigned higher. |
1598 __ CompareImmediate(R2, sorted[i].cid); | |
1599 __ b(&next_test, NE); | |
1600 } | 1591 } |
1601 } | 1592 } |
1602 // Do not use the code from the function, but let the code be patched so | 1593 // Do not use the code from the function, but let the code be patched so |
1603 // that we can record the outgoing edges to other code. | 1594 // that we can record the outgoing edges to other code. |
1604 const Function& function = *sorted[i].target; | 1595 const Function& function = *sorted[i].target; |
1605 GenerateStaticDartCall(deopt_id, token_index, | 1596 GenerateStaticDartCall(deopt_id, token_index, |
1606 *StubCode::CallStaticFunction_entry(), | 1597 *StubCode::CallStaticFunction_entry(), |
1607 RawPcDescriptors::kOther, locs, function); | 1598 RawPcDescriptors::kOther, locs, function); |
1608 __ Drop(argument_count); | 1599 __ Drop(argument_count); |
1609 if (!kIsLastCheck) { | 1600 if (!is_last_check) { |
1610 __ b(match_found); | 1601 __ b(match_found); |
1611 } | 1602 } |
1612 __ Bind(&next_test); | 1603 __ Bind(&next_test); |
1613 } | 1604 } |
1605 if (add_megamorphic_call) { | |
1606 int try_index = CatchClauseNode::kInvalidTryIndex; | |
1607 EmitMegamorphicInstanceCall(ic_data, argument_count, deopt_id, token_index, | |
1608 locs, try_index, argument_count); | |
1609 } | |
1614 } | 1610 } |
1615 | 1611 |
1616 | 1612 |
1617 #undef __ | 1613 #undef __ |
1618 #define __ compiler_->assembler()-> | 1614 #define __ compiler_->assembler()-> |
1619 | 1615 |
1620 | 1616 |
1621 void ParallelMoveResolver::EmitMove(int index) { | 1617 void ParallelMoveResolver::EmitMove(int index) { |
1622 MoveOperands* move = moves_[index]; | 1618 MoveOperands* move = moves_[index]; |
1623 const Location source = move->src(); | 1619 const Location source = move->src(); |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1906 DRegister dreg = EvenDRegisterOf(reg); | 1902 DRegister dreg = EvenDRegisterOf(reg); |
1907 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); | 1903 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); |
1908 } | 1904 } |
1909 | 1905 |
1910 | 1906 |
1911 #undef __ | 1907 #undef __ |
1912 | 1908 |
1913 } // namespace dart | 1909 } // namespace dart |
1914 | 1910 |
1915 #endif // defined TARGET_ARCH_ARM | 1911 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |