| 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 |