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

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

Issue 11642003: Create and cache method extraction stub in the ICData. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: ready for review. Created 8 years 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 | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/il_printer.cc » ('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) 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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/il_printer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698