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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
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 1232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1243 const String& name = String::Handle(zone(), ic_data.target_name()); | 1243 const String& name = String::Handle(zone(), ic_data.target_name()); |
1244 const Array& arguments_descriptor = | 1244 const Array& arguments_descriptor = |
1245 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); | 1245 Array::ZoneHandle(zone(), ic_data.arguments_descriptor()); |
1246 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1246 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
1247 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( | 1247 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( |
1248 zone(), | 1248 zone(), |
1249 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); | 1249 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); |
1250 __ Comment("MegamorphicCall"); | 1250 __ Comment("MegamorphicCall"); |
1251 // Load receiver into RDI. | 1251 // Load receiver into RDI. |
1252 __ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize)); | 1252 __ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize)); |
1253 Label done; | |
1254 if (ShouldInlineSmiStringHashCode(ic_data)) { | |
1255 Label megamorphic_call; | |
1256 __ Comment("Inlined get:hashCode for Smi and OneByteString"); | |
1257 __ movq(RAX, RDI); // Move Smi hashcode to RAX. | |
1258 __ testq(RDI, Immediate(kSmiTagMask)); | |
1259 __ j(ZERO, &done, Assembler::kNearJump); // It is Smi, we are done. | |
1260 | |
1261 __ CompareClassId(RDI, kOneByteStringCid); | |
1262 __ j(NOT_EQUAL, &megamorphic_call, Assembler::kNearJump); | |
1263 __ movq(RAX, FieldAddress(RDI, String::hash_offset())); | |
1264 __ cmpq(RAX, Immediate(0)); | |
1265 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | |
1266 | |
1267 __ Bind(&megamorphic_call); | |
1268 __ Comment("Slow case: megamorphic call"); | |
1269 } | |
1270 __ LoadObject(RBX, cache); | 1253 __ LoadObject(RBX, cache); |
1271 __ call(Address(THR, Thread::megamorphic_call_checked_entry_offset())); | 1254 __ call(Address(THR, Thread::megamorphic_call_checked_entry_offset())); |
1272 | 1255 |
1273 __ Bind(&done); | |
1274 RecordSafepoint(locs, slow_path_argument_count); | 1256 RecordSafepoint(locs, slow_path_argument_count); |
1275 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 1257 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); |
1276 if (FLAG_precompiled_mode) { | 1258 if (FLAG_precompiled_mode) { |
1277 // Megamorphic calls may occur in slow path stubs. | 1259 // Megamorphic calls may occur in slow path stubs. |
1278 // If valid use try_index argument. | 1260 // If valid use try_index argument. |
1279 if (try_index == CatchClauseNode::kInvalidTryIndex) { | 1261 if (try_index == CatchClauseNode::kInvalidTryIndex) { |
1280 try_index = CurrentTryIndex(); | 1262 try_index = CurrentTryIndex(); |
1281 } | 1263 } |
1282 AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(), | 1264 AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(), |
1283 Thread::kNoDeoptId, token_pos, try_index); | 1265 Thread::kNoDeoptId, token_pos, try_index); |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1447 | 1429 |
1448 | 1430 |
1449 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 1431 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
1450 intptr_t argument_count, | 1432 intptr_t argument_count, |
1451 const Array& argument_names, | 1433 const Array& argument_names, |
1452 Label* failed, | 1434 Label* failed, |
1453 Label* match_found, | 1435 Label* match_found, |
1454 intptr_t deopt_id, | 1436 intptr_t deopt_id, |
1455 TokenPosition token_index, | 1437 TokenPosition token_index, |
1456 LocationSummary* locs, | 1438 LocationSummary* locs, |
1457 bool complete) { | 1439 bool complete, |
1440 intptr_t total_ic_calls) { | |
1458 ASSERT(is_optimizing()); | 1441 ASSERT(is_optimizing()); |
1459 | 1442 |
1460 __ Comment("EmitTestAndCall"); | 1443 __ Comment("EmitTestAndCall"); |
1461 const Array& arguments_descriptor = Array::ZoneHandle( | 1444 const Array& arguments_descriptor = Array::ZoneHandle( |
1462 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); | 1445 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); |
1463 // Load receiver into RAX. | 1446 // Load receiver into RAX. |
1464 __ movq(RAX, Address(RSP, (argument_count - 1) * kWordSize)); | 1447 __ movq(RAX, Address(RSP, (argument_count - 1) * kWordSize)); |
1465 __ LoadObject(R10, arguments_descriptor); | 1448 __ LoadObject(R10, arguments_descriptor); |
1466 | 1449 |
1467 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1450 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
(...skipping 25 matching lines...) Expand all Loading... | |
1493 // Receiver is Smi, but Smi is not a valid class therefore fail. | 1476 // Receiver is Smi, but Smi is not a valid class therefore fail. |
1494 // (Smi class must be first in the list). | 1477 // (Smi class must be first in the list). |
1495 if (!complete) { | 1478 if (!complete) { |
1496 __ testq(RAX, Immediate(kSmiTagMask)); | 1479 __ testq(RAX, Immediate(kSmiTagMask)); |
1497 __ j(ZERO, failed); | 1480 __ j(ZERO, failed); |
1498 } | 1481 } |
1499 } | 1482 } |
1500 __ Bind(&after_smi_test); | 1483 __ Bind(&after_smi_test); |
1501 | 1484 |
1502 ASSERT(!ic_data.IsNull() && (num_checks > 0)); | 1485 ASSERT(!ic_data.IsNull() && (num_checks > 0)); |
1503 GrowableArray<CidTarget> sorted(num_checks); | 1486 GrowableArray<CidRangeTarget> sorted(num_checks); |
1504 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true); | 1487 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true); |
1505 | 1488 |
1506 const intptr_t kSortedLen = sorted.length(); | 1489 const intptr_t sorted_len = sorted.length(); |
1507 // If kSortedLen is 0 then only a Smi check was needed; the Smi check above | 1490 // If sorted_len is 0 then only a Smi check was needed; the Smi check above |
1508 // will fail if there was only one check and receiver is not Smi. | 1491 // will fail if there was only one check and receiver is not Smi. |
1509 if (kSortedLen == 0) return; | 1492 if (sorted_len == 0) return; |
1510 | 1493 |
1511 // Value is not Smi, | 1494 // Value is not Smi, |
1512 __ LoadClassId(RDI, RAX); | 1495 __ LoadClassId(RDI, RAX); |
1513 for (intptr_t i = 0; i < kSortedLen; i++) { | 1496 |
1514 const bool kIsLastCheck = (i == (kSortedLen - 1)); | 1497 bool add_megamorphic_call = false; |
1515 ASSERT(sorted[i].cid != kSmiCid); | 1498 int bias = GetGoodBias(sorted, 127); |
Vyacheslav Egorov (Google)
2017/03/10 10:31:30
magic constant?
erikcorry
2017/03/10 13:30:01
I gave it a name, kMaxImmediateInInstruction. It'
| |
1499 if (bias != 0) __ addl(RDI, Immediate(-bias)); | |
1500 | |
1501 for (intptr_t i = 0; i < sorted_len; i++) { | |
1502 const bool is_last_check = (i == (sorted_len - 1)); | |
1503 int cid_start = sorted[i].cid_start; | |
1504 int cid_end = sorted[i].cid_end; | |
1505 int count = sorted[i].count; | |
1506 if (!is_last_check && !complete && count < (total_ic_calls >> 5)) { | |
1507 // This case is hit too rarely to be worth writing class-id checks inline | |
1508 // for. | |
1509 add_megamorphic_call = true; | |
1510 break; | |
1511 } | |
1512 ASSERT(cid_start > kSmiCid || cid_end < kSmiCid); | |
1516 Label next_test; | 1513 Label next_test; |
1517 if (!complete) { | 1514 if (!complete || !is_last_check) { |
1518 __ cmpl(RDI, Immediate(sorted[i].cid)); | 1515 Label* next_label = is_last_check ? failed : &next_test; |
1519 if (kIsLastCheck) { | 1516 bool near = is_last_check ? Assembler::kFarJump : Assembler::kNearJump; |
1520 __ j(NOT_EQUAL, failed); | 1517 if (cid_start == cid_end) { |
1518 __ cmpl(RDI, Immediate(cid_start - bias)); | |
1519 __ j(NOT_EQUAL, next_label, near); | |
1521 } else { | 1520 } else { |
1522 __ j(NOT_EQUAL, &next_test); | 1521 __ addl(RDI, Immediate(bias - cid_start)); |
1523 } | 1522 bias = cid_start; |
1524 } else { | 1523 __ cmpl(RDI, Immediate(cid_end - cid_start)); |
1525 if (!kIsLastCheck) { | 1524 __ j(ABOVE, next_label, near); // Unsigned higher. |
1526 __ cmpl(RDI, Immediate(sorted[i].cid)); | |
1527 __ j(NOT_EQUAL, &next_test); | |
1528 } | 1525 } |
1529 } | 1526 } |
1530 // Do not use the code from the function, but let the code be patched so | 1527 // Do not use the code from the function, but let the code be patched so |
1531 // that we can record the outgoing edges to other code. | 1528 // that we can record the outgoing edges to other code. |
1532 const Function& function = *sorted[i].target; | 1529 const Function& function = *sorted[i].target; |
1533 GenerateStaticDartCall(deopt_id, token_index, | 1530 GenerateStaticDartCall(deopt_id, token_index, |
1534 *StubCode::CallStaticFunction_entry(), | 1531 *StubCode::CallStaticFunction_entry(), |
1535 RawPcDescriptors::kOther, locs, function); | 1532 RawPcDescriptors::kOther, locs, function); |
1536 __ Drop(argument_count, RCX); | 1533 __ Drop(argument_count, RCX); |
1537 if (!kIsLastCheck) { | 1534 if (!is_last_check) { |
1538 __ jmp(match_found); | 1535 __ jmp(match_found); |
1539 } | 1536 } |
1540 __ Bind(&next_test); | 1537 __ Bind(&next_test); |
1541 } | 1538 } |
1539 if (add_megamorphic_call) { | |
1540 int try_index = CatchClauseNode::kInvalidTryIndex; | |
1541 EmitMegamorphicInstanceCall(ic_data, argument_count, deopt_id, token_index, | |
1542 locs, try_index, argument_count); | |
1543 } | |
1542 } | 1544 } |
1543 | 1545 |
1544 | 1546 |
1545 #undef __ | 1547 #undef __ |
1546 #define __ compiler_->assembler()-> | 1548 #define __ compiler_->assembler()-> |
1547 | 1549 |
1548 | 1550 |
1549 void ParallelMoveResolver::EmitMove(int index) { | 1551 void ParallelMoveResolver::EmitMove(int index) { |
1550 MoveOperands* move = moves_[index]; | 1552 MoveOperands* move = moves_[index]; |
1551 const Location source = move->src(); | 1553 const Location source = move->src(); |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1772 __ movups(reg, Address(RSP, 0)); | 1774 __ movups(reg, Address(RSP, 0)); |
1773 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); | 1775 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); |
1774 } | 1776 } |
1775 | 1777 |
1776 | 1778 |
1777 #undef __ | 1779 #undef __ |
1778 | 1780 |
1779 } // namespace dart | 1781 } // namespace dart |
1780 | 1782 |
1781 #endif // defined TARGET_ARCH_X64 | 1783 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |