OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
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 1218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1229 const Array& arguments_descriptor = | 1229 const Array& arguments_descriptor = |
1230 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1230 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
1231 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1231 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
1232 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( | 1232 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
1233 zone(), | 1233 zone(), |
1234 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); | 1234 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); |
1235 | 1235 |
1236 __ Comment("MegamorphicCall"); | 1236 __ Comment("MegamorphicCall"); |
1237 // Load receiver into R0. | 1237 // Load receiver into R0. |
1238 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); | 1238 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); |
1239 Label done; | |
1240 if (ShouldInlineSmiStringHashCode(ic_data)) { | |
1241 Label megamorphic_call; | |
1242 __ Comment("Inlined get:hashCode for Smi and OneByteString"); | |
1243 __ tsti(R0, Immediate(kSmiTagMask)); | |
1244 __ b(&done, EQ); // Is Smi (result is receiver). | |
1245 | |
1246 __ CompareClassId(R0, kOneByteStringCid); | |
1247 __ b(&megamorphic_call, NE); | |
1248 | |
1249 // Use R5 (cache for megamorphic call) as scratch. | |
1250 __ mov(R5, R0); // Preserve receiver in R5, result in R0. | |
1251 __ ldr(R0, FieldAddress(R0, String::hash_offset())); | |
1252 __ CompareRegisters(R0, ZR); | |
1253 __ b(&done, NE); | |
1254 __ mov(R0, R5); // Restore receiver in R0, | |
1255 | |
1256 __ Bind(&megamorphic_call); | |
1257 __ Comment("Slow case: megamorphic call"); | |
1258 } | |
1259 | 1239 |
1260 __ LoadObject(R5, cache); | 1240 __ LoadObject(R5, cache); |
1261 __ ldr(LR, Address(THR, Thread::megamorphic_call_checked_entry_offset())); | 1241 __ ldr(LR, Address(THR, Thread::megamorphic_call_checked_entry_offset())); |
1262 __ blr(LR); | 1242 __ blr(LR); |
1263 | 1243 |
1264 __ Bind(&done); | |
1265 RecordSafepoint(locs, slow_path_argument_count); | 1244 RecordSafepoint(locs, slow_path_argument_count); |
1266 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1245 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1267 if (FLAG_precompiled_mode) { | 1246 if (FLAG_precompiled_mode) { |
1268 // Megamorphic calls may occur in slow path stubs. | 1247 // Megamorphic calls may occur in slow path stubs. |
1269 // If valid use try_index argument. | 1248 // If valid use try_index argument. |
1270 if (try_index == CatchClauseNode::kInvalidTryIndex) { | 1249 if (try_index == CatchClauseNode::kInvalidTryIndex) { |
1271 try_index = CurrentTryIndex(); | 1250 try_index = CurrentTryIndex(); |
1272 } | 1251 } |
1273 AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(), | 1252 AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(), |
1274 Thread::kNoDeoptId, token_pos, try_index); | 1253 Thread::kNoDeoptId, token_pos, try_index); |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1481 | 1460 |
1482 | 1461 |
1483 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 1462 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
1484 intptr_t argument_count, | 1463 intptr_t argument_count, |
1485 const Array& argument_names, | 1464 const Array& argument_names, |
1486 Label* failed, | 1465 Label* failed, |
1487 Label* match_found, | 1466 Label* match_found, |
1488 intptr_t deopt_id, | 1467 intptr_t deopt_id, |
1489 TokenPosition token_index, | 1468 TokenPosition token_index, |
1490 LocationSummary* locs, | 1469 LocationSummary* locs, |
1491 bool complete) { | 1470 bool complete, |
| 1471 intptr_t total_ic_calls) { |
1492 ASSERT(is_optimizing()); | 1472 ASSERT(is_optimizing()); |
1493 | |
1494 __ Comment("EmitTestAndCall"); | 1473 __ Comment("EmitTestAndCall"); |
1495 const Array& arguments_descriptor = Array::ZoneHandle( | 1474 const Array& arguments_descriptor = Array::ZoneHandle( |
1496 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); | 1475 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); |
1497 | 1476 |
1498 // Load receiver into R0. | 1477 // Load receiver into R0. |
1499 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); | 1478 __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize); |
1500 __ LoadObject(R4, arguments_descriptor); | 1479 __ LoadObject(R4, arguments_descriptor); |
1501 | 1480 |
1502 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1481 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
1503 const intptr_t num_checks = ic_data.NumberOfChecks(); | 1482 const intptr_t num_checks = ic_data.NumberOfChecks(); |
(...skipping 24 matching lines...) Expand all Loading... |
1528 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1507 // Receiver is Smi, but Smi is not a valid class therefore fail. |
1529 // (Smi class must be first in the list). | 1508 // (Smi class must be first in the list). |
1530 if (!complete) { | 1509 if (!complete) { |
1531 __ tsti(R0, Immediate(kSmiTagMask)); | 1510 __ tsti(R0, Immediate(kSmiTagMask)); |
1532 __ b(failed, EQ); | 1511 __ b(failed, EQ); |
1533 } | 1512 } |
1534 } | 1513 } |
1535 __ Bind(&after_smi_test); | 1514 __ Bind(&after_smi_test); |
1536 | 1515 |
1537 ASSERT(!ic_data.IsNull() && (num_checks > 0)); | 1516 ASSERT(!ic_data.IsNull() && (num_checks > 0)); |
1538 GrowableArray<CidTarget> sorted(num_checks); | 1517 GrowableArray<CidRangeTarget> sorted(num_checks); |
1539 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true); | 1518 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true); |
1540 | 1519 |
| 1520 const intptr_t sorted_len = sorted.length(); |
| 1521 // If sorted_len is 0 then only a Smi check was needed; the Smi check above |
| 1522 // will fail if there was only one check and receiver is not Smi. |
| 1523 if (sorted_len == 0) return; |
| 1524 |
1541 // Value is not Smi, | 1525 // Value is not Smi, |
1542 const intptr_t kSortedLen = sorted.length(); | 1526 __ LoadClassId(R2, R0); |
1543 // If kSortedLen is 0 then only a Smi check was needed; the Smi check above | |
1544 // will fail if there was only one check and receiver is not Smi. | |
1545 if (kSortedLen == 0) return; | |
1546 | 1527 |
1547 __ LoadClassId(R2, R0); | 1528 bool add_megamorphic_call = false; |
1548 for (intptr_t i = 0; i < kSortedLen; i++) { | 1529 const int kMaxImmediateInInstruction = 256; |
1549 const bool kIsLastCheck = (i == (kSortedLen - 1)); | 1530 int bias = |
1550 ASSERT(sorted[i].cid != kSmiCid); | 1531 ComputeGoodBiasForCidComparison(sorted, kMaxImmediateInInstruction); |
| 1532 if (bias != 0) __ AddImmediate(R2, R2, -bias); |
| 1533 |
| 1534 for (intptr_t i = 0; i < sorted_len; i++) { |
| 1535 const bool is_last_check = (i == (sorted_len - 1)); |
| 1536 int cid_start = sorted[i].cid_start; |
| 1537 int cid_end = sorted[i].cid_end; |
| 1538 int count = sorted[i].count; |
| 1539 if (!is_last_check && !complete && count < (total_ic_calls >> 5)) { |
| 1540 // This case is hit too rarely to be worth writing class-id checks inline |
| 1541 // for. |
| 1542 add_megamorphic_call = true; |
| 1543 break; |
| 1544 } |
| 1545 ASSERT(cid_start > kSmiCid || cid_end < kSmiCid); |
1551 Label next_test; | 1546 Label next_test; |
1552 if (!complete) { | 1547 if (!complete || !is_last_check) { |
1553 __ CompareImmediate(R2, sorted[i].cid); | 1548 Label* next_label = is_last_check ? failed : &next_test; |
1554 if (kIsLastCheck) { | 1549 if (cid_start == cid_end) { |
1555 __ b(failed, NE); | 1550 __ CompareImmediate(R2, cid_start - bias); |
| 1551 __ b(next_label, NE); |
1556 } else { | 1552 } else { |
1557 __ b(&next_test, NE); | 1553 __ AddImmediate(R2, R2, bias - cid_start); |
1558 } | 1554 bias = cid_start; |
1559 } else { | 1555 __ CompareImmediate(R2, cid_end - cid_start); |
1560 if (!kIsLastCheck) { | 1556 __ b(next_label, HI); // Unsigned higher. |
1561 __ CompareImmediate(R2, sorted[i].cid); | |
1562 __ b(&next_test, NE); | |
1563 } | 1557 } |
1564 } | 1558 } |
1565 // Do not use the code from the function, but let the code be patched so | 1559 // Do not use the code from the function, but let the code be patched so |
1566 // that we can record the outgoing edges to other code. | 1560 // that we can record the outgoing edges to other code. |
1567 const Function& function = *sorted[i].target; | 1561 const Function& function = *sorted[i].target; |
1568 GenerateStaticDartCall(deopt_id, token_index, | 1562 GenerateStaticDartCall(deopt_id, token_index, |
1569 *StubCode::CallStaticFunction_entry(), | 1563 *StubCode::CallStaticFunction_entry(), |
1570 RawPcDescriptors::kOther, locs, function); | 1564 RawPcDescriptors::kOther, locs, function); |
1571 __ Drop(argument_count); | 1565 __ Drop(argument_count); |
1572 if (!kIsLastCheck) { | 1566 if (!is_last_check) { |
1573 __ b(match_found); | 1567 __ b(match_found); |
1574 } | 1568 } |
1575 __ Bind(&next_test); | 1569 __ Bind(&next_test); |
1576 } | 1570 } |
| 1571 if (add_megamorphic_call) { |
| 1572 int try_index = CatchClauseNode::kInvalidTryIndex; |
| 1573 EmitMegamorphicInstanceCall(ic_data, argument_count, deopt_id, token_index, |
| 1574 locs, try_index, argument_count); |
| 1575 } |
1577 } | 1576 } |
1578 | 1577 |
1579 | 1578 |
1580 #undef __ | 1579 #undef __ |
1581 #define __ compiler_->assembler()-> | 1580 #define __ compiler_->assembler()-> |
1582 | 1581 |
1583 | 1582 |
1584 void ParallelMoveResolver::EmitMove(int index) { | 1583 void ParallelMoveResolver::EmitMove(int index) { |
1585 MoveOperands* move = moves_[index]; | 1584 MoveOperands* move = moves_[index]; |
1586 const Location source = move->src(); | 1585 const Location source = move->src(); |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1849 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1848 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
1850 __ PopDouble(reg); | 1849 __ PopDouble(reg); |
1851 } | 1850 } |
1852 | 1851 |
1853 | 1852 |
1854 #undef __ | 1853 #undef __ |
1855 | 1854 |
1856 } // namespace dart | 1855 } // namespace dart |
1857 | 1856 |
1858 #endif // defined TARGET_ARCH_ARM64 | 1857 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |