OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 | 4 |
5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
9 #include "vm/flow_graph_builder.h" | 9 #include "vm/flow_graph_builder.h" |
10 #include "vm/flow_graph_compiler.h" | 10 #include "vm/flow_graph_compiler.h" |
(...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
596 type_arguments_field_offset, | 596 type_arguments_field_offset, |
597 Type::ZoneHandle()); // No type. | 597 Type::ZoneHandle()); // No type. |
598 InsertBefore(call, load_type_args, NULL, Definition::kValue); | 598 InsertBefore(call, load_type_args, NULL, Definition::kValue); |
599 instantiator = array->Copy(); | 599 instantiator = array->Copy(); |
600 type_args = new Value(load_type_args); | 600 type_args = new Value(load_type_args); |
601 break; | 601 break; |
602 } | 602 } |
603 case kUint8ArrayCid: | 603 case kUint8ArrayCid: |
604 case kFloat32ArrayCid: | 604 case kFloat32ArrayCid: |
605 case kFloat64ArrayCid: { | 605 case kFloat64ArrayCid: { |
606 ConstantInstr* null_constant = new ConstantInstr(Object::ZoneHandle()); | 606 instantiator = new Value(flow_graph_->constant_null()); |
607 InsertBefore(call, null_constant, NULL, Definition::kValue); | 607 type_args = new Value(flow_graph_->constant_null()); |
608 instantiator = new Value(null_constant); | |
609 type_args = new Value(null_constant); | |
610 ASSERT((class_id != kUint8ArrayCid) || value_type.IsIntType()); | 608 ASSERT((class_id != kUint8ArrayCid) || value_type.IsIntType()); |
611 ASSERT((class_id != kFloat32ArrayCid && class_id != kFloat64ArrayCid) || | 609 ASSERT((class_id != kFloat32ArrayCid && class_id != kFloat64ArrayCid) || |
612 value_type.IsDoubleType()); | 610 value_type.IsDoubleType()); |
613 ASSERT(value_type.IsInstantiated()); | 611 ASSERT(value_type.IsInstantiated()); |
614 break; | 612 break; |
615 } | 613 } |
616 default: | 614 default: |
617 // TODO(fschneider): Add support for other array types. | 615 // TODO(fschneider): Add support for other array types. |
618 UNREACHABLE(); | 616 UNREACHABLE(); |
619 } | 617 } |
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
957 if (function.IsDynamicFunction() && | 955 if (function.IsDynamicFunction() && |
958 callee_receiver->IsParameter() && | 956 callee_receiver->IsParameter() && |
959 (callee_receiver->AsParameter()->index() == 0)) { | 957 (callee_receiver->AsParameter()->index() == 0)) { |
960 return CHA::HasOverride(Class::Handle(function.Owner()), | 958 return CHA::HasOverride(Class::Handle(function.Owner()), |
961 call->function_name()); | 959 call->function_name()); |
962 } | 960 } |
963 return true; | 961 return true; |
964 } | 962 } |
965 | 963 |
966 | 964 |
| 965 bool FlowGraphOptimizer::MethodExtractorNeedsClassCheck( |
| 966 InstanceCallInstr* call) const { |
| 967 if (!FLAG_use_cha) return true; |
| 968 Definition* callee_receiver = call->ArgumentAt(0)->value()->definition(); |
| 969 ASSERT(callee_receiver != NULL); |
| 970 const Function& function = flow_graph_->parsed_function().function(); |
| 971 if (function.IsDynamicFunction() && |
| 972 callee_receiver->IsParameter() && |
| 973 (callee_receiver->AsParameter()->index() == 0)) { |
| 974 const String& field_name = |
| 975 String::Handle(Field::NameFromGetter(call->function_name())); |
| 976 return CHA::HasOverride(Class::Handle(function.Owner()), field_name); |
| 977 } |
| 978 return true; |
| 979 } |
| 980 |
| 981 |
967 void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { | 982 void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { |
968 ASSERT(call->HasICData()); | 983 ASSERT(call->HasICData()); |
969 const ICData& ic_data = *call->ic_data(); | 984 const ICData& ic_data = *call->ic_data(); |
970 Function& target = Function::Handle(); | 985 Function& target = Function::Handle(); |
971 GrowableArray<intptr_t> class_ids; | 986 GrowableArray<intptr_t> class_ids; |
972 ic_data.GetCheckAt(0, &class_ids, &target); | 987 ic_data.GetCheckAt(0, &class_ids, &target); |
973 ASSERT(class_ids.length() == 1); | 988 ASSERT(class_ids.length() == 1); |
974 // Inline implicit instance getter. | 989 // Inline implicit instance getter. |
975 const String& field_name = | 990 const String& field_name = |
976 String::Handle(Field::NameFromGetter(call->function_name())); | 991 String::Handle(Field::NameFromGetter(call->function_name())); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1104 return false; | 1119 return false; |
1105 } | 1120 } |
1106 Function& target = Function::Handle(ic_data.GetTargetAt(0)); | 1121 Function& target = Function::Handle(ic_data.GetTargetAt(0)); |
1107 if (target.kind() == RawFunction::kImplicitGetter) { | 1122 if (target.kind() == RawFunction::kImplicitGetter) { |
1108 if (!ic_data.HasOneTarget()) { | 1123 if (!ic_data.HasOneTarget()) { |
1109 // TODO(srdjan): Implement for mutiple targets. | 1124 // TODO(srdjan): Implement for mutiple targets. |
1110 return false; | 1125 return false; |
1111 } | 1126 } |
1112 InlineImplicitInstanceGetter(call); | 1127 InlineImplicitInstanceGetter(call); |
1113 return true; | 1128 return true; |
| 1129 } else if (target.kind() == RawFunction::kMethodExtractor) { |
| 1130 return false; |
1114 } | 1131 } |
1115 | 1132 |
1116 // Not an implicit getter. | 1133 // Not an implicit getter. |
1117 MethodRecognizer::Kind recognized_kind = | 1134 MethodRecognizer::Kind recognized_kind = |
1118 MethodRecognizer::RecognizeKind(target); | 1135 MethodRecognizer::RecognizeKind(target); |
1119 | 1136 |
1120 // VM objects length getter. | 1137 // VM objects length getter. |
1121 switch (recognized_kind) { | 1138 switch (recognized_kind) { |
1122 case MethodRecognizer::kObjectArrayLength: | 1139 case MethodRecognizer::kObjectArrayLength: |
1123 case MethodRecognizer::kImmutableArrayLength: | 1140 case MethodRecognizer::kImmutableArrayLength: |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1356 | 1373 |
1357 const Token::Kind op_kind = instr->token_kind(); | 1374 const Token::Kind op_kind = instr->token_kind(); |
1358 // Type test is special as it always gets converted into inlined code. | 1375 // Type test is special as it always gets converted into inlined code. |
1359 if (Token::IsTypeTestOperator(op_kind)) { | 1376 if (Token::IsTypeTestOperator(op_kind)) { |
1360 ReplaceWithInstanceOf(instr); | 1377 ReplaceWithInstanceOf(instr); |
1361 return; | 1378 return; |
1362 } | 1379 } |
1363 | 1380 |
1364 const ICData& unary_checks = | 1381 const ICData& unary_checks = |
1365 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); | 1382 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); |
| 1383 |
1366 if ((unary_checks.NumberOfChecks() > FLAG_max_polymorphic_checks) && | 1384 if ((unary_checks.NumberOfChecks() > FLAG_max_polymorphic_checks) && |
1367 InstanceCallNeedsClassCheck(instr)) { | 1385 InstanceCallNeedsClassCheck(instr)) { |
1368 // Too many checks, it will be megamorphic which needs unary checks. | 1386 // Too many checks, it will be megamorphic which needs unary checks. |
1369 instr->set_ic_data(&unary_checks); | 1387 instr->set_ic_data(&unary_checks); |
1370 return; | 1388 return; |
1371 } | 1389 } |
1372 | 1390 |
1373 if ((op_kind == Token::kASSIGN_INDEX) && | 1391 if ((op_kind == Token::kASSIGN_INDEX) && |
1374 TryReplaceWithStoreIndexed(instr)) { | 1392 TryReplaceWithStoreIndexed(instr)) { |
1375 return; | 1393 return; |
(...skipping 12 matching lines...) Expand all Loading... |
1388 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) { | 1406 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) { |
1389 return; | 1407 return; |
1390 } | 1408 } |
1391 if ((op_kind == Token::kSET) && | 1409 if ((op_kind == Token::kSET) && |
1392 TryInlineInstanceSetter(instr, unary_checks)) { | 1410 TryInlineInstanceSetter(instr, unary_checks)) { |
1393 return; | 1411 return; |
1394 } | 1412 } |
1395 if (TryInlineInstanceMethod(instr)) { | 1413 if (TryInlineInstanceMethod(instr)) { |
1396 return; | 1414 return; |
1397 } | 1415 } |
1398 if (!InstanceCallNeedsClassCheck(instr)) { | 1416 |
1399 const bool call_with_checks = false; | 1417 const bool has_one_target = unary_checks.HasOneTarget(); |
1400 PolymorphicInstanceCallInstr* call = | 1418 |
1401 new PolymorphicInstanceCallInstr(instr, unary_checks, | 1419 if (has_one_target) { |
1402 call_with_checks); | 1420 const bool is_method_extraction = |
1403 instr->ReplaceWith(call, current_iterator()); | 1421 Function::Handle(unary_checks.GetTargetAt(0)).IsMethodExtractor(); |
1404 return; | 1422 |
| 1423 if ((is_method_extraction && !MethodExtractorNeedsClassCheck(instr)) || |
| 1424 (!is_method_extraction && !InstanceCallNeedsClassCheck(instr))) { |
| 1425 const bool call_with_checks = false; |
| 1426 PolymorphicInstanceCallInstr* call = |
| 1427 new PolymorphicInstanceCallInstr(instr, unary_checks, |
| 1428 call_with_checks); |
| 1429 instr->ReplaceWith(call, current_iterator()); |
| 1430 return; |
| 1431 } |
1405 } | 1432 } |
| 1433 |
1406 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 1434 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
1407 bool call_with_checks; | 1435 bool call_with_checks; |
1408 if (unary_checks.HasOneTarget()) { | 1436 if (has_one_target) { |
1409 // Type propagation has not run yet, we cannot eliminate the check. | 1437 // Type propagation has not run yet, we cannot eliminate the check. |
1410 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); | 1438 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); |
1411 // Call can still deoptimize, do not detach environment from instr. | 1439 // Call can still deoptimize, do not detach environment from instr. |
1412 call_with_checks = false; | 1440 call_with_checks = false; |
1413 } else { | 1441 } else { |
1414 call_with_checks = true; | 1442 call_with_checks = true; |
1415 } | 1443 } |
1416 PolymorphicInstanceCallInstr* call = | 1444 PolymorphicInstanceCallInstr* call = |
1417 new PolymorphicInstanceCallInstr(instr, unary_checks, | 1445 new PolymorphicInstanceCallInstr(instr, unary_checks, |
1418 call_with_checks); | 1446 call_with_checks); |
(...skipping 3031 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4450 | 4478 |
4451 if (FLAG_trace_constant_propagation) { | 4479 if (FLAG_trace_constant_propagation) { |
4452 OS::Print("\n==== After constant propagation ====\n"); | 4480 OS::Print("\n==== After constant propagation ====\n"); |
4453 FlowGraphPrinter printer(*graph_); | 4481 FlowGraphPrinter printer(*graph_); |
4454 printer.PrintBlocks(); | 4482 printer.PrintBlocks(); |
4455 } | 4483 } |
4456 } | 4484 } |
4457 | 4485 |
4458 | 4486 |
4459 } // namespace dart | 4487 } // namespace dart |
OLD | NEW |