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

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

Issue 2833413002: Revert "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
« no previous file with comments | « runtime/vm/jit_optimizer.h ('k') | runtime/vm/object.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #ifndef DART_PRECOMPILED_RUNTIME 4 #ifndef DART_PRECOMPILED_RUNTIME
5 #include "vm/jit_optimizer.h" 5 #include "vm/jit_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/branch_optimizer.h" 8 #include "vm/branch_optimizer.h"
9 #include "vm/cha.h" 9 #include "vm/cha.h"
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 if (!call->with_checks()) { 202 if (!call->with_checks()) {
203 return; // Already specialized. 203 return; // Already specialized.
204 } 204 }
205 205
206 const intptr_t receiver_cid = 206 const intptr_t receiver_cid =
207 call->PushArgumentAt(0)->value()->Type()->ToCid(); 207 call->PushArgumentAt(0)->value()->Type()->ToCid();
208 if (receiver_cid == kDynamicCid) { 208 if (receiver_cid == kDynamicCid) {
209 return; // No information about receiver was infered. 209 return; // No information about receiver was infered.
210 } 210 }
211 211
212 const ICData& ic_data = *call->instance_call()->ic_data(); 212 const ICData& ic_data = FlowGraphCompiler::TrySpecializeICDataByReceiverCid(
213 213 call->ic_data(), receiver_cid);
214 const CallTargets* targets = 214 if (ic_data.raw() == call->ic_data().raw()) {
215 FlowGraphCompiler::ResolveCallTargetsForReceiverCid(
216 receiver_cid, String::Handle(zone(), ic_data.target_name()),
217 Array::Handle(zone(), ic_data.arguments_descriptor()));
218 if (targets == NULL) {
219 // No specialization. 215 // No specialization.
220 return; 216 return;
221 } 217 }
222 218
223 const bool with_checks = false; 219 const bool with_checks = false;
224 const bool complete = false; 220 const bool complete = false;
225 PolymorphicInstanceCallInstr* specialized = 221 PolymorphicInstanceCallInstr* specialized =
226 new (Z) PolymorphicInstanceCallInstr(call->instance_call(), *targets, 222 new (Z) PolymorphicInstanceCallInstr(call->instance_call(), ic_data,
227 with_checks, complete); 223 with_checks, complete);
228 call->ReplaceWith(specialized, current_iterator()); 224 call->ReplaceWith(specialized, current_iterator());
229 } 225 }
230 226
231 227
232 static bool ClassIdIsOneOf(intptr_t class_id, 228 static bool ClassIdIsOneOf(intptr_t class_id,
233 const GrowableArray<intptr_t>& class_ids) { 229 const GrowableArray<intptr_t>& class_ids) {
234 for (intptr_t i = 0; i < class_ids.length(); i++) { 230 for (intptr_t i = 0; i < class_ids.length(); i++) {
235 ASSERT(class_ids[i] != kIllegalCid); 231 ASSERT(class_ids[i] != kIllegalCid);
236 if (class_ids[i] == class_id) { 232 if (class_ids[i] == class_id) {
(...skipping 1208 matching lines...) Expand 10 before | Expand all | Expand 10 after
1445 } 1441 }
1446 } 1442 }
1447 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr( 1443 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr(
1448 call->token_pos(), new (Z) Value(left), 1444 call->token_pos(), new (Z) Value(left),
1449 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), 1445 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args),
1450 type, Symbols::InTypeCast(), call->deopt_id()); 1446 type, Symbols::InTypeCast(), call->deopt_id());
1451 ReplaceCall(call, assert_as); 1447 ReplaceCall(call, assert_as);
1452 } 1448 }
1453 1449
1454 1450
1451 bool JitOptimizer::LookupMethodFor(int class_id,
1452 const ArgumentsDescriptor& args_desc,
1453 const String& name,
1454 Function* fn_return) {
1455 if (class_id < 0) return false;
1456 if (class_id >= I->class_table()->NumCids()) return false;
1457
1458 RawClass* raw_class = I->class_table()->At(class_id);
1459 if (raw_class == NULL) return false;
1460 Class& cls = Class::Handle(Z, raw_class);
1461 if (cls.IsNull()) return false;
1462 if (!cls.is_finalized()) return false;
1463 if (Array::Handle(cls.functions()).IsNull()) return false;
1464
1465 bool allow_add = false;
1466 Function& target_function =
1467 Function::Handle(Z, Resolver::ResolveDynamicForReceiverClass(
1468 cls, name, args_desc, allow_add));
1469 if (target_function.IsNull()) return false;
1470 *fn_return ^= target_function.raw();
1471 return true;
1472 }
1473
1474
1475 static int OrderById(const intptr_t* a, const intptr_t* b) {
1476 // Negative if 'a' should sort before 'b'.
1477 return *a - *b;
1478 }
1479
1480
1481 void JitOptimizer::TryExpandClassesInICData(const ICData& ic_data) {
1482 if (ic_data.NumberOfChecks() == 0) return;
1483
1484 Function& dummy = Function::Handle(Z);
1485
1486 GrowableArray<intptr_t> ids;
1487 for (int i = 0; i < ic_data.NumberOfChecks(); i++) {
1488 // The API works for multi dispatch ICs that check more than one argument,
1489 // but we know we only check one arg here, so only the 0th element of id
1490 // will be used.
1491 GrowableArray<intptr_t> id;
1492 ic_data.GetCheckAt(i, &id, &dummy);
1493 ids.Add(id[0]);
1494 }
1495 ids.Sort(OrderById);
1496
1497 Array& args_desc_array = Array::Handle(Z, ic_data.arguments_descriptor());
1498 ArgumentsDescriptor args_desc(args_desc_array);
1499 String& name = String::Handle(Z, ic_data.target_name());
1500
1501 Function& fn = Function::Handle(Z);
1502 Function& fn_high = Function::Handle(Z);
1503 Function& possible_match = Function::Handle(Z);
1504
1505 for (int cid_index = 0; cid_index < ids.length() - 1; cid_index++) {
1506 int low_cid = ids[cid_index];
1507 int high_cid = ids[cid_index + 1];
1508 if (low_cid + 1 == high_cid) continue;
1509 if (LookupMethodFor(low_cid, args_desc, name, &fn) &&
1510 LookupMethodFor(high_cid, args_desc, name, &fn_high) &&
1511 fn.raw() == fn_high.raw()) {
1512 // Try to fill in the IC table by going downwards from a known class-id.
1513 bool can_fill_in = true;
1514 for (int i = low_cid + 1; i < high_cid; i++) {
1515 if (!LookupMethodFor(i, args_desc, name, &possible_match) ||
1516 possible_match.raw() != fn.raw()) {
1517 can_fill_in = false;
1518 break;
1519 }
1520 }
1521 if (can_fill_in) {
1522 for (int i = low_cid + 1; i < high_cid; i++) {
1523 ic_data.AddReceiverCheck(i, fn, 0);
1524 }
1525 }
1526 }
1527 }
1528 }
1529
1455 // Tries to optimize instance call by replacing it with a faster instruction 1530 // Tries to optimize instance call by replacing it with a faster instruction
1456 // (e.g, binary op, field load, ..). 1531 // (e.g, binary op, field load, ..).
1457 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { 1532 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
1458 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { 1533 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
1459 return; 1534 return;
1460 } 1535 }
1461 const Token::Kind op_kind = instr->token_kind(); 1536 const Token::Kind op_kind = instr->token_kind();
1462 1537
1463 // Type test is special as it always gets converted into inlined code. 1538 // Type test is special as it always gets converted into inlined code.
1464 if (Token::IsTypeTestOperator(op_kind)) { 1539 if (Token::IsTypeTestOperator(op_kind)) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1502 return; 1577 return;
1503 } 1578 }
1504 if ((op_kind == Token::kSET) && 1579 if ((op_kind == Token::kSET) &&
1505 TryInlineInstanceSetter(instr, unary_checks)) { 1580 TryInlineInstanceSetter(instr, unary_checks)) {
1506 return; 1581 return;
1507 } 1582 }
1508 if (TryInlineInstanceMethod(instr)) { 1583 if (TryInlineInstanceMethod(instr)) {
1509 return; 1584 return;
1510 } 1585 }
1511 1586
1512 CallTargets* targets = CallTargets::Create(Z, unary_checks); 1587 // Now we are done trying the inlining options that benefit from only having
1588 // 1 entry in the IC table.
1589 TryExpandClassesInICData(unary_checks);
1513 1590
1514 bool has_one_target = targets->HasSingleTarget(); 1591 bool has_one_target = unary_checks.HasOneTarget();
1515 1592
1516 if (has_one_target) { 1593 if (has_one_target) {
1517 // Check if the single target is a polymorphic target, if it is, 1594 // Check if the single target is a polymorphic target, if it is,
1518 // we don't have one target. 1595 // we don't have one target.
1519 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); 1596 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
1520 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { 1597 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
1521 has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType( 1598 has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType(
1522 *targets) != Type::null(); 1599 unary_checks) != Type::null();
1523 } else { 1600 } else {
1524 const bool polymorphic_target = 1601 const bool polymorphic_target =
1525 MethodRecognizer::PolymorphicTarget(target); 1602 MethodRecognizer::PolymorphicTarget(target);
1526 has_one_target = !polymorphic_target; 1603 has_one_target = !polymorphic_target;
1527 } 1604 }
1528 } 1605 }
1529 1606
1530 if (has_one_target) { 1607 if (has_one_target) {
1531 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); 1608 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
1532 const RawFunction::Kind function_kind = target.kind(); 1609 const RawFunction::Kind function_kind = target.kind();
1533 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { 1610 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) {
1534 PolymorphicInstanceCallInstr* call = 1611 PolymorphicInstanceCallInstr* call =
1535 new (Z) PolymorphicInstanceCallInstr(instr, *targets, 1612 new (Z) PolymorphicInstanceCallInstr(instr, unary_checks,
1536 /* call_with_checks = */ false, 1613 /* call_with_checks = */ false,
1537 /* complete = */ false); 1614 /* complete = */ false);
1538 instr->ReplaceWith(call, current_iterator()); 1615 instr->ReplaceWith(call, current_iterator());
1539 return; 1616 return;
1540 } 1617 }
1541 } 1618 }
1542 1619
1543 // If there is only one target we can make this into a deopting class check, 1620 // If there is only one target we can make this into a deopting class check,
1544 // followed by a call instruction that does not check the class of the 1621 // followed by a call instruction that does not check the class of the
1545 // receiver. This enables a lot of optimizations because after the class 1622 // receiver. This enables a lot of optimizations because after the class
1546 // check we can probably inline the call and not worry about side effects. 1623 // check we can probably inline the call and not worry about side effects.
1547 // However, this can fall down if new receiver classes arrive at this call 1624 // However, this can fall down if new receiver classes arrive at this call
1548 // site after we generated optimized code. This causes a deopt, and after a 1625 // site after we generated optimized code. This causes a deopt, and after a
1549 // few deopts we won't optimize this function any more at all. Therefore for 1626 // few deopts we won't optimize this function any more at all. Therefore for
1550 // very polymorphic sites we don't make this optimization, keeping it as a 1627 // very polymorphic sites we don't make this optimization, keeping it as a
1551 // regular checked PolymorphicInstanceCall, which falls back to the slow but 1628 // regular checked PolymorphicInstanceCall, which falls back to the slow but
1552 // non-deopting megamorphic call stub when it sees new receiver classes. 1629 // non-deopting megamorphic call stub when it sees new receiver classes.
1553 bool call_with_checks; 1630 bool call_with_checks;
1554 if (has_one_target && FLAG_polymorphic_with_deopt && 1631 if (has_one_target && FLAG_polymorphic_with_deopt &&
1555 (!instr->ic_data()->HasDeoptReason(ICData::kDeoptCheckClass) || 1632 (!instr->ic_data()->HasDeoptReason(ICData::kDeoptCheckClass) ||
1556 unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { 1633 unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
1557 // Type propagation has not run yet, we cannot eliminate the check. 1634 // Type propagation has not run yet, we cannot eliminate the check.
1558 // TODO(erikcorry): The receiver check should use the off-heap targets
1559 // array, not the IC array.
1560 AddReceiverCheck(instr); 1635 AddReceiverCheck(instr);
1561 // Call can still deoptimize, do not detach environment from instr. 1636 // Call can still deoptimize, do not detach environment from instr.
1562 call_with_checks = false; 1637 call_with_checks = false;
1563 } else { 1638 } else {
1564 call_with_checks = true; 1639 call_with_checks = true;
1565 } 1640 }
1566 PolymorphicInstanceCallInstr* call = 1641 PolymorphicInstanceCallInstr* call = new (Z)
1567 new (Z) PolymorphicInstanceCallInstr(instr, *targets, call_with_checks, 1642 PolymorphicInstanceCallInstr(instr, unary_checks, call_with_checks,
1568 /* complete = */ false); 1643 /* complete = */ false);
1569 instr->ReplaceWith(call, current_iterator()); 1644 instr->ReplaceWith(call, current_iterator());
1570 } 1645 }
1571 1646
1572 1647
1573 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { 1648 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
1574 MethodRecognizer::Kind recognized_kind = 1649 MethodRecognizer::Kind recognized_kind =
1575 MethodRecognizer::RecognizeKind(call->function()); 1650 MethodRecognizer::RecognizeKind(call->function());
1576 switch (recognized_kind) { 1651 switch (recognized_kind) {
1577 case MethodRecognizer::kObjectConstructor: 1652 case MethodRecognizer::kObjectConstructor:
1578 case MethodRecognizer::kObjectArrayAllocate: 1653 case MethodRecognizer::kObjectArrayAllocate:
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
1813 // Discard the environment from the original instruction because the store 1888 // Discard the environment from the original instruction because the store
1814 // can't deoptimize. 1889 // can't deoptimize.
1815 instr->RemoveEnvironment(); 1890 instr->RemoveEnvironment();
1816 ReplaceCall(instr, store); 1891 ReplaceCall(instr, store);
1817 return true; 1892 return true;
1818 } 1893 }
1819 1894
1820 1895
1821 } // namespace dart 1896 } // namespace dart
1822 #endif // DART_PRECOMPILED_RUNTIME 1897 #endif // DART_PRECOMPILED_RUNTIME
OLDNEW
« no previous file with comments | « runtime/vm/jit_optimizer.h ('k') | runtime/vm/object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698