| 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/flow_graph_builder.h" | 7 #include "vm/flow_graph_builder.h" |
| 8 #include "vm/il_printer.h" | 8 #include "vm/il_printer.h" |
| 9 #include "vm/object_store.h" | 9 #include "vm/object_store.h" |
| 10 | 10 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 DECLARE_FLAG(bool, enable_type_checks); | 13 DECLARE_FLAG(bool, enable_type_checks); |
| 14 DECLARE_FLAG(bool, print_flow_graph); | 14 DECLARE_FLAG(bool, print_flow_graph); |
| 15 DECLARE_FLAG(bool, trace_optimization); | 15 DECLARE_FLAG(bool, trace_optimization); |
| 16 | 16 |
| 17 // TODO(srdjan): Add _ByteArrayBase, get:length. |
| 18 |
| 19 #define RECOGNIZED_LIST(V) \ |
| 20 V(ObjectArray, get:length, ObjectArrayLength) \ |
| 21 V(ImmutableArray, get:length, ImmutableArrayLength) \ |
| 22 V(GrowableObjectArray, get:length, GrowableArrayLength) \ |
| 23 V(StringBase, get:length, StringBaseLength) \ |
| 24 V(IntegerImplementation, toDouble, IntegerToDouble) \ |
| 25 V(Double, toDouble, DoubleToDouble) \ |
| 26 V(Math, sqrt, MathSqrt) \ |
| 27 |
| 28 // Class that recognizes the name and owner of a function and returns the |
| 29 // corresponding enum. See RECOGNIZED_LIST above for list of recognizable |
| 30 // functions. |
| 31 class MethodRecognizer : public AllStatic { |
| 32 public: |
| 33 enum Kind { |
| 34 kUnknown, |
| 35 #define DEFINE_ENUM_LIST(class_name, function_name, enum_name) k##enum_name, |
| 36 RECOGNIZED_LIST(DEFINE_ENUM_LIST) |
| 37 #undef DEFINE_ENUM_LIST |
| 38 }; |
| 39 |
| 40 static Kind RecognizeKind(const Function& function) { |
| 41 // Only core library methods can be recognized. |
| 42 const Library& core_lib = Library::Handle(Library::CoreLibrary()); |
| 43 const Library& core_impl_lib = Library::Handle(Library::CoreImplLibrary()); |
| 44 const Class& function_class = Class::Handle(function.owner()); |
| 45 if ((function_class.library() != core_lib.raw()) && |
| 46 (function_class.library() != core_impl_lib.raw())) { |
| 47 return kUnknown; |
| 48 } |
| 49 const String& recognize_name = String::Handle(function.name()); |
| 50 const String& recognize_class = String::Handle(function_class.Name()); |
| 51 String& test_function_name = String::Handle(); |
| 52 String& test_class_name = String::Handle(); |
| 53 #define RECOGNIZE_FUNCTION(class_name, function_name, enum_name) \ |
| 54 test_function_name = String::NewSymbol(#function_name); \ |
| 55 test_class_name = String::NewSymbol(#class_name); \ |
| 56 if (recognize_name.Equals(test_function_name) && \ |
| 57 recognize_class.Equals(test_class_name)) { \ |
| 58 return k##enum_name; \ |
| 59 } |
| 60 RECOGNIZED_LIST(RECOGNIZE_FUNCTION) |
| 61 #undef RECOGNIZE_FUNCTION |
| 62 return kUnknown; |
| 63 } |
| 64 |
| 65 static const char* KindToCString(Kind kind) { |
| 66 #define KIND_TO_STRING(class_name, function_name, enum_name) \ |
| 67 if (kind == k##enum_name) return #enum_name; |
| 68 RECOGNIZED_LIST(KIND_TO_STRING) |
| 69 #undef KIND_TO_STRING |
| 70 return "?"; |
| 71 } |
| 72 }; |
| 73 |
| 74 |
| 17 void FlowGraphOptimizer::ApplyICData() { | 75 void FlowGraphOptimizer::ApplyICData() { |
| 18 VisitBlocks(); | 76 VisitBlocks(); |
| 19 if (FLAG_print_flow_graph) { | 77 if (FLAG_print_flow_graph) { |
| 20 OS::Print("After Optimizations:\n"); | 78 OS::Print("After Optimizations:\n"); |
| 21 FlowGraphPrinter printer(Function::Handle(), block_order_); | 79 FlowGraphPrinter printer(Function::Handle(), block_order_); |
| 22 printer.PrintBlocks(); | 80 printer.PrintBlocks(); |
| 23 } | 81 } |
| 24 } | 82 } |
| 25 | 83 |
| 26 | 84 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 if (unary_op != NULL) { | 224 if (unary_op != NULL) { |
| 167 ASSERT(unary_op->ic_data() == NULL); | 225 ASSERT(unary_op->ic_data() == NULL); |
| 168 unary_op->set_ic_data(comp->ic_data()); | 226 unary_op->set_ic_data(comp->ic_data()); |
| 169 unary_op->set_instr(comp->instr()); | 227 unary_op->set_instr(comp->instr()); |
| 170 comp->instr()->replace_computation(unary_op); | 228 comp->instr()->replace_computation(unary_op); |
| 171 } | 229 } |
| 172 } | 230 } |
| 173 | 231 |
| 174 | 232 |
| 175 // Returns true if all targets are the same. | 233 // Returns true if all targets are the same. |
| 234 // TODO(srdjan): if targets are native use their C_function to compare. |
| 176 static bool HasOneTarget(const ICData& ic_data) { | 235 static bool HasOneTarget(const ICData& ic_data) { |
| 177 ASSERT(ic_data.NumberOfChecks() > 0); | 236 ASSERT(ic_data.NumberOfChecks() > 0); |
| 178 Function& prev_target = Function::Handle(); | 237 Function& prev_target = Function::Handle(); |
| 179 GrowableArray<const Class*> classes; | 238 GrowableArray<const Class*> classes; |
| 180 ic_data.GetCheckAt(0, &classes, &prev_target); | 239 ic_data.GetCheckAt(0, &classes, &prev_target); |
| 181 ASSERT(!prev_target.IsNull()); | 240 ASSERT(!prev_target.IsNull()); |
| 182 Function& target = Function::Handle(); | 241 Function& target = Function::Handle(); |
| 183 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { | 242 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { |
| 184 ic_data.GetCheckAt(i, &classes, &target); | 243 ic_data.GetCheckAt(i, &classes, &target); |
| 185 ASSERT(!target.IsNull()); | 244 ASSERT(!target.IsNull()); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 232 } | 291 } |
| 233 return result; | 292 return result; |
| 234 } | 293 } |
| 235 | 294 |
| 236 | 295 |
| 237 // Only unique implicit instance getters can be currently handled. | 296 // Only unique implicit instance getters can be currently handled. |
| 238 void FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallComp* comp) { | 297 void FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallComp* comp) { |
| 239 ASSERT(comp->HasICData()); | 298 ASSERT(comp->HasICData()); |
| 240 const ICData& ic_data = *comp->ic_data(); | 299 const ICData& ic_data = *comp->ic_data(); |
| 241 if (ic_data.NumberOfChecks() == 0) { | 300 if (ic_data.NumberOfChecks() == 0) { |
| 242 // No type feedback collected | 301 // No type feedback collected. |
| 243 return; | |
| 244 } | |
| 245 if (!HasOneTarget(ic_data)) { | |
| 246 // TODO(srdjan): Implement when not all targets are the sa,e. | |
| 247 return; | 302 return; |
| 248 } | 303 } |
| 249 Function& target = Function::Handle(); | 304 Function& target = Function::Handle(); |
| 250 Class& cls = Class::Handle(); | 305 GrowableArray<const Class*> classes; |
| 251 ic_data.GetOneClassCheckAt(0, &cls, &target); | 306 ic_data.GetCheckAt(0, &classes, &target); |
| 252 if (target.kind() != RawFunction::kImplicitGetter) { | 307 ASSERT(classes.length() == 1); |
| 253 // Not an implicit getter. | 308 |
| 254 // TODO(srdjan): Inline special getters (e.g., array length). | 309 if (target.kind() == RawFunction::kImplicitGetter) { |
| 310 if (!HasOneTarget(ic_data)) { |
| 311 // TODO(srdjan): Implement for mutiple targets. |
| 312 return; |
| 313 } |
| 314 // Inline implicit instance getter. |
| 315 const String& field_name = |
| 316 String::Handle(Field::NameFromGetter(comp->function_name())); |
| 317 const Field& field = Field::Handle(GetField(*classes[0], field_name)); |
| 318 ASSERT(!field.IsNull()); |
| 319 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( |
| 320 field, comp->InputAt(0), comp, ExtractClassIds(ic_data)); |
| 321 // Replace 'comp' with 'load'. |
| 322 load->set_instr(comp->instr()); |
| 323 comp->instr()->replace_computation(load); |
| 255 return; | 324 return; |
| 256 } | 325 } |
| 257 // Inline implicit instance getter. | 326 |
| 258 const String& field_name = | 327 // Not an implicit getter. |
| 259 String::Handle(Field::NameFromGetter(comp->function_name())); | 328 MethodRecognizer::Kind recognized_kind = |
| 260 const Field& field = Field::Handle(GetField(cls, field_name)); | 329 MethodRecognizer::RecognizeKind(target); |
| 261 ASSERT(!field.IsNull()); | 330 |
| 262 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( | 331 // VM objects length getter. |
| 263 field, comp->InputAt(0), comp, ExtractClassIds(ic_data)); | 332 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || |
| 264 // Replace 'comp' with 'load'. | 333 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || |
| 265 load->set_instr(comp->instr()); | 334 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { |
| 266 comp->instr()->replace_computation(load); | 335 if (!HasOneTarget(ic_data)) { |
| 336 // TODO(srdjan): Implement for mutiple targets. |
| 337 return; |
| 338 } |
| 339 intptr_t length_offset = -1; |
| 340 switch (recognized_kind) { |
| 341 case MethodRecognizer::kObjectArrayLength: |
| 342 case MethodRecognizer::kImmutableArrayLength: |
| 343 length_offset = Array::length_offset(); |
| 344 break; |
| 345 case MethodRecognizer::kGrowableArrayLength: |
| 346 length_offset = GrowableObjectArray::length_offset(); |
| 347 break; |
| 348 default: |
| 349 UNREACHABLE(); |
| 350 } |
| 351 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 352 comp->InputAt(0), |
| 353 Array::length_offset(), |
| 354 Type::ZoneHandle(Type::IntInterface()), |
| 355 comp, |
| 356 ExtractClassIds(ic_data)); |
| 357 load->set_instr(comp->instr()); |
| 358 comp->instr()->replace_computation(load); |
| 359 return; |
| 360 } |
| 361 |
| 362 if (recognized_kind == MethodRecognizer::kStringBaseLength) { |
| 363 ASSERT(HasOneTarget(ic_data)); |
| 364 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 365 comp->InputAt(0), |
| 366 String::length_offset(), |
| 367 Type::ZoneHandle(Type::IntInterface()), |
| 368 comp, |
| 369 ExtractClassIds(ic_data)); |
| 370 load->set_instr(comp->instr()); |
| 371 comp->instr()->replace_computation(load); |
| 372 return; |
| 373 } |
| 374 } |
| 375 |
| 376 |
| 377 // Inline only simple, frequently called core library methods. |
| 378 void FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallComp* comp) { |
| 379 ASSERT(comp->HasICData()); |
| 380 const ICData& ic_data = *comp->ic_data(); |
| 381 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { |
| 382 // No type feedback collected. |
| 383 return; |
| 384 } |
| 385 Function& target = Function::Handle(); |
| 386 GrowableArray<const Class*> classes; |
| 387 ic_data.GetCheckAt(0, &classes, &target); |
| 388 ASSERT(classes.length() == 1); |
| 389 MethodRecognizer::Kind recognized_kind = |
| 390 MethodRecognizer::RecognizeKind(target); |
| 391 if (recognized_kind == MethodRecognizer::kDoubleToDouble) { |
| 392 // TODO(srdjan): Implement. |
| 393 } |
| 394 if (recognized_kind == MethodRecognizer::kIntegerToDouble) { |
| 395 // TODO(srdjan): Implement. |
| 396 } |
| 397 } |
| 398 |
| 399 |
| 400 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { |
| 401 if (comp->HasICData()) { |
| 402 const String& function_name = comp->function_name(); |
| 403 Token::Kind op_kind = Token::GetBinaryOp(function_name); |
| 404 if (op_kind != Token::kILLEGAL) { |
| 405 TryReplaceWithBinaryOp(comp, op_kind); |
| 406 return; |
| 407 } |
| 408 op_kind = Token::GetUnaryOp(function_name); |
| 409 if (op_kind != Token::kILLEGAL) { |
| 410 TryReplaceWithUnaryOp(comp, op_kind); |
| 411 return; |
| 412 } |
| 413 if (Field::IsGetterName(function_name)) { |
| 414 TryInlineInstanceGetter(comp); |
| 415 return; |
| 416 } |
| 417 TryInlineInstanceMethod(comp); |
| 418 } |
| 419 } |
| 420 |
| 421 |
| 422 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp) { |
| 423 MethodRecognizer::Kind recognized_kind = |
| 424 MethodRecognizer::RecognizeKind(comp->function()); |
| 425 if (recognized_kind == MethodRecognizer::kMathSqrt) { |
| 426 // TODO(srdjan): Implement this. |
| 427 } |
| 267 } | 428 } |
| 268 | 429 |
| 269 | 430 |
| 270 void FlowGraphOptimizer::TryInlineInstanceSetter(InstanceSetterComp* comp) { | 431 void FlowGraphOptimizer::TryInlineInstanceSetter(InstanceSetterComp* comp) { |
| 271 ASSERT(comp->HasICData()); | 432 ASSERT(comp->HasICData()); |
| 272 const ICData& ic_data = *comp->ic_data(); | 433 const ICData& ic_data = *comp->ic_data(); |
| 273 if (ic_data.NumberOfChecks() == 0) { | 434 if (ic_data.NumberOfChecks() == 0) { |
| 274 // No type feedback collected | 435 // No type feedback collected. |
| 275 return; | 436 return; |
| 276 } | 437 } |
| 277 if (!HasOneTarget(ic_data)) { | 438 if (!HasOneTarget(ic_data)) { |
| 278 // TODO(srdjan): Implement when not all targets are the sa,e. | 439 // TODO(srdjan): Implement when not all targets are the sa,e. |
| 279 return; | 440 return; |
| 280 } | 441 } |
| 281 Function& target = Function::Handle(); | 442 Function& target = Function::Handle(); |
| 282 Class& cls = Class::Handle(); | 443 Class& cls = Class::Handle(); |
| 283 ic_data.GetOneClassCheckAt(0, &cls, &target); | 444 ic_data.GetOneClassCheckAt(0, &cls, &target); |
| 284 if (target.kind() != RawFunction::kImplicitSetter) { | 445 if (target.kind() != RawFunction::kImplicitSetter) { |
| 285 // Not an implicit setter. | 446 // Not an implicit setter. |
| 286 // TODO(srdjan): Inline special setters. | 447 // TODO(srdjan): Inline special setters. |
| 287 return; | 448 return; |
| 288 } | 449 } |
| 289 // Inline implicit instance setter. | 450 // Inline implicit instance setter. |
| 290 const Field& field = Field::Handle(GetField(cls, comp->field_name())); | 451 const Field& field = Field::Handle(GetField(cls, comp->field_name())); |
| 291 ASSERT(!field.IsNull()); | 452 ASSERT(!field.IsNull()); |
| 292 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( | 453 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( |
| 293 field, | 454 field, |
| 294 comp->InputAt(0), | 455 comp->InputAt(0), |
| 295 comp->InputAt(1), | 456 comp->InputAt(1), |
| 296 comp, | 457 comp, |
| 297 ExtractClassIds(ic_data)); | 458 ExtractClassIds(ic_data)); |
| 298 // Replace 'comp' with 'store'. | 459 // Replace 'comp' with 'store'. |
| 299 store->set_instr(comp->instr()); | 460 store->set_instr(comp->instr()); |
| 300 comp->instr()->replace_computation(store); | 461 comp->instr()->replace_computation(store); |
| 301 } | 462 } |
| 302 | 463 |
| 303 | 464 |
| 304 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { | |
| 305 if (comp->HasICData()) { | |
| 306 const String& function_name = comp->function_name(); | |
| 307 Token::Kind op_kind = Token::GetBinaryOp(function_name); | |
| 308 if (op_kind != Token::kILLEGAL) { | |
| 309 TryReplaceWithBinaryOp(comp, op_kind); | |
| 310 return; | |
| 311 } | |
| 312 op_kind = Token::GetUnaryOp(function_name); | |
| 313 if (op_kind != Token::kILLEGAL) { | |
| 314 TryReplaceWithUnaryOp(comp, op_kind); | |
| 315 return; | |
| 316 } | |
| 317 if (Field::IsGetterName(function_name)) { | |
| 318 TryInlineInstanceGetter(comp); | |
| 319 return; | |
| 320 } | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 | 465 |
| 325 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { | 466 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { |
| 326 // TODO(srdjan): Add assigneable check node if --enable_type_checks. | 467 // TODO(srdjan): Add assigneable check node if --enable_type_checks. |
| 327 if (comp->HasICData() && !FLAG_enable_type_checks) { | 468 if (comp->HasICData() && !FLAG_enable_type_checks) { |
| 328 TryInlineInstanceSetter(comp); | 469 TryInlineInstanceSetter(comp); |
| 329 } | 470 } |
| 330 } | 471 } |
| 331 | 472 |
| 332 | 473 |
| 333 void FlowGraphOptimizer::VisitLoadIndexed(LoadIndexedComp* comp) { | 474 void FlowGraphOptimizer::VisitLoadIndexed(LoadIndexedComp* comp) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 instr->computation()->Accept(this); | 514 instr->computation()->Accept(this); |
| 374 } | 515 } |
| 375 | 516 |
| 376 | 517 |
| 377 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { | 518 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| 378 instr->computation()->Accept(this); | 519 instr->computation()->Accept(this); |
| 379 } | 520 } |
| 380 | 521 |
| 381 | 522 |
| 382 } // namespace dart | 523 } // namespace dart |
| OLD | NEW |