Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(781)

Side by Side Diff: runtime/vm/flow_graph_compiler_arm.cc

Issue 2809583002: Use off-heap data for type feedback in PolymorphicInstanceCallInstr (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 1195 matching lines...) Expand 10 before | Expand all | Expand 10 after
1206 LocationSummary* locs) { 1206 LocationSummary* locs) {
1207 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); 1207 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
1208 __ LoadUniqueObject(R9, ic_data); 1208 __ LoadUniqueObject(R9, ic_data);
1209 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, 1209 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
1210 locs); 1210 locs);
1211 __ Drop(argument_count); 1211 __ Drop(argument_count);
1212 } 1212 }
1213 1213
1214 1214
1215 void FlowGraphCompiler::EmitMegamorphicInstanceCall( 1215 void FlowGraphCompiler::EmitMegamorphicInstanceCall(
1216 const ICData& ic_data, 1216 const String& name,
1217 const Array& arguments_descriptor,
1217 intptr_t argument_count, 1218 intptr_t argument_count,
1218 intptr_t deopt_id, 1219 intptr_t deopt_id,
1219 TokenPosition token_pos, 1220 TokenPosition token_pos,
1220 LocationSummary* locs, 1221 LocationSummary* locs,
1221 intptr_t try_index, 1222 intptr_t try_index,
1222 intptr_t slow_path_argument_count) { 1223 intptr_t slow_path_argument_count) {
1223 const String& name = String::Handle(zone(), ic_data.target_name());
1224 const Array& arguments_descriptor =
1225 Array::ZoneHandle(zone(), ic_data.arguments_descriptor());
1226 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); 1224 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
1227 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle( 1225 const MegamorphicCache& cache = MegamorphicCache::ZoneHandle(
1228 zone(), 1226 zone(),
1229 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor)); 1227 MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
1230 1228
1231 __ Comment("MegamorphicCall"); 1229 __ Comment("MegamorphicCall");
1232 // Load receiver into R0. 1230 // Load receiver into R0.
1233 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); 1231 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize);
1234 __ LoadObject(R9, cache); 1232 __ LoadObject(R9, cache);
1235 __ ldr(LR, Address(THR, Thread::megamorphic_call_checked_entry_offset())); 1233 __ ldr(LR, Address(THR, Thread::megamorphic_call_checked_entry_offset()));
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
1473 // TODO(zerny): clobber non-live temporary FPU registers. 1471 // TODO(zerny): clobber non-live temporary FPU registers.
1474 if (tmp.IsRegister() && 1472 if (tmp.IsRegister() &&
1475 !locs->live_registers()->ContainsRegister(tmp.reg())) { 1473 !locs->live_registers()->ContainsRegister(tmp.reg())) {
1476 __ mov(tmp.reg(), Operand(0xf7)); 1474 __ mov(tmp.reg(), Operand(0xf7));
1477 } 1475 }
1478 } 1476 }
1479 } 1477 }
1480 #endif 1478 #endif
1481 1479
1482 1480
1483 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, 1481 void FlowGraphCompiler::EmitTestAndCall(const PolymorphicTargets& targets,
1482 const String& function_name,
1484 intptr_t argument_count, 1483 intptr_t argument_count,
1485 const Array& argument_names, 1484 const Array& argument_names,
1486 Label* failed, 1485 Label* failed,
1487 Label* match_found, 1486 Label* match_found,
1488 intptr_t deopt_id, 1487 intptr_t deopt_id,
1489 TokenPosition token_index, 1488 TokenPosition token_index,
1490 LocationSummary* locs, 1489 LocationSummary* locs,
1491 bool complete, 1490 bool complete,
1492 intptr_t total_ic_calls) { 1491 intptr_t total_ic_calls) {
1493 ASSERT(is_optimizing()); 1492 ASSERT(is_optimizing());
1493
1494 __ Comment("EmitTestAndCall"); 1494 __ Comment("EmitTestAndCall");
1495 const Array& arguments_descriptor = Array::ZoneHandle( 1495 const Array& arguments_descriptor = Array::ZoneHandle(
1496 zone(), ArgumentsDescriptor::New(argument_count, argument_names)); 1496 zone(), ArgumentsDescriptor::New(argument_count, argument_names));
1497
1498 // Load receiver into R0. 1497 // Load receiver into R0.
1499 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize); 1498 __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize);
1500 __ LoadObject(R4, arguments_descriptor); 1499 __ LoadObject(R4, arguments_descriptor);
1501 1500
1502 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; 1501 const int kNoCase = -1;
Vyacheslav Egorov (Google) 2017/04/10 10:59:27 This code is duplicated in each architecture. Coul
erikcorry 2017/04/19 15:06:39 Done.
1503 const intptr_t num_checks = ic_data.NumberOfChecks(); 1502 int smi_case = kNoCase;
1503 int which_case_to_skip = kNoCase;
1504 1504
1505 ASSERT(!ic_data.IsNull() && (num_checks > 0)); 1505 const int length = targets.length();
1506 int non_smi_length = length;
1506 1507
1507 Label after_smi_test; 1508 // Find out if one of the classes in one of the cases is the Smi class. We
1508 if (kFirstCheckIsSmi) { 1509 // will be handling that specially.
1510 for (int i = 0; i < length; i++) {
1511 const intptr_t start = targets[i].cid_start;
1512 if (start > kSmiCid) continue;
1513 const intptr_t end = targets[i].cid_end;
1514 if (end >= kSmiCid) {
1515 smi_case = i;
1516 if (start == kSmiCid && end == kSmiCid) {
1517 // If this case has only the Smi class then we won't need to emit it at
1518 // all later.
1519 which_case_to_skip = i;
1520 non_smi_length--;
1521 }
1522 break;
1523 }
1524 }
1525
1526 if (smi_case != kNoCase) {
1527 Label after_smi_test;
1509 __ tst(R0, Operand(kSmiTagMask)); 1528 __ tst(R0, Operand(kSmiTagMask));
1510 // Jump if receiver is not Smi. 1529 // Jump if receiver is not Smi.
1511 if (num_checks == 1) { 1530 __ b(non_smi_length == 0 ? failed : &after_smi_test, NE);
1512 __ b(failed, NE);
1513 } else {
1514 __ b(&after_smi_test, NE);
1515 }
1516 // Do not use the code from the function, but let the code be patched so 1531 // Do not use the code from the function, but let the code be patched so
1517 // that we can record the outgoing edges to other code. 1532 // that we can record the outgoing edges to other code.
1518 const Function& function = 1533 const Function& function = *targets[smi_case].target;
1519 Function::ZoneHandle(zone(), ic_data.GetTargetAt(0));
1520 GenerateStaticDartCall(deopt_id, token_index, 1534 GenerateStaticDartCall(deopt_id, token_index,
1521 *StubCode::CallStaticFunction_entry(), 1535 *StubCode::CallStaticFunction_entry(),
1522 RawPcDescriptors::kOther, locs, function); 1536 RawPcDescriptors::kOther, locs, function);
1523 __ Drop(argument_count); 1537 __ Drop(argument_count);
1524 if (num_checks > 1) { 1538 if (non_smi_length > 0) {
1525 __ b(match_found); 1539 __ b(match_found);
1526 } 1540 }
1541 __ Bind(&after_smi_test);
1527 } else { 1542 } else {
1528 // 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.
1529 // (Smi class must be first in the list).
1530 if (!complete) { 1544 if (!complete) {
1531 __ tst(R0, Operand(kSmiTagMask)); 1545 __ tst(R0, Operand(kSmiTagMask));
1532 __ b(failed, EQ); 1546 __ b(failed, EQ);
1533 } 1547 }
1534 } 1548 }
1535 __ Bind(&after_smi_test);
1536 1549
1537 ASSERT(!ic_data.IsNull() && (num_checks > 0)); 1550 ASSERT(length > 0);
1538 GrowableArray<CidRangeTarget> sorted(num_checks);
1539 SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true);
1540 1551
1541 const intptr_t sorted_len = sorted.length(); 1552 // If non_smi_length is 0 then only a Smi check was needed; the Smi check
1542 // If sorted_len is 0 then only a Smi check was needed; the Smi check above 1553 // above will fail if there was only one check and receiver is not Smi.
1543 // will fail if there was only one check and receiver is not Smi. 1554 if (non_smi_length == 0) return;
1544 if (sorted_len == 0) return;
1545 1555
1546 // Value is not Smi, 1556 // Value is not Smi,
1547 __ LoadClassId(R2, R0); 1557 __ LoadClassId(R2, R0);
1548 1558
1549 bool add_megamorphic_call = false; 1559 bool add_megamorphic_call = false;
1550 const int kMaxImmediateInInstruction = 256; 1560 const int kMaxImmediateInInstruction = 256;
1551 int bias = 1561 int bias =
1552 ComputeGoodBiasForCidComparison(sorted, kMaxImmediateInInstruction); 1562 ComputeGoodBiasForCidComparison(targets, kMaxImmediateInInstruction);
1553 if (bias != 0) __ AddImmediate(R2, R2, -bias); 1563 if (bias != 0) __ AddImmediate(R2, R2, -bias);
1554 1564
1555 for (intptr_t i = 0; i < sorted_len; i++) { 1565 int last_check = which_case_to_skip == length - 1 ? length - 2 : length - 1;
1556 const bool is_last_check = (i == (sorted_len - 1)); 1566
1557 int cid_start = sorted[i].cid_start; 1567 for (intptr_t i = 0; i < length; i++) {
1558 int cid_end = sorted[i].cid_end; 1568 if (i == which_case_to_skip) continue;
1559 int count = sorted[i].count; 1569 const bool is_last_check = (i == last_check);
1570 const int cid_start = targets[i].cid_start;
1571 const int cid_end = targets[i].cid_end;
1572 const int count = targets[i].count;
1560 if (!is_last_check && !complete && count < (total_ic_calls >> 5)) { 1573 if (!is_last_check && !complete && count < (total_ic_calls >> 5)) {
1561 // This case is hit too rarely to be worth writing class-id checks inline 1574 // This case is hit too rarely to be worth writing class-id checks inline
1562 // for. 1575 // for. Note that we can't do this for calls with only one target because
1576 // the type propagator may have made use of that and expects a deopt if
1577 // a new class is seen at this calls site. See HasSingleRecognizedCid.
1563 add_megamorphic_call = true; 1578 add_megamorphic_call = true;
1564 break; 1579 break;
1565 } 1580 }
1566 ASSERT(cid_start > kSmiCid || cid_end < kSmiCid);
1567 Label next_test; 1581 Label next_test;
1568 if (!complete || !is_last_check) { 1582 if (!complete || !is_last_check) {
1569 Label* next_label = is_last_check ? failed : &next_test; 1583 Label* next_label = is_last_check ? failed : &next_test;
1570 if (cid_start == cid_end) { 1584 if (cid_start == cid_end) {
1571 __ CompareImmediate(R2, cid_start - bias); 1585 __ CompareImmediate(R2, cid_start - bias);
1572 __ b(next_label, NE); 1586 __ b(next_label, NE);
1573 } else { 1587 } else {
1574 __ AddImmediate(R2, R2, bias - cid_start); 1588 __ AddImmediate(R2, R2, bias - cid_start);
1575 bias = cid_start; 1589 bias = cid_start;
1576 __ CompareImmediate(R2, cid_end - cid_start); 1590 __ CompareImmediate(R2, cid_end - cid_start);
1577 __ b(next_label, HI); // Unsigned higher. 1591 __ b(next_label, HI); // Unsigned higher.
1578 } 1592 }
1579 } 1593 }
1580 // Do not use the code from the function, but let the code be patched so 1594 // Do not use the code from the function, but let the code be patched so
1581 // that we can record the outgoing edges to other code. 1595 // that we can record the outgoing edges to other code.
1582 const Function& function = *sorted[i].target; 1596 const Function& function = *targets[i].target;
1583 GenerateStaticDartCall(deopt_id, token_index, 1597 GenerateStaticDartCall(deopt_id, token_index,
1584 *StubCode::CallStaticFunction_entry(), 1598 *StubCode::CallStaticFunction_entry(),
1585 RawPcDescriptors::kOther, locs, function); 1599 RawPcDescriptors::kOther, locs, function);
1586 __ Drop(argument_count); 1600 __ Drop(argument_count);
1587 if (!is_last_check) { 1601 if (!is_last_check || add_megamorphic_call) {
1588 __ b(match_found); 1602 __ b(match_found);
1589 } 1603 }
1590 __ Bind(&next_test); 1604 __ Bind(&next_test);
1591 } 1605 }
1592 if (add_megamorphic_call) { 1606 if (add_megamorphic_call) {
1593 int try_index = CatchClauseNode::kInvalidTryIndex; 1607 int try_index = CatchClauseNode::kInvalidTryIndex;
1594 EmitMegamorphicInstanceCall(ic_data, argument_count, deopt_id, token_index, 1608 EmitMegamorphicInstanceCall(function_name, arguments_descriptor,
1595 locs, try_index, argument_count); 1609 argument_count, deopt_id, token_index, locs,
1610 try_index);
1596 } 1611 }
1597 } 1612 }
1598 1613
1599 1614
1600 #undef __ 1615 #undef __
1601 #define __ compiler_->assembler()-> 1616 #define __ compiler_->assembler()->
1602 1617
1603 1618
1604 void ParallelMoveResolver::EmitMove(int index) { 1619 void ParallelMoveResolver::EmitMove(int index) {
1605 MoveOperands* move = moves_[index]; 1620 MoveOperands* move = moves_[index];
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
1889 DRegister dreg = EvenDRegisterOf(reg); 1904 DRegister dreg = EvenDRegisterOf(reg);
1890 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex)); 1905 __ vldrd(dreg, Address(SP, kDoubleSize, Address::PostIndex));
1891 } 1906 }
1892 1907
1893 1908
1894 #undef __ 1909 #undef __
1895 1910
1896 } // namespace dart 1911 } // namespace dart
1897 1912
1898 #endif // defined TARGET_ARCH_ARM 1913 #endif // defined TARGET_ARCH_ARM
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698