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

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

Issue 2734883002: ICData::NumberOfChecks is O(n) so don't call it in loops (Closed)
Patch Set: Add const 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
« no previous file with comments | « runtime/vm/intermediate_language_x64.cc ('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 420 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 } 431 }
432 return true; 432 return true;
433 } 433 }
434 434
435 435
436 bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { 436 bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
437 // Check for monomorphic IC data. 437 // Check for monomorphic IC data.
438 if (!call->HasICData()) return false; 438 if (!call->HasICData()) return false;
439 const ICData& ic_data = 439 const ICData& ic_data =
440 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); 440 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks());
441 if (ic_data.NumberOfChecks() != 1) { 441 if (!ic_data.NumberOfChecksIs(1)) {
442 return false; 442 return false;
443 } 443 }
444 return FlowGraphInliner::TryReplaceInstanceCallWithInline( 444 return FlowGraphInliner::TryReplaceInstanceCallWithInline(
445 flow_graph_, current_iterator(), call); 445 flow_graph_, current_iterator(), call);
446 } 446 }
447 447
448 448
449 // Return true if d is a string of length one (a constant or result from 449 // Return true if d is a string of length one (a constant or result from
450 // from string-from-char-code instruction. 450 // from string-from-char-code instruction.
451 static bool IsLengthOneString(Definition* d) { 451 static bool IsLengthOneString(Definition* d) {
(...skipping 739 matching lines...) Expand 10 before | Expand all | Expand 10 after
1191 // Unknown result. 1191 // Unknown result.
1192 return Bool::null(); 1192 return Bool::null();
1193 } 1193 }
1194 } 1194 }
1195 1195
1196 const ClassTable& class_table = *isolate()->class_table(); 1196 const ClassTable& class_table = *isolate()->class_table();
1197 Bool& prev = Bool::Handle(Z); 1197 Bool& prev = Bool::Handle(Z);
1198 Class& cls = Class::Handle(Z); 1198 Class& cls = Class::Handle(Z);
1199 1199
1200 bool results_differ = false; 1200 bool results_differ = false;
1201 for (int i = 0; i < ic_data.NumberOfChecks(); i++) { 1201 const intptr_t number_of_checks = ic_data.NumberOfChecks();
1202 for (int i = 0; i < number_of_checks; i++) {
1202 cls = class_table.At(ic_data.GetReceiverClassIdAt(i)); 1203 cls = class_table.At(ic_data.GetReceiverClassIdAt(i));
1203 if (cls.NumTypeArguments() > 0) { 1204 if (cls.NumTypeArguments() > 0) {
1204 return Bool::null(); 1205 return Bool::null();
1205 } 1206 }
1206 // As of Dart 1.5, the Null type is a subtype of (and is more specific than) 1207 // As of Dart 1.5, the Null type is a subtype of (and is more specific than)
1207 // any type. However, we are checking instances here and not types. The 1208 // any type. However, we are checking instances here and not types. The
1208 // null instance is only an instance of Null, Object, and dynamic. 1209 // null instance is only an instance of Null, Object, and dynamic.
1209 const bool is_subtype = 1210 const bool is_subtype =
1210 cls.IsNullClass() 1211 cls.IsNullClass()
1211 ? (type_class.IsNullClass() || type_class.IsObjectClass() || 1212 ? (type_class.IsNullClass() || type_class.IsObjectClass() ||
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1369 } else { 1370 } else {
1370 type_args = call->ArgumentAt(1); 1371 type_args = call->ArgumentAt(1);
1371 type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw(); 1372 type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw();
1372 negate = 1373 negate =
1373 Bool::Cast( 1374 Bool::Cast(
1374 call->ArgumentAt(3)->OriginalDefinition()->AsConstant()->value()) 1375 call->ArgumentAt(3)->OriginalDefinition()->AsConstant()->value())
1375 .value(); 1376 .value();
1376 } 1377 }
1377 const ICData& unary_checks = 1378 const ICData& unary_checks =
1378 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 1379 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
1379 if ((unary_checks.NumberOfChecks() > 0) && 1380 const intptr_t number_of_checks = unary_checks.NumberOfChecks();
1380 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { 1381 if ((number_of_checks > 0) &&
1382 (number_of_checks <= FLAG_max_polymorphic_checks)) {
1381 ZoneGrowableArray<intptr_t>* results = 1383 ZoneGrowableArray<intptr_t>* results =
1382 new (Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); 1384 new (Z) ZoneGrowableArray<intptr_t>(number_of_checks * 2);
1383 Bool& as_bool = 1385 Bool& as_bool =
1384 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results)); 1386 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results));
1385 if (as_bool.IsNull()) { 1387 if (as_bool.IsNull()) {
1386 if (results->length() == unary_checks.NumberOfChecks() * 2) { 1388 if (results->length() == number_of_checks * 2) {
1387 const bool can_deopt = TryExpandTestCidsResult(results, type); 1389 const bool can_deopt = TryExpandTestCidsResult(results, type);
1388 TestCidsInstr* test_cids = new (Z) TestCidsInstr( 1390 TestCidsInstr* test_cids = new (Z) TestCidsInstr(
1389 call->token_pos(), negate ? Token::kISNOT : Token::kIS, 1391 call->token_pos(), negate ? Token::kISNOT : Token::kIS,
1390 new (Z) Value(left), *results, 1392 new (Z) Value(left), *results,
1391 can_deopt ? call->deopt_id() : Thread::kNoDeoptId); 1393 can_deopt ? call->deopt_id() : Thread::kNoDeoptId);
1392 // Remove type. 1394 // Remove type.
1393 ReplaceCall(call, test_cids); 1395 ReplaceCall(call, test_cids);
1394 return; 1396 return;
1395 } 1397 }
1396 } else { 1398 } else {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1438 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). 1440 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
1439 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { 1441 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
1440 ASSERT(Token::IsTypeCastOperator(call->token_kind())); 1442 ASSERT(Token::IsTypeCastOperator(call->token_kind()));
1441 Definition* left = call->ArgumentAt(0); 1443 Definition* left = call->ArgumentAt(0);
1442 Definition* type_args = call->ArgumentAt(1); 1444 Definition* type_args = call->ArgumentAt(1);
1443 const AbstractType& type = 1445 const AbstractType& type =
1444 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); 1446 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value());
1445 ASSERT(!type.IsMalformedOrMalbounded()); 1447 ASSERT(!type.IsMalformedOrMalbounded());
1446 const ICData& unary_checks = 1448 const ICData& unary_checks =
1447 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 1449 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
1448 if ((unary_checks.NumberOfChecks() > 0) && 1450 const intptr_t number_of_checks = unary_checks.NumberOfChecks();
1449 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { 1451 if ((number_of_checks > 0) &&
1452 (number_of_checks <= FLAG_max_polymorphic_checks)) {
1450 ZoneGrowableArray<intptr_t>* results = 1453 ZoneGrowableArray<intptr_t>* results =
1451 new (Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); 1454 new (Z) ZoneGrowableArray<intptr_t>(number_of_checks * 2);
1452 const Bool& as_bool = 1455 const Bool& as_bool =
1453 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results)); 1456 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results));
1454 if (as_bool.raw() == Bool::True().raw()) { 1457 if (as_bool.raw() == Bool::True().raw()) {
1455 AddReceiverCheck(call); 1458 AddReceiverCheck(call);
1456 // Remove the original push arguments. 1459 // Remove the original push arguments.
1457 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 1460 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
1458 PushArgumentInstr* push = call->PushArgumentAt(i); 1461 PushArgumentInstr* push = call->PushArgumentAt(i);
1459 push->ReplaceUsesWith(push->value()->definition()); 1462 push->ReplaceUsesWith(push->value()->definition());
1460 push->RemoveFromGraph(); 1463 push->RemoveFromGraph();
1461 } 1464 }
(...skipping 30 matching lines...) Expand all
1492 return; 1495 return;
1493 } 1496 }
1494 1497
1495 const ICData& unary_checks = 1498 const ICData& unary_checks =
1496 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); 1499 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
1497 1500
1498 const bool is_dense = CheckClassInstr::IsDenseCidRange(unary_checks); 1501 const bool is_dense = CheckClassInstr::IsDenseCidRange(unary_checks);
1499 const intptr_t max_checks = (op_kind == Token::kEQ) 1502 const intptr_t max_checks = (op_kind == Token::kEQ)
1500 ? FLAG_max_equality_polymorphic_checks 1503 ? FLAG_max_equality_polymorphic_checks
1501 : FLAG_max_polymorphic_checks; 1504 : FLAG_max_polymorphic_checks;
1502 if ((unary_checks.NumberOfChecks() > max_checks) && !is_dense && 1505 const intptr_t number_of_checks = unary_checks.NumberOfChecks();
1506 if ((number_of_checks > max_checks) && !is_dense &&
1503 flow_graph()->InstanceCallNeedsClassCheck( 1507 flow_graph()->InstanceCallNeedsClassCheck(
1504 instr, RawFunction::kRegularFunction)) { 1508 instr, RawFunction::kRegularFunction)) {
1505 // Too many checks, it will be megamorphic which needs unary checks. 1509 // Too many checks, it will be megamorphic which needs unary checks.
1506 instr->set_ic_data(&unary_checks); 1510 instr->set_ic_data(&unary_checks);
1507 return; 1511 return;
1508 } 1512 }
1509 1513
1510 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { 1514 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
1511 return; 1515 return;
1512 } 1516 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1564 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { 1568 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) {
1565 PolymorphicInstanceCallInstr* call = 1569 PolymorphicInstanceCallInstr* call =
1566 new (Z) PolymorphicInstanceCallInstr(instr, unary_checks, 1570 new (Z) PolymorphicInstanceCallInstr(instr, unary_checks,
1567 /* call_with_checks = */ false, 1571 /* call_with_checks = */ false,
1568 /* complete = */ false); 1572 /* complete = */ false);
1569 instr->ReplaceWith(call, current_iterator()); 1573 instr->ReplaceWith(call, current_iterator());
1570 return; 1574 return;
1571 } 1575 }
1572 } 1576 }
1573 1577
1574 if ((unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) || 1578 if (number_of_checks <= FLAG_max_polymorphic_checks ||
1575 (has_one_target && is_dense)) { 1579 (has_one_target && is_dense)) {
1576 bool call_with_checks; 1580 bool call_with_checks;
1577 if (has_one_target && FLAG_polymorphic_with_deopt) { 1581 if (has_one_target && FLAG_polymorphic_with_deopt) {
1578 // Type propagation has not run yet, we cannot eliminate the check. 1582 // Type propagation has not run yet, we cannot eliminate the check.
1579 AddReceiverCheck(instr); 1583 AddReceiverCheck(instr);
1580 // Call can still deoptimize, do not detach environment from instr. 1584 // Call can still deoptimize, do not detach environment from instr.
1581 call_with_checks = false; 1585 call_with_checks = false;
1582 } else { 1586 } else {
1583 call_with_checks = true; 1587 call_with_checks = true;
1584 } 1588 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1616 case MethodRecognizer::kMathAtan: 1620 case MethodRecognizer::kMathAtan:
1617 case MethodRecognizer::kMathAtan2: 1621 case MethodRecognizer::kMathAtan2:
1618 FlowGraphInliner::TryReplaceStaticCallWithInline( 1622 FlowGraphInliner::TryReplaceStaticCallWithInline(
1619 flow_graph_, current_iterator(), call); 1623 flow_graph_, current_iterator(), call);
1620 break; 1624 break;
1621 case MethodRecognizer::kMathMin: 1625 case MethodRecognizer::kMathMin:
1622 case MethodRecognizer::kMathMax: { 1626 case MethodRecognizer::kMathMax: {
1623 // We can handle only monomorphic min/max call sites with both arguments 1627 // We can handle only monomorphic min/max call sites with both arguments
1624 // being either doubles or smis. 1628 // being either doubles or smis.
1625 if (CanUnboxDouble() && call->HasICData() && 1629 if (CanUnboxDouble() && call->HasICData() &&
1626 (call->ic_data()->NumberOfChecks() == 1)) { 1630 call->ic_data()->NumberOfChecksIs(1)) {
1627 const ICData& ic_data = *call->ic_data(); 1631 const ICData& ic_data = *call->ic_data();
1628 intptr_t result_cid = kIllegalCid; 1632 intptr_t result_cid = kIllegalCid;
1629 if (ICDataHasReceiverArgumentClassIds(ic_data, kDoubleCid, 1633 if (ICDataHasReceiverArgumentClassIds(ic_data, kDoubleCid,
1630 kDoubleCid)) { 1634 kDoubleCid)) {
1631 result_cid = kDoubleCid; 1635 result_cid = kDoubleCid;
1632 } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, 1636 } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid,
1633 kSmiCid)) { 1637 kSmiCid)) {
1634 result_cid = kSmiCid; 1638 result_cid = kSmiCid;
1635 } 1639 }
1636 if (result_cid != kIllegalCid) { 1640 if (result_cid != kIllegalCid) {
1637 MathMinMaxInstr* min_max = new (Z) MathMinMaxInstr( 1641 MathMinMaxInstr* min_max = new (Z) MathMinMaxInstr(
1638 recognized_kind, new (Z) Value(call->ArgumentAt(0)), 1642 recognized_kind, new (Z) Value(call->ArgumentAt(0)),
1639 new (Z) Value(call->ArgumentAt(1)), call->deopt_id(), result_cid); 1643 new (Z) Value(call->ArgumentAt(1)), call->deopt_id(), result_cid);
1640 const ICData& unary_checks = 1644 const ICData& unary_checks =
1641 ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks()); 1645 ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks());
1642 AddCheckClass(min_max->left()->definition(), unary_checks, 1646 AddCheckClass(min_max->left()->definition(), unary_checks,
1643 call->deopt_id(), call->env(), call); 1647 call->deopt_id(), call->env(), call);
1644 AddCheckClass(min_max->right()->definition(), unary_checks, 1648 AddCheckClass(min_max->right()->definition(), unary_checks,
1645 call->deopt_id(), call->env(), call); 1649 call->deopt_id(), call->env(), call);
1646 ReplaceCall(call, min_max); 1650 ReplaceCall(call, min_max);
1647 } 1651 }
1648 } 1652 }
1649 break; 1653 break;
1650 } 1654 }
1651 1655
1652 case MethodRecognizer::kDoubleFromInteger: { 1656 case MethodRecognizer::kDoubleFromInteger: {
1653 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { 1657 if (call->HasICData() && call->ic_data()->NumberOfChecksIs(1)) {
1654 const ICData& ic_data = *call->ic_data(); 1658 const ICData& ic_data = *call->ic_data();
1655 if (CanUnboxDouble()) { 1659 if (CanUnboxDouble()) {
1656 if (ArgIsAlways(kSmiCid, ic_data, 1)) { 1660 if (ArgIsAlways(kSmiCid, ic_data, 1)) {
1657 Definition* arg = call->ArgumentAt(1); 1661 Definition* arg = call->ArgumentAt(1);
1658 AddCheckSmi(arg, call->deopt_id(), call->env(), call); 1662 AddCheckSmi(arg, call->deopt_id(), call->env(), call);
1659 ReplaceCall(call, new (Z) SmiToDoubleInstr(new (Z) Value(arg), 1663 ReplaceCall(call, new (Z) SmiToDoubleInstr(new (Z) Value(arg),
1660 call->token_pos())); 1664 call->token_pos()));
1661 } else if (ArgIsAlways(kMintCid, ic_data, 1) && 1665 } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
1662 CanConvertUnboxedMintToDouble()) { 1666 CanConvertUnboxedMintToDouble()) {
1663 Definition* arg = call->ArgumentAt(1); 1667 Definition* arg = call->ArgumentAt(1);
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
1762 void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { 1766 void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
1763 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. 1767 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
1764 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) 1768 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
1765 if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedMint); 1769 if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedMint);
1766 #endif 1770 #endif
1767 } 1771 }
1768 1772
1769 1773
1770 bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, 1774 bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
1771 const ICData& unary_ic_data) { 1775 const ICData& unary_ic_data) {
1772 ASSERT((unary_ic_data.NumberOfChecks() > 0) && 1776 ASSERT(!unary_ic_data.NumberOfChecksIs(0) &&
1773 (unary_ic_data.NumArgsTested() == 1)); 1777 (unary_ic_data.NumArgsTested() == 1));
1774 if (I->type_checks()) { 1778 if (I->type_checks()) {
1775 // Checked mode setters are inlined like normal methods by conventional 1779 // Checked mode setters are inlined like normal methods by conventional
1776 // inlining. 1780 // inlining.
1777 return false; 1781 return false;
1778 } 1782 }
1779 1783
1780 ASSERT(instr->HasICData()); 1784 ASSERT(instr->HasICData());
1781 if (unary_ic_data.NumberOfChecks() == 0) { 1785 if (unary_ic_data.NumberOfChecksIs(0)) {
1782 // No type feedback collected. 1786 // No type feedback collected.
1783 return false; 1787 return false;
1784 } 1788 }
1785 if (!unary_ic_data.HasOneTarget()) { 1789 if (!unary_ic_data.HasOneTarget()) {
1786 // Polymorphic sites are inlined like normal method calls by conventional 1790 // Polymorphic sites are inlined like normal method calls by conventional
1787 // inlining. 1791 // inlining.
1788 return false; 1792 return false;
1789 } 1793 }
1790 Function& target = Function::Handle(Z); 1794 Function& target = Function::Handle(Z);
1791 intptr_t class_id; 1795 intptr_t class_id;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1833 // Discard the environment from the original instruction because the store 1837 // Discard the environment from the original instruction because the store
1834 // can't deoptimize. 1838 // can't deoptimize.
1835 instr->RemoveEnvironment(); 1839 instr->RemoveEnvironment();
1836 ReplaceCall(instr, store); 1840 ReplaceCall(instr, store);
1837 return true; 1841 return true;
1838 } 1842 }
1839 1843
1840 1844
1841 } // namespace dart 1845 } // namespace dart
1842 #endif // DART_PRECOMPILED_RUNTIME 1846 #endif // DART_PRECOMPILED_RUNTIME
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language_x64.cc ('k') | runtime/vm/object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698