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

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: 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 Class& clarse = Class::Handle(Z, I->class_table()->At(class_id));
Vyacheslav Egorov (Google) 2017/03/10 10:31:30 please use cls
erikcorry 2017/03/10 13:30:01 Done.
1484 if (clarse.IsNull()) return false;
1485 if (!clarse.is_finalized()) return false;
1486 Function& target_function = Function::Handle(
1487 Z, Resolver::ResolveDynamicForReceiverClass(clarse, name, args_desc));
1488 if (target_function.IsNull()) return false;
1489 *fn_return ^= target_function.raw();
1490 return true;
1491 }
1492
1493
1494 bool JitOptimizer::TryAddClass(const ICData& ic_data,
Vyacheslav Egorov (Google) 2017/03/10 10:31:31 This function is called TryAddClass but it does no
erikcorry 2017/03/10 13:30:01 This method was removed.
1495 const Function& match,
1496 int class_id,
1497 const ArgumentsDescriptor& args_desc,
1498 const String& name) {
1499 if (class_id < 0) return false;
1500 if (class_id >= I->class_table()->NumCids()) return false;
1501
1502 RawClass* raw_class = I->class_table()->At(class_id);
Vyacheslav Egorov (Google) 2017/03/10 10:31:30 This seems to almost duplicate the code in the Loo
erikcorry 2017/03/10 13:30:01 Done.
1503 if (raw_class == NULL) return false;
1504 Class& try_class = Class::Handle(Z, raw_class);
1505
1506 if (!try_class.is_finalized()) return false;
1507 if (Array::Handle(try_class.functions()).IsNull()) return false;
1508 Function& target_function = Function::Handle(
1509 Z, Resolver::ResolveDynamicForReceiverClass(try_class, name, args_desc));
1510 if (target_function.IsNull()) return false;
1511 if (target_function.raw() != match.raw()) return false;
1512 return true;
1513 }
1514
1515 static int OrderById(const intptr_t* a, const intptr_t* b) {
1516 // Negative if 'a' should sort before 'b'.
1517 return *a - *b;
1518 }
1519
1520 void JitOptimizer::TryExpandClassesInIC(const ICData& ic_data) {
1521 if (ic_data.NumberOfChecks() == 0) return;
1522
1523 Function& dummy = Function::Handle(Z);
1524
1525 GrowableArray<intptr_t> ids;
1526 for (int i = 0; i < ic_data.NumberOfChecks(); i++) {
1527 // The API works for multi dispatch ICs that check more than one argument,
1528 // but we know we only check one arg here, so only the 0th element of id
1529 // will be used.
1530 GrowableArray<intptr_t> id;
1531 ic_data.GetCheckAt(i, &id, &dummy);
1532 ids.Add(id[0]);
1533 }
1534 ids.Sort(OrderById);
1535
1536 Array& args_desc_array = Array::Handle(Z, ic_data.arguments_descriptor());
1537 ArgumentsDescriptor args_desc(args_desc_array);
1538 String& name = String::Handle(Z, ic_data.target_name());
1539
1540 Function& fn = Function::Handle(Z);
1541 Function& fn_high = Function::Handle(Z);
1542
1543 for (int cid_index = 0; cid_index < ids.length() - 1; cid_index++) {
1544 int low_cid = ids[cid_index];
1545 int high_cid = ids[cid_index + 1];
1546 if (low_cid + 1 == high_cid) continue;
1547 if (LookupMethodFor(low_cid, args_desc, name, &fn) &&
1548 LookupMethodFor(high_cid, args_desc, name, &fn_high) &&
1549 fn.raw() == fn_high.raw()) {
1550 // Try to fill in the IC table by going downwards from a known class-id.
1551 bool can_fill_in = true;
1552 for (int i = low_cid + 1; i < high_cid; i++) {
1553 if (!TryAddClass(ic_data, fn, i, args_desc, name)) {
1554 can_fill_in = false;
1555 break;
1556 }
1557 }
1558 if (can_fill_in) {
1559 for (int i = low_cid + 1; i < high_cid; i++) {
1560 ic_data.AddReceiverCheck(i, fn, 0);
1561 }
1562 }
1563 }
1564 }
1565 }
1566
1479 // Tries to optimize instance call by replacing it with a faster instruction 1567 // Tries to optimize instance call by replacing it with a faster instruction
1480 // (e.g, binary op, field load, ..). 1568 // (e.g, binary op, field load, ..).
1481 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { 1569 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
1482 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { 1570 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
1483 return; 1571 return;
1484 } 1572 }
1485 const Token::Kind op_kind = instr->token_kind(); 1573 const Token::Kind op_kind = instr->token_kind();
1486 1574
1487 // Type test is special as it always gets converted into inlined code. 1575 // Type test is special as it always gets converted into inlined code.
1488 if (Token::IsTypeTestOperator(op_kind)) { 1576 if (Token::IsTypeTestOperator(op_kind)) {
1489 ReplaceWithInstanceOf(instr); 1577 ReplaceWithInstanceOf(instr);
1490 return; 1578 return;
1491 } 1579 }
1492 1580
1493 if (Token::IsTypeCastOperator(op_kind)) { 1581 if (Token::IsTypeCastOperator(op_kind)) {
1494 ReplaceWithTypeCast(instr); 1582 ReplaceWithTypeCast(instr);
1495 return; 1583 return;
1496 } 1584 }
1497 1585
1498 const ICData& unary_checks = 1586 const ICData& unary_checks =
1499 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); 1587 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
1500 1588
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
Vyacheslav Egorov (Google) 2017/03/10 10:31:30 If you killed the code, kill the flag FLAG_max_equ
erikcorry 2017/03/10 13:30:01 Killed the flag. Original code review has no rati
erikcorry 2017/03/10 13:36:54 I got confused here between the two flags. I'll ch
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)) { 1589 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
1515 return; 1590 return;
1516 } 1591 }
1517 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { 1592 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) {
1518 return; 1593 return;
1519 } 1594 }
1520 1595
1521 if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) { 1596 if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) {
1522 return; 1597 return;
1523 } 1598 }
(...skipping 15 matching lines...) Expand all
1539 return; 1614 return;
1540 } 1615 }
1541 if ((op_kind == Token::kSET) && 1616 if ((op_kind == Token::kSET) &&
1542 TryInlineInstanceSetter(instr, unary_checks)) { 1617 TryInlineInstanceSetter(instr, unary_checks)) {
1543 return; 1618 return;
1544 } 1619 }
1545 if (TryInlineInstanceMethod(instr)) { 1620 if (TryInlineInstanceMethod(instr)) {
1546 return; 1621 return;
1547 } 1622 }
1548 1623
1624 // Now we are done trying the inlining options that benefit from only having
1625 // 1 entry in the IC table.
1626 TryExpandClassesInIC(unary_checks);
1627
1549 bool has_one_target = unary_checks.HasOneTarget(); 1628 bool has_one_target = unary_checks.HasOneTarget();
1550 1629
1551 if (has_one_target) { 1630 if (has_one_target) {
1552 // Check if the single target is a polymorphic target, if it is, 1631 // Check if the single target is a polymorphic target, if it is,
1553 // we don't have one target. 1632 // we don't have one target.
1554 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); 1633 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
1555 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { 1634 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
1556 has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType( 1635 has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType(
1557 unary_checks) != Type::null(); 1636 unary_checks) != Type::null();
1558 } else { 1637 } else {
1559 const bool polymorphic_target = 1638 const bool polymorphic_target =
1560 MethodRecognizer::PolymorphicTarget(target); 1639 MethodRecognizer::PolymorphicTarget(target);
1561 has_one_target = !polymorphic_target; 1640 has_one_target = !polymorphic_target;
1562 } 1641 }
1563 } 1642 }
1564 1643
1565 if (has_one_target) { 1644 if (has_one_target) {
1566 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); 1645 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
1567 const RawFunction::Kind function_kind = target.kind(); 1646 const RawFunction::Kind function_kind = target.kind();
1568 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { 1647 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) {
1569 PolymorphicInstanceCallInstr* call = 1648 PolymorphicInstanceCallInstr* call =
1570 new (Z) PolymorphicInstanceCallInstr(instr, unary_checks, 1649 new (Z) PolymorphicInstanceCallInstr(instr, unary_checks,
1571 /* call_with_checks = */ false, 1650 /* call_with_checks = */ false,
1572 /* complete = */ false); 1651 /* complete = */ false);
1573 instr->ReplaceWith(call, current_iterator()); 1652 instr->ReplaceWith(call, current_iterator());
1574 return; 1653 return;
1575 } 1654 }
1576 } 1655 }
1577 1656
1578 if (number_of_checks <= FLAG_max_polymorphic_checks || 1657 bool call_with_checks;
1579 (has_one_target && is_dense)) { 1658 if (has_one_target && FLAG_polymorphic_with_deopt) {
1580 bool call_with_checks; 1659 // Type propagation has not run yet, we cannot eliminate the check.
1581 if (has_one_target && FLAG_polymorphic_with_deopt) { 1660 AddReceiverCheck(instr);
1582 // Type propagation has not run yet, we cannot eliminate the check. 1661 // Call can still deoptimize, do not detach environment from instr.
1583 AddReceiverCheck(instr); 1662 call_with_checks = false;
1584 // Call can still deoptimize, do not detach environment from instr. 1663 } else {
1585 call_with_checks = false; 1664 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 } 1665 }
1666 PolymorphicInstanceCallInstr* call = new (Z)
1667 PolymorphicInstanceCallInstr(instr, unary_checks, call_with_checks,
1668 /* complete = */ false);
1669 instr->ReplaceWith(call, current_iterator());
1594 } 1670 }
1595 1671
1596 1672
1597 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { 1673 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
1598 MethodRecognizer::Kind recognized_kind = 1674 MethodRecognizer::Kind recognized_kind =
1599 MethodRecognizer::RecognizeKind(call->function()); 1675 MethodRecognizer::RecognizeKind(call->function());
1600 switch (recognized_kind) { 1676 switch (recognized_kind) {
1601 case MethodRecognizer::kObjectConstructor: 1677 case MethodRecognizer::kObjectConstructor:
1602 case MethodRecognizer::kObjectArrayAllocate: 1678 case MethodRecognizer::kObjectArrayAllocate:
1603 case MethodRecognizer::kFloat32x4Zero: 1679 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 1913 // Discard the environment from the original instruction because the store
1838 // can't deoptimize. 1914 // can't deoptimize.
1839 instr->RemoveEnvironment(); 1915 instr->RemoveEnvironment();
1840 ReplaceCall(instr, store); 1916 ReplaceCall(instr, store);
1841 return true; 1917 return true;
1842 } 1918 }
1843 1919
1844 1920
1845 } // namespace dart 1921 } // namespace dart
1846 #endif // DART_PRECOMPILED_RUNTIME 1922 #endif // DART_PRECOMPILED_RUNTIME
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698