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

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

Issue 2737303003: Allow dispatch to use a range of Class-ids in tests (Closed)
Patch Set: Feedback from Slava Created 3 years, 9 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 #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 1458 matching lines...) Expand 10 before | Expand all | Expand 10 after
1469 return; 1469 return;
1470 } 1470 }
1471 } 1471 }
1472 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr( 1472 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr(
1473 call->token_pos(), new (Z) Value(left), new (Z) Value(type_args), type, 1473 call->token_pos(), new (Z) Value(left), new (Z) Value(type_args), type,
1474 Symbols::InTypeCast(), call->deopt_id()); 1474 Symbols::InTypeCast(), call->deopt_id());
1475 ReplaceCall(call, assert_as); 1475 ReplaceCall(call, assert_as);
1476 } 1476 }
1477 1477
1478 1478
1479 bool JitOptimizer::LookupMethodFor(int class_id,
1480 const ArgumentsDescriptor& args_desc,
1481 const String& name,
1482 Function* fn_return) {
1483 if (class_id < 0) return false;
1484 if (class_id >= I->class_table()->NumCids()) return false;
1485
1486 RawClass* raw_class = I->class_table()->At(class_id);
1487 if (raw_class == NULL) return false;
1488 Class& cls = Class::Handle(Z, raw_class);
1489 if (cls.IsNull()) return false;
1490 if (!cls.is_finalized()) return false;
1491 if (Array::Handle(cls.functions()).IsNull()) return false;
1492
1493 Function& target_function = Function::Handle(
1494 Z, Resolver::ResolveDynamicForReceiverClass(cls, name, args_desc));
rmacnak 2017/04/06 22:24:52 This lookup introduced a race with the mutator whe
1495 if (target_function.IsNull()) return false;
1496 *fn_return ^= target_function.raw();
1497 return true;
1498 }
1499
1500
1501 static int OrderById(const intptr_t* a, const intptr_t* b) {
1502 // Negative if 'a' should sort before 'b'.
1503 return *a - *b;
1504 }
1505
1506
1507 void JitOptimizer::TryExpandClassesInICData(const ICData& ic_data) {
1508 if (ic_data.NumberOfChecks() == 0) return;
1509
1510 Function& dummy = Function::Handle(Z);
1511
1512 GrowableArray<intptr_t> ids;
1513 for (int i = 0; i < ic_data.NumberOfChecks(); i++) {
1514 // The API works for multi dispatch ICs that check more than one argument,
1515 // but we know we only check one arg here, so only the 0th element of id
1516 // will be used.
1517 GrowableArray<intptr_t> id;
1518 ic_data.GetCheckAt(i, &id, &dummy);
1519 ids.Add(id[0]);
1520 }
1521 ids.Sort(OrderById);
1522
1523 Array& args_desc_array = Array::Handle(Z, ic_data.arguments_descriptor());
1524 ArgumentsDescriptor args_desc(args_desc_array);
1525 String& name = String::Handle(Z, ic_data.target_name());
1526
1527 Function& fn = Function::Handle(Z);
1528 Function& fn_high = Function::Handle(Z);
1529 Function& possible_match = Function::Handle(Z);
1530
1531 for (int cid_index = 0; cid_index < ids.length() - 1; cid_index++) {
1532 int low_cid = ids[cid_index];
1533 int high_cid = ids[cid_index + 1];
1534 if (low_cid + 1 == high_cid) continue;
1535 if (LookupMethodFor(low_cid, args_desc, name, &fn) &&
1536 LookupMethodFor(high_cid, args_desc, name, &fn_high) &&
1537 fn.raw() == fn_high.raw()) {
1538 // Try to fill in the IC table by going downwards from a known class-id.
1539 bool can_fill_in = true;
1540 for (int i = low_cid + 1; i < high_cid; i++) {
1541 if (!LookupMethodFor(i, args_desc, name, &possible_match) ||
1542 possible_match.raw() != fn.raw()) {
1543 can_fill_in = false;
1544 break;
1545 }
1546 }
1547 if (can_fill_in) {
1548 for (int i = low_cid + 1; i < high_cid; i++) {
1549 ic_data.AddReceiverCheck(i, fn, 0);
1550 }
1551 }
1552 }
1553 }
1554 }
1555
1479 // Tries to optimize instance call by replacing it with a faster instruction 1556 // Tries to optimize instance call by replacing it with a faster instruction
1480 // (e.g, binary op, field load, ..). 1557 // (e.g, binary op, field load, ..).
1481 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { 1558 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
1482 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { 1559 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
1483 return; 1560 return;
1484 } 1561 }
1485 const Token::Kind op_kind = instr->token_kind(); 1562 const Token::Kind op_kind = instr->token_kind();
1486 1563
1487 // Type test is special as it always gets converted into inlined code. 1564 // Type test is special as it always gets converted into inlined code.
1488 if (Token::IsTypeTestOperator(op_kind)) { 1565 if (Token::IsTypeTestOperator(op_kind)) {
1489 ReplaceWithInstanceOf(instr); 1566 ReplaceWithInstanceOf(instr);
1490 return; 1567 return;
1491 } 1568 }
1492 1569
1493 if (Token::IsTypeCastOperator(op_kind)) { 1570 if (Token::IsTypeCastOperator(op_kind)) {
1494 ReplaceWithTypeCast(instr); 1571 ReplaceWithTypeCast(instr);
1495 return; 1572 return;
1496 } 1573 }
1497 1574
1498 const ICData& unary_checks = 1575 const ICData& unary_checks =
1499 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); 1576 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
1500 1577
1501 const bool is_dense = CheckClassInstr::IsDenseCidRange(unary_checks);
1502 const intptr_t max_checks = (op_kind == Token::kEQ)
1503 ? FLAG_max_equality_polymorphic_checks
1504 : FLAG_max_polymorphic_checks;
1505 const intptr_t number_of_checks = unary_checks.NumberOfChecks();
1506 if ((number_of_checks > max_checks) && !is_dense &&
1507 flow_graph()->InstanceCallNeedsClassCheck(
1508 instr, RawFunction::kRegularFunction)) {
1509 // Too many checks, it will be megamorphic which needs unary checks.
1510 instr->set_ic_data(&unary_checks);
1511 return;
1512 }
1513
1514 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { 1578 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
1515 return; 1579 return;
1516 } 1580 }
1517 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { 1581 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
1518 return; 1582 return;
1519 } 1583 }
1520 1584
1521 if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) { 1585 if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) {
1522 return; 1586 return;
1523 } 1587 }
(...skipping 15 matching lines...) Expand all
1539 return; 1603 return;
1540 } 1604 }
1541 if ((op_kind == Token::kSET) && 1605 if ((op_kind == Token::kSET) &&
1542 TryInlineInstanceSetter(instr, unary_checks)) { 1606 TryInlineInstanceSetter(instr, unary_checks)) {
1543 return; 1607 return;
1544 } 1608 }
1545 if (TryInlineInstanceMethod(instr)) { 1609 if (TryInlineInstanceMethod(instr)) {
1546 return; 1610 return;
1547 } 1611 }
1548 1612
1613 // Now we are done trying the inlining options that benefit from only having
1614 // 1 entry in the IC table.
1615 TryExpandClassesInICData(unary_checks);
1616
1549 bool has_one_target = unary_checks.HasOneTarget(); 1617 bool has_one_target = unary_checks.HasOneTarget();
1550 1618
1551 if (has_one_target) { 1619 if (has_one_target) {
1552 // Check if the single target is a polymorphic target, if it is, 1620 // Check if the single target is a polymorphic target, if it is,
1553 // we don't have one target. 1621 // we don't have one target.
1554 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); 1622 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
1555 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { 1623 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
1556 has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType( 1624 has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType(
1557 unary_checks) != Type::null(); 1625 unary_checks) != Type::null();
1558 } else { 1626 } else {
1559 const bool polymorphic_target = 1627 const bool polymorphic_target =
1560 MethodRecognizer::PolymorphicTarget(target); 1628 MethodRecognizer::PolymorphicTarget(target);
1561 has_one_target = !polymorphic_target; 1629 has_one_target = !polymorphic_target;
1562 } 1630 }
1563 } 1631 }
1564 1632
1565 if (has_one_target) { 1633 if (has_one_target) {
1566 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); 1634 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
1567 const RawFunction::Kind function_kind = target.kind(); 1635 const RawFunction::Kind function_kind = target.kind();
1568 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { 1636 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) {
1569 PolymorphicInstanceCallInstr* call = 1637 PolymorphicInstanceCallInstr* call =
1570 new (Z) PolymorphicInstanceCallInstr(instr, unary_checks, 1638 new (Z) PolymorphicInstanceCallInstr(instr, unary_checks,
1571 /* call_with_checks = */ false, 1639 /* call_with_checks = */ false,
1572 /* complete = */ false); 1640 /* complete = */ false);
1573 instr->ReplaceWith(call, current_iterator()); 1641 instr->ReplaceWith(call, current_iterator());
1574 return; 1642 return;
1575 } 1643 }
1576 } 1644 }
1577 1645
1578 if (number_of_checks <= FLAG_max_polymorphic_checks || 1646 bool call_with_checks;
1579 (has_one_target && is_dense)) { 1647 if (has_one_target && FLAG_polymorphic_with_deopt) {
1580 bool call_with_checks; 1648 // Type propagation has not run yet, we cannot eliminate the check.
1581 if (has_one_target && FLAG_polymorphic_with_deopt) { 1649 AddReceiverCheck(instr);
1582 // Type propagation has not run yet, we cannot eliminate the check. 1650 // Call can still deoptimize, do not detach environment from instr.
1583 AddReceiverCheck(instr); 1651 call_with_checks = false;
1584 // Call can still deoptimize, do not detach environment from instr. 1652 } else {
1585 call_with_checks = false; 1653 call_with_checks = true;
1586 } else {
1587 call_with_checks = true;
1588 }
1589 PolymorphicInstanceCallInstr* call = new (Z)
1590 PolymorphicInstanceCallInstr(instr, unary_checks, call_with_checks,
1591 /* complete = */ false);
1592 instr->ReplaceWith(call, current_iterator());
1593 } 1654 }
1655 PolymorphicInstanceCallInstr* call = new (Z)
1656 PolymorphicInstanceCallInstr(instr, unary_checks, call_with_checks,
1657 /* complete = */ false);
1658 instr->ReplaceWith(call, current_iterator());
1594 } 1659 }
1595 1660
1596 1661
1597 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { 1662 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
1598 MethodRecognizer::Kind recognized_kind = 1663 MethodRecognizer::Kind recognized_kind =
1599 MethodRecognizer::RecognizeKind(call->function()); 1664 MethodRecognizer::RecognizeKind(call->function());
1600 switch (recognized_kind) { 1665 switch (recognized_kind) {
1601 case MethodRecognizer::kObjectConstructor: 1666 case MethodRecognizer::kObjectConstructor:
1602 case MethodRecognizer::kObjectArrayAllocate: 1667 case MethodRecognizer::kObjectArrayAllocate:
1603 case MethodRecognizer::kFloat32x4Zero: 1668 case MethodRecognizer::kFloat32x4Zero:
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
1837 // Discard the environment from the original instruction because the store 1902 // Discard the environment from the original instruction because the store
1838 // can't deoptimize. 1903 // can't deoptimize.
1839 instr->RemoveEnvironment(); 1904 instr->RemoveEnvironment();
1840 ReplaceCall(instr, store); 1905 ReplaceCall(instr, store);
1841 return true; 1906 return true;
1842 } 1907 }
1843 1908
1844 1909
1845 } // namespace dart 1910 } // namespace dart
1846 #endif // DART_PRECOMPILED_RUNTIME 1911 #endif // DART_PRECOMPILED_RUNTIME
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698