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 #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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |