Chromium Code Reviews| 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 |