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 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
565 new LoadFieldInstr(array->Copy(), | 565 new LoadFieldInstr(array->Copy(), |
566 type_arguments_field_offset, | 566 type_arguments_field_offset, |
567 Type::ZoneHandle()); // No type. | 567 Type::ZoneHandle()); // No type. |
568 InsertBefore(call, load_type_args, NULL, Definition::kValue); | 568 InsertBefore(call, load_type_args, NULL, Definition::kValue); |
569 instantiator = array->Copy(); | 569 instantiator = array->Copy(); |
570 type_args = new Value(load_type_args); | 570 type_args = new Value(load_type_args); |
571 break; | 571 break; |
572 } | 572 } |
573 case kFloat32ArrayCid: | 573 case kFloat32ArrayCid: |
574 case kFloat64ArrayCid: { | 574 case kFloat64ArrayCid: { |
575 ConstantInstr* null_constant = new ConstantInstr(Object::ZoneHandle()); | 575 instantiator = new Value(flow_graph_->constant_null()); |
576 InsertBefore(call, null_constant, NULL, Definition::kValue); | 576 type_args = new Value(flow_graph_->constant_null()); |
577 instantiator = new Value(null_constant); | |
578 type_args = new Value(null_constant); | |
579 ASSERT(value_type.IsDoubleType()); | 577 ASSERT(value_type.IsDoubleType()); |
580 ASSERT(value_type.IsInstantiated()); | 578 ASSERT(value_type.IsInstantiated()); |
581 break; | 579 break; |
582 } | 580 } |
583 default: | 581 default: |
584 // TODO(fschneider): Add support for other array types. | 582 // TODO(fschneider): Add support for other array types. |
585 UNREACHABLE(); | 583 UNREACHABLE(); |
586 } | 584 } |
587 AssertAssignableInstr* assert_value = | 585 AssertAssignableInstr* assert_value = |
588 new AssertAssignableInstr(call->token_pos(), | 586 new AssertAssignableInstr(call->token_pos(), |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
920 if (function.IsDynamicFunction() && | 918 if (function.IsDynamicFunction() && |
921 callee_receiver->IsParameter() && | 919 callee_receiver->IsParameter() && |
922 (callee_receiver->AsParameter()->index() == 0)) { | 920 (callee_receiver->AsParameter()->index() == 0)) { |
923 return CHA::HasOverride(Class::Handle(function.Owner()), | 921 return CHA::HasOverride(Class::Handle(function.Owner()), |
924 call->function_name()); | 922 call->function_name()); |
925 } | 923 } |
926 return true; | 924 return true; |
927 } | 925 } |
928 | 926 |
929 | 927 |
928 bool FlowGraphOptimizer::MethodExtractorNeedsClassCheck( | |
929 InstanceCallInstr* call) const { | |
930 if (!FLAG_use_cha) return true; | |
931 Definition* callee_receiver = call->ArgumentAt(0)->value()->definition(); | |
932 ASSERT(callee_receiver != NULL); | |
933 const Function& function = flow_graph_->parsed_function().function(); | |
934 if (function.IsDynamicFunction() && | |
935 callee_receiver->IsParameter() && | |
936 (callee_receiver->AsParameter()->index() == 0)) { | |
937 const String& field_name = | |
938 String::Handle(Field::NameFromGetter(call->function_name())); | |
srdjan
2013/01/16 22:08:56
indent 4 spaces
| |
939 return CHA::HasOverride(Class::Handle(function.Owner()), field_name); | |
940 } | |
941 return true; | |
942 } | |
943 | |
944 | |
930 void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { | 945 void FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { |
931 ASSERT(call->HasICData()); | 946 ASSERT(call->HasICData()); |
932 const ICData& ic_data = *call->ic_data(); | 947 const ICData& ic_data = *call->ic_data(); |
933 Function& target = Function::Handle(); | 948 Function& target = Function::Handle(); |
934 GrowableArray<intptr_t> class_ids; | 949 GrowableArray<intptr_t> class_ids; |
935 ic_data.GetCheckAt(0, &class_ids, &target); | 950 ic_data.GetCheckAt(0, &class_ids, &target); |
936 ASSERT(class_ids.length() == 1); | 951 ASSERT(class_ids.length() == 1); |
937 // Inline implicit instance getter. | 952 // Inline implicit instance getter. |
938 const String& field_name = | 953 const String& field_name = |
939 String::Handle(Field::NameFromGetter(call->function_name())); | 954 String::Handle(Field::NameFromGetter(call->function_name())); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1033 | 1048 |
1034 StrictCompareInstr* compare = | 1049 StrictCompareInstr* compare = |
1035 new StrictCompareInstr(Token::kEQ_STRICT, | 1050 new StrictCompareInstr(Token::kEQ_STRICT, |
1036 new Value(load), | 1051 new Value(load), |
1037 new Value(zero)); | 1052 new Value(zero)); |
1038 call->ReplaceWith(compare, current_iterator()); | 1053 call->ReplaceWith(compare, current_iterator()); |
1039 RemovePushArguments(call); | 1054 RemovePushArguments(call); |
1040 } | 1055 } |
1041 | 1056 |
1042 | 1057 |
1058 void FlowGraphOptimizer::InlineMethodExtractor(InstanceCallInstr* call) { | |
1059 Value* receiver = call->ArgumentAt(0)->value(); | |
1060 if (MethodExtractorNeedsClassCheck(call)) { | |
1061 AddCheckClass(call, receiver->Copy()); | |
1062 } | |
1063 | |
1064 // Load and push type arguments. | |
1065 Definition* type_arguments = NULL; | |
1066 | |
1067 const Class& receiver_class = Class::Handle( | |
1068 Isolate::Current()->class_table()->At(ReceiverClassId(call))); | |
1069 const intptr_t type_arguments_field_offset = | |
1070 receiver_class.type_arguments_field_offset(); | |
1071 if (type_arguments_field_offset != Class::kNoTypeArguments) { | |
1072 type_arguments = new LoadFieldInstr(receiver->Copy(), | |
1073 type_arguments_field_offset, | |
1074 Type::ZoneHandle()); // No type. | |
1075 InsertBefore(call, type_arguments, NULL, Definition::kValue); | |
1076 } else { | |
1077 type_arguments = flow_graph_->constant_null(); | |
1078 } | |
1079 | |
1080 PushArgumentInstr* push_type_arguments = | |
1081 new PushArgumentInstr(new Value(type_arguments)); | |
1082 InsertBefore(call, push_type_arguments, NULL, Definition::kEffect); | |
1083 | |
1084 ZoneGrowableArray<PushArgumentInstr*>* args = | |
1085 new ZoneGrowableArray<PushArgumentInstr*>(2); | |
1086 | |
1087 args->Add(call->ArgumentAt(0)); | |
1088 args->Add(push_type_arguments); | |
1089 | |
1090 const Function& extractor = Function::Handle(call->ic_data()->GetTargetAt(0)); | |
1091 const Function& function = | |
1092 Function::ZoneHandle(extractor.extracted_method_closure()); | |
1093 ASSERT(function.IsImplicitInstanceClosureFunction()); | |
1094 call->set_env(NULL); | |
1095 CreateClosureInstr* create_closure = | |
1096 new CreateClosureInstr(function, args, call->token_pos()); | |
1097 call->ReplaceWith(create_closure, current_iterator()); | |
1098 } | |
1099 | |
1100 | |
1043 // Only unique implicit instance getters can be currently handled. | 1101 // Only unique implicit instance getters can be currently handled. |
1044 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { | 1102 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
1045 ASSERT(call->HasICData()); | 1103 ASSERT(call->HasICData()); |
1046 const ICData& ic_data = *call->ic_data(); | 1104 const ICData& ic_data = *call->ic_data(); |
1047 if (ic_data.NumberOfChecks() == 0) { | 1105 if (ic_data.NumberOfChecks() == 0) { |
1048 // No type feedback collected. | 1106 // No type feedback collected. |
1049 return false; | 1107 return false; |
1050 } | 1108 } |
1051 Function& target = Function::Handle(ic_data.GetTargetAt(0)); | 1109 Function& target = Function::Handle(ic_data.GetTargetAt(0)); |
1052 if (target.kind() == RawFunction::kImplicitGetter) { | 1110 if (target.kind() == RawFunction::kImplicitGetter) { |
1053 if (!ic_data.HasOneTarget()) { | 1111 if (!ic_data.HasOneTarget()) { |
1054 // TODO(srdjan): Implement for mutiple targets. | 1112 // TODO(srdjan): Implement for mutiple targets. |
1055 return false; | 1113 return false; |
1056 } | 1114 } |
1057 InlineImplicitInstanceGetter(call); | 1115 InlineImplicitInstanceGetter(call); |
1058 return true; | 1116 return true; |
1117 } else if (target.kind() == RawFunction::kMethodExtractor) { | |
1118 if (!ic_data.HasOneTarget()) { | |
1119 return false; | |
1120 } | |
1121 InlineMethodExtractor(call); | |
1122 return true; | |
1059 } | 1123 } |
1060 | 1124 |
1061 // Not an implicit getter. | 1125 // Not an implicit getter. |
1062 MethodRecognizer::Kind recognized_kind = | 1126 MethodRecognizer::Kind recognized_kind = |
1063 MethodRecognizer::RecognizeKind(target); | 1127 MethodRecognizer::RecognizeKind(target); |
1064 | 1128 |
1065 // VM objects length getter. | 1129 // VM objects length getter. |
1066 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || | 1130 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || |
1067 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || | 1131 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || |
1068 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { | 1132 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1217 // Tries to optimize instance call by replacing it with a faster instruction | 1281 // Tries to optimize instance call by replacing it with a faster instruction |
1218 // (e.g, binary op, field load, ..). | 1282 // (e.g, binary op, field load, ..). |
1219 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 1283 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
1220 if (!instr->HasICData() || (instr->ic_data()->NumberOfChecks() == 0)) { | 1284 if (!instr->HasICData() || (instr->ic_data()->NumberOfChecks() == 0)) { |
1221 // An instance call without ICData will trigger deoptimization. | 1285 // An instance call without ICData will trigger deoptimization. |
1222 return; | 1286 return; |
1223 } | 1287 } |
1224 | 1288 |
1225 const ICData& unary_checks = | 1289 const ICData& unary_checks = |
1226 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); | 1290 ICData::ZoneHandle(instr->ic_data()->AsUnaryClassChecks()); |
1291 const bool has_one_target = unary_checks.HasOneTarget(); | |
1227 if ((unary_checks.NumberOfChecks() > FLAG_max_polymorphic_checks) && | 1292 if ((unary_checks.NumberOfChecks() > FLAG_max_polymorphic_checks) && |
1228 InstanceCallNeedsClassCheck(instr)) { | 1293 InstanceCallNeedsClassCheck(instr)) { |
1229 // Too many checks, it will be megamorphic which needs unary checks. | 1294 // Too many checks, it will be megamorphic which needs unary checks. |
1230 instr->set_ic_data(&unary_checks); | 1295 instr->set_ic_data(&unary_checks); |
1231 return; | 1296 return; |
1232 } | 1297 } |
1233 | 1298 |
1234 const Token::Kind op_kind = instr->token_kind(); | 1299 const Token::Kind op_kind = instr->token_kind(); |
1235 if ((op_kind == Token::kASSIGN_INDEX) && | 1300 if ((op_kind == Token::kASSIGN_INDEX) && |
1236 TryReplaceWithStoreIndexed(instr)) { | 1301 TryReplaceWithStoreIndexed(instr)) { |
(...skipping 13 matching lines...) Expand all Loading... | |
1250 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) { | 1315 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) { |
1251 return; | 1316 return; |
1252 } | 1317 } |
1253 if ((op_kind == Token::kSET) && | 1318 if ((op_kind == Token::kSET) && |
1254 TryInlineInstanceSetter(instr, unary_checks)) { | 1319 TryInlineInstanceSetter(instr, unary_checks)) { |
1255 return; | 1320 return; |
1256 } | 1321 } |
1257 if (TryInlineInstanceMethod(instr)) { | 1322 if (TryInlineInstanceMethod(instr)) { |
1258 return; | 1323 return; |
1259 } | 1324 } |
1260 if (!InstanceCallNeedsClassCheck(instr)) { | 1325 if (has_one_target && !InstanceCallNeedsClassCheck(instr)) { |
1326 ASSERT(!Function::Handle(unary_checks.GetTargetAt(0)).IsMethodExtractor()); | |
1261 const bool call_with_checks = false; | 1327 const bool call_with_checks = false; |
1262 PolymorphicInstanceCallInstr* call = | 1328 PolymorphicInstanceCallInstr* call = |
1263 new PolymorphicInstanceCallInstr(instr, unary_checks, | 1329 new PolymorphicInstanceCallInstr(instr, unary_checks, |
1264 call_with_checks); | 1330 call_with_checks); |
1265 instr->ReplaceWith(call, current_iterator()); | 1331 instr->ReplaceWith(call, current_iterator()); |
1266 return; | 1332 return; |
1267 } | 1333 } |
1268 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | 1334 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { |
1269 bool call_with_checks; | 1335 bool call_with_checks; |
1270 if (unary_checks.HasOneTarget()) { | 1336 if (has_one_target) { |
1271 // Type propagation has not run yet, we cannot eliminate the check. | 1337 // Type propagation has not run yet, we cannot eliminate the check. |
1272 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); | 1338 AddCheckClass(instr, instr->ArgumentAt(0)->value()->Copy()); |
1273 // Call can still deoptimize, do not detach environment from instr. | 1339 // Call can still deoptimize, do not detach environment from instr. |
1274 call_with_checks = false; | 1340 call_with_checks = false; |
1275 } else { | 1341 } else { |
1276 call_with_checks = true; | 1342 call_with_checks = true; |
1277 } | 1343 } |
1278 PolymorphicInstanceCallInstr* call = | 1344 PolymorphicInstanceCallInstr* call = |
1279 new PolymorphicInstanceCallInstr(instr, unary_checks, | 1345 new PolymorphicInstanceCallInstr(instr, unary_checks, |
1280 call_with_checks); | 1346 call_with_checks); |
(...skipping 2988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4269 | 4335 |
4270 if (FLAG_trace_constant_propagation) { | 4336 if (FLAG_trace_constant_propagation) { |
4271 OS::Print("\n==== After constant propagation ====\n"); | 4337 OS::Print("\n==== After constant propagation ====\n"); |
4272 FlowGraphPrinter printer(*graph_); | 4338 FlowGraphPrinter printer(*graph_); |
4273 printer.PrintBlocks(); | 4339 printer.PrintBlocks(); |
4274 } | 4340 } |
4275 } | 4341 } |
4276 | 4342 |
4277 | 4343 |
4278 } // namespace dart | 4344 } // namespace dart |
OLD | NEW |