| 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 |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 return ICDataHasReceiverClassId(ic_data, kDouble); | 124 return ICDataHasReceiverClassId(ic_data, kDouble); |
| 125 } | 125 } |
| 126 | 126 |
| 127 | 127 |
| 128 static bool HasOnlyTwoDouble(const ICData& ic_data) { | 128 static bool HasOnlyTwoDouble(const ICData& ic_data) { |
| 129 return (ic_data.NumberOfChecks() == 1) && | 129 return (ic_data.NumberOfChecks() == 1) && |
| 130 ICDataHasReceiverArgumentClassIds(ic_data, kDouble, kDouble); | 130 ICDataHasReceiverArgumentClassIds(ic_data, kDouble, kDouble); |
| 131 } | 131 } |
| 132 | 132 |
| 133 | 133 |
| 134 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallComp* comp, | 134 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, |
| 135 InstanceCallComp* comp, |
| 135 Token::Kind op_kind) { | 136 Token::Kind op_kind) { |
| 136 BinaryOpComp::OperandsType operands_type = BinaryOpComp::kDynamicOperands; | 137 BinaryOpComp::OperandsType operands_type = BinaryOpComp::kDynamicOperands; |
| 137 ASSERT(comp->HasICData()); | 138 ASSERT(comp->HasICData()); |
| 138 const ICData& ic_data = *comp->ic_data(); | 139 const ICData& ic_data = *comp->ic_data(); |
| 139 switch (op_kind) { | 140 switch (op_kind) { |
| 140 case Token::kADD: | 141 case Token::kADD: |
| 141 case Token::kSUB: | 142 case Token::kSUB: |
| 142 case Token::kMUL: | 143 case Token::kMUL: |
| 143 if (HasOnlyTwoSmi(ic_data)) { | 144 if (HasOnlyTwoSmi(ic_data)) { |
| 144 operands_type = BinaryOpComp::kSmiOperands; | 145 operands_type = BinaryOpComp::kSmiOperands; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 172 if (HasOnlyTwoSmi(ic_data)) { | 173 if (HasOnlyTwoSmi(ic_data)) { |
| 173 operands_type = BinaryOpComp::kSmiOperands; | 174 operands_type = BinaryOpComp::kSmiOperands; |
| 174 } else { | 175 } else { |
| 175 return false; | 176 return false; |
| 176 } | 177 } |
| 177 break; | 178 break; |
| 178 default: | 179 default: |
| 179 UNREACHABLE(); | 180 UNREACHABLE(); |
| 180 }; | 181 }; |
| 181 | 182 |
| 182 ASSERT(comp->instr() != NULL); | |
| 183 ASSERT(comp->InputCount() == 2); | 183 ASSERT(comp->InputCount() == 2); |
| 184 Value* left = comp->InputAt(0); | 184 Value* left = comp->InputAt(0); |
| 185 Value* right = comp->InputAt(1); | 185 Value* right = comp->InputAt(1); |
| 186 BinaryOpComp* bin_op = | 186 BinaryOpComp* bin_op = |
| 187 new BinaryOpComp(op_kind, | 187 new BinaryOpComp(op_kind, |
| 188 operands_type, | 188 operands_type, |
| 189 comp, | 189 comp, |
| 190 left, | 190 left, |
| 191 right); | 191 right); |
| 192 bin_op->set_ic_data(comp->ic_data()); | 192 bin_op->set_ic_data(comp->ic_data()); |
| 193 comp->ReplaceWith(bin_op); | 193 instr->set_computation(bin_op); |
| 194 return true; | 194 return true; |
| 195 } | 195 } |
| 196 | 196 |
| 197 | 197 |
| 198 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallComp* comp, | 198 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(BindInstr* instr, |
| 199 InstanceCallComp* comp, |
| 199 Token::Kind op_kind) { | 200 Token::Kind op_kind) { |
| 200 if (comp->ic_data()->NumberOfChecks() != 1) { | 201 if (comp->ic_data()->NumberOfChecks() != 1) { |
| 201 // TODO(srdjan): Not yet supported. | 202 // TODO(srdjan): Not yet supported. |
| 202 return false; | 203 return false; |
| 203 } | 204 } |
| 204 ASSERT(comp->instr() != NULL); | |
| 205 ASSERT(comp->InputCount() == 1); | 205 ASSERT(comp->InputCount() == 1); |
| 206 Computation* unary_op = NULL; | 206 Computation* unary_op = NULL; |
| 207 if (HasOneSmi(*comp->ic_data())) { | 207 if (HasOneSmi(*comp->ic_data())) { |
| 208 unary_op = new UnarySmiOpComp(op_kind, comp, comp->InputAt(0)); | 208 unary_op = new UnarySmiOpComp(op_kind, comp, comp->InputAt(0)); |
| 209 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { | 209 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { |
| 210 unary_op = new NumberNegateComp(comp, comp->InputAt(0)); | 210 unary_op = new NumberNegateComp(comp, comp->InputAt(0)); |
| 211 } | 211 } |
| 212 if (unary_op != NULL) { | 212 if (unary_op != NULL) { |
| 213 unary_op->set_ic_data(comp->ic_data()); | 213 unary_op->set_ic_data(comp->ic_data()); |
| 214 comp->ReplaceWith(unary_op); | 214 instr->set_computation(unary_op); |
| 215 return true; | 215 return true; |
| 216 } | 216 } |
| 217 return false; | 217 return false; |
| 218 } | 218 } |
| 219 | 219 |
| 220 | 220 |
| 221 // Returns true if all targets are the same. | 221 // Returns true if all targets are the same. |
| 222 // TODO(srdjan): if targets are native use their C_function to compare. | 222 // TODO(srdjan): if targets are native use their C_function to compare. |
| 223 static bool HasOneTarget(const ICData& ic_data) { | 223 static bool HasOneTarget(const ICData& ic_data) { |
| 224 ASSERT(ic_data.NumberOfChecks() > 0); | 224 ASSERT(ic_data.NumberOfChecks() > 0); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 // This will make sure that Smi is first if it exists. | 276 // This will make sure that Smi is first if it exists. |
| 277 result.AddReceiverCheck(class_id, | 277 result.AddReceiverCheck(class_id, |
| 278 Function::Handle(ic_data.GetTargetAt(i))); | 278 Function::Handle(ic_data.GetTargetAt(i))); |
| 279 } | 279 } |
| 280 } | 280 } |
| 281 return result.raw(); | 281 return result.raw(); |
| 282 } | 282 } |
| 283 | 283 |
| 284 | 284 |
| 285 // Only unique implicit instance getters can be currently handled. | 285 // Only unique implicit instance getters can be currently handled. |
| 286 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallComp* comp) { | 286 bool FlowGraphOptimizer::TryInlineInstanceGetter(BindInstr* instr, |
| 287 InstanceCallComp* comp) { |
| 287 ASSERT(comp->HasICData()); | 288 ASSERT(comp->HasICData()); |
| 288 const ICData& ic_data = *comp->ic_data(); | 289 const ICData& ic_data = *comp->ic_data(); |
| 289 if (ic_data.NumberOfChecks() == 0) { | 290 if (ic_data.NumberOfChecks() == 0) { |
| 290 // No type feedback collected. | 291 // No type feedback collected. |
| 291 return false; | 292 return false; |
| 292 } | 293 } |
| 293 Function& target = Function::Handle(); | 294 Function& target = Function::Handle(); |
| 294 GrowableArray<intptr_t> class_ids; | 295 GrowableArray<intptr_t> class_ids; |
| 295 ic_data.GetCheckAt(0, &class_ids, &target); | 296 ic_data.GetCheckAt(0, &class_ids, &target); |
| 296 ASSERT(class_ids.length() == 1); | 297 ASSERT(class_ids.length() == 1); |
| 297 | 298 |
| 298 if (target.kind() == RawFunction::kImplicitGetter) { | 299 if (target.kind() == RawFunction::kImplicitGetter) { |
| 299 if (!HasOneTarget(ic_data)) { | 300 if (!HasOneTarget(ic_data)) { |
| 300 // TODO(srdjan): Implement for mutiple targets. | 301 // TODO(srdjan): Implement for mutiple targets. |
| 301 return false; | 302 return false; |
| 302 } | 303 } |
| 303 // Inline implicit instance getter. | 304 // Inline implicit instance getter. |
| 304 const String& field_name = | 305 const String& field_name = |
| 305 String::Handle(Field::NameFromGetter(comp->function_name())); | 306 String::Handle(Field::NameFromGetter(comp->function_name())); |
| 306 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); | 307 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); |
| 307 ASSERT(!field.IsNull()); | 308 ASSERT(!field.IsNull()); |
| 308 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( | 309 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( |
| 309 field, comp->InputAt(0), comp); | 310 field, comp->InputAt(0), comp); |
| 310 load->set_ic_data(comp->ic_data()); | 311 load->set_ic_data(comp->ic_data()); |
| 311 comp->ReplaceWith(load); | 312 instr->set_computation(load); |
| 312 return true; | 313 return true; |
| 313 } | 314 } |
| 314 | 315 |
| 315 // Not an implicit getter. | 316 // Not an implicit getter. |
| 316 MethodRecognizer::Kind recognized_kind = | 317 MethodRecognizer::Kind recognized_kind = |
| 317 MethodRecognizer::RecognizeKind(target); | 318 MethodRecognizer::RecognizeKind(target); |
| 318 | 319 |
| 319 // VM objects length getter. | 320 // VM objects length getter. |
| 320 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || | 321 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || |
| 321 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || | 322 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || |
| (...skipping 13 matching lines...) Expand all Loading... |
| 335 break; | 336 break; |
| 336 default: | 337 default: |
| 337 UNREACHABLE(); | 338 UNREACHABLE(); |
| 338 } | 339 } |
| 339 LoadVMFieldComp* load = new LoadVMFieldComp( | 340 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 340 comp->InputAt(0), | 341 comp->InputAt(0), |
| 341 length_offset, | 342 length_offset, |
| 342 Type::ZoneHandle(Type::IntInterface())); | 343 Type::ZoneHandle(Type::IntInterface())); |
| 343 load->set_original(comp); | 344 load->set_original(comp); |
| 344 load->set_ic_data(comp->ic_data()); | 345 load->set_ic_data(comp->ic_data()); |
| 345 comp->ReplaceWith(load); | 346 instr->set_computation(load); |
| 346 return true; | 347 return true; |
| 347 } | 348 } |
| 348 | 349 |
| 349 if (recognized_kind == MethodRecognizer::kStringBaseLength) { | 350 if (recognized_kind == MethodRecognizer::kStringBaseLength) { |
| 350 ASSERT(HasOneTarget(ic_data)); | 351 ASSERT(HasOneTarget(ic_data)); |
| 351 LoadVMFieldComp* load = new LoadVMFieldComp( | 352 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 352 comp->InputAt(0), | 353 comp->InputAt(0), |
| 353 String::length_offset(), | 354 String::length_offset(), |
| 354 Type::ZoneHandle(Type::IntInterface())); | 355 Type::ZoneHandle(Type::IntInterface())); |
| 355 load->set_original(comp); | 356 load->set_original(comp); |
| 356 load->set_ic_data(comp->ic_data()); | 357 load->set_ic_data(comp->ic_data()); |
| 357 comp->ReplaceWith(load); | 358 instr->set_computation(load); |
| 358 return true; | 359 return true; |
| 359 } | 360 } |
| 360 return false; | 361 return false; |
| 361 } | 362 } |
| 362 | 363 |
| 363 | 364 |
| 364 // Inline only simple, frequently called core library methods. | 365 // Inline only simple, frequently called core library methods. |
| 365 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallComp* comp) { | 366 bool FlowGraphOptimizer::TryInlineInstanceMethod(BindInstr* instr, |
| 367 InstanceCallComp* comp) { |
| 366 ASSERT(comp->HasICData()); | 368 ASSERT(comp->HasICData()); |
| 367 const ICData& ic_data = *comp->ic_data(); | 369 const ICData& ic_data = *comp->ic_data(); |
| 368 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { | 370 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { |
| 369 // No type feedback collected. | 371 // No type feedback collected. |
| 370 return false; | 372 return false; |
| 371 } | 373 } |
| 372 Function& target = Function::Handle(); | 374 Function& target = Function::Handle(); |
| 373 GrowableArray<intptr_t> class_ids; | 375 GrowableArray<intptr_t> class_ids; |
| 374 ic_data.GetCheckAt(0, &class_ids, &target); | 376 ic_data.GetCheckAt(0, &class_ids, &target); |
| 375 MethodRecognizer::Kind recognized_kind = | 377 MethodRecognizer::Kind recognized_kind = |
| 376 MethodRecognizer::RecognizeKind(target); | 378 MethodRecognizer::RecognizeKind(target); |
| 377 | 379 |
| 378 ObjectKind from_kind; | 380 ObjectKind from_kind; |
| 379 if (recognized_kind == MethodRecognizer::kDoubleToDouble) { | 381 if (recognized_kind == MethodRecognizer::kDoubleToDouble) { |
| 380 from_kind = kDouble; | 382 from_kind = kDouble; |
| 381 } else if (recognized_kind == MethodRecognizer::kIntegerToDouble) { | 383 } else if (recognized_kind == MethodRecognizer::kIntegerToDouble) { |
| 382 from_kind = kSmi; | 384 from_kind = kSmi; |
| 383 } else { | 385 } else { |
| 384 return false; | 386 return false; |
| 385 } | 387 } |
| 386 | 388 |
| 387 if (class_ids[0] != from_kind) { | 389 if (class_ids[0] != from_kind) { |
| 388 return false; | 390 return false; |
| 389 } | 391 } |
| 390 ToDoubleComp* coerce = new ToDoubleComp( | 392 ToDoubleComp* coerce = new ToDoubleComp( |
| 391 comp->InputAt(0), from_kind, comp); | 393 comp->InputAt(0), from_kind, comp); |
| 392 coerce->set_instr(comp->instr()); | 394 instr->set_computation(coerce); |
| 393 comp->instr()->replace_computation(coerce); | |
| 394 return true; | 395 return true; |
| 395 } | 396 } |
| 396 | 397 |
| 397 | 398 |
| 398 | 399 |
| 399 | 400 |
| 400 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { | 401 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp, |
| 402 BindInstr* instr) { |
| 401 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { | 403 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { |
| 402 const Token::Kind op_kind = comp->token_kind(); | 404 const Token::Kind op_kind = comp->token_kind(); |
| 403 if (Token::IsBinaryToken(op_kind) && | 405 if (Token::IsBinaryToken(op_kind) && |
| 404 TryReplaceWithBinaryOp(comp, op_kind)) { | 406 TryReplaceWithBinaryOp(instr, comp, op_kind)) { |
| 405 return; | 407 return; |
| 406 } | 408 } |
| 407 if (Token::IsUnaryToken(op_kind) && TryReplaceWithUnaryOp(comp, op_kind)) { | 409 if (Token::IsUnaryToken(op_kind) && |
| 410 TryReplaceWithUnaryOp(instr, comp, op_kind)) { |
| 408 return; | 411 return; |
| 409 } | 412 } |
| 410 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(comp)) { | 413 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr, comp)) { |
| 411 return; | 414 return; |
| 412 } | 415 } |
| 413 if (TryInlineInstanceMethod(comp)) { | 416 if (TryInlineInstanceMethod(instr, comp)) { |
| 414 return; | 417 return; |
| 415 } | 418 } |
| 416 const intptr_t kMaxChecks = 4; | 419 const intptr_t kMaxChecks = 4; |
| 417 if (comp->ic_data()->NumberOfChecks() <= kMaxChecks) { | 420 if (comp->ic_data()->NumberOfChecks() <= kMaxChecks) { |
| 418 PolymorphicInstanceCallComp* call = new PolymorphicInstanceCallComp(comp); | 421 PolymorphicInstanceCallComp* call = new PolymorphicInstanceCallComp(comp); |
| 419 ICData& unary_checks = | 422 ICData& unary_checks = |
| 420 ICData::ZoneHandle(ToUnaryClassChecks(*comp->ic_data())); | 423 ICData::ZoneHandle(ToUnaryClassChecks(*comp->ic_data())); |
| 421 call->set_ic_data(&unary_checks); | 424 call->set_ic_data(&unary_checks); |
| 422 comp->ReplaceWith(call); | 425 instr->set_computation(call); |
| 423 } | 426 } |
| 424 } else { | 427 } else { |
| 425 // Mark it for deopt. | 428 // Mark it for deopt. |
| 426 PolymorphicInstanceCallComp* call = new PolymorphicInstanceCallComp(comp); | 429 PolymorphicInstanceCallComp* call = new PolymorphicInstanceCallComp(comp); |
| 427 call->set_ic_data(&ICData::ZoneHandle()); | 430 call->set_ic_data(&ICData::ZoneHandle()); |
| 428 comp->ReplaceWith(call); | 431 instr->set_computation(call); |
| 429 } | 432 } |
| 430 } | 433 } |
| 431 | 434 |
| 432 | 435 |
| 433 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp) { | 436 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp, |
| 437 BindInstr* instr) { |
| 434 MethodRecognizer::Kind recognized_kind = | 438 MethodRecognizer::Kind recognized_kind = |
| 435 MethodRecognizer::RecognizeKind(comp->function()); | 439 MethodRecognizer::RecognizeKind(comp->function()); |
| 436 if (recognized_kind == MethodRecognizer::kMathSqrt) { | 440 if (recognized_kind == MethodRecognizer::kMathSqrt) { |
| 437 comp->set_recognized(MethodRecognizer::kMathSqrt); | 441 comp->set_recognized(MethodRecognizer::kMathSqrt); |
| 438 } | 442 } |
| 439 } | 443 } |
| 440 | 444 |
| 441 | 445 |
| 442 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceSetterComp* comp) { | 446 bool FlowGraphOptimizer::TryInlineInstanceSetter(BindInstr* instr, |
| 447 InstanceSetterComp* comp) { |
| 443 ASSERT(comp->HasICData()); | 448 ASSERT(comp->HasICData()); |
| 444 const ICData& ic_data = *comp->ic_data(); | 449 const ICData& ic_data = *comp->ic_data(); |
| 445 if (ic_data.NumberOfChecks() == 0) { | 450 if (ic_data.NumberOfChecks() == 0) { |
| 446 // No type feedback collected. | 451 // No type feedback collected. |
| 447 return false; | 452 return false; |
| 448 } | 453 } |
| 449 if (!HasOneTarget(ic_data)) { | 454 if (!HasOneTarget(ic_data)) { |
| 450 // TODO(srdjan): Implement when not all targets are the same. | 455 // TODO(srdjan): Implement when not all targets are the same. |
| 451 return false; | 456 return false; |
| 452 } | 457 } |
| 453 Function& target = Function::Handle(); | 458 Function& target = Function::Handle(); |
| 454 intptr_t class_id; | 459 intptr_t class_id; |
| 455 ic_data.GetOneClassCheckAt(0, &class_id, &target); | 460 ic_data.GetOneClassCheckAt(0, &class_id, &target); |
| 456 if (target.kind() != RawFunction::kImplicitSetter) { | 461 if (target.kind() != RawFunction::kImplicitSetter) { |
| 457 // Not an implicit setter. | 462 // Not an implicit setter. |
| 458 // TODO(srdjan): Inline special setters. | 463 // TODO(srdjan): Inline special setters. |
| 459 return false; | 464 return false; |
| 460 } | 465 } |
| 461 // Inline implicit instance setter. | 466 // Inline implicit instance setter. |
| 462 const Field& field = Field::Handle(GetField(class_id, comp->field_name())); | 467 const Field& field = Field::Handle(GetField(class_id, comp->field_name())); |
| 463 ASSERT(!field.IsNull()); | 468 ASSERT(!field.IsNull()); |
| 464 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( | 469 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( |
| 465 field, | 470 field, |
| 466 comp->InputAt(0), | 471 comp->InputAt(0), |
| 467 comp->InputAt(1), | 472 comp->InputAt(1), |
| 468 comp); | 473 comp); |
| 469 store->set_ic_data(comp->ic_data()); | 474 store->set_ic_data(comp->ic_data()); |
| 470 comp->ReplaceWith(store); | 475 instr->set_computation(store); |
| 471 return true; | 476 return true; |
| 472 } | 477 } |
| 473 | 478 |
| 474 | 479 |
| 475 | 480 |
| 476 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { | 481 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp, |
| 482 BindInstr* instr) { |
| 477 // TODO(srdjan): Add assignable check node if --enable_type_checks. | 483 // TODO(srdjan): Add assignable check node if --enable_type_checks. |
| 478 if (comp->HasICData() && !FLAG_enable_type_checks) { | 484 if (comp->HasICData() && !FLAG_enable_type_checks) { |
| 479 if (TryInlineInstanceSetter(comp)) { | 485 if (TryInlineInstanceSetter(instr, comp)) { |
| 480 return; | 486 return; |
| 481 } | 487 } |
| 482 } | 488 } |
| 483 // TODO(srdjan): Polymorphic dispatch to setters or deoptimize. | 489 // TODO(srdjan): Polymorphic dispatch to setters or deoptimize. |
| 484 } | 490 } |
| 485 | 491 |
| 486 | 492 |
| 487 enum IndexedAccessType { | 493 enum IndexedAccessType { |
| 488 kIndexedLoad, | 494 kIndexedLoad, |
| 489 kIndexedStore | 495 kIndexedStore |
| (...skipping 10 matching lines...) Expand all Loading... |
| 500 if (ic_data.NumberOfChecks() != 1) return kIllegalObjectKind; | 506 if (ic_data.NumberOfChecks() != 1) return kIllegalObjectKind; |
| 501 ASSERT(HasOneTarget(ic_data)); | 507 ASSERT(HasOneTarget(ic_data)); |
| 502 | 508 |
| 503 Function& target = Function::Handle(); | 509 Function& target = Function::Handle(); |
| 504 intptr_t class_id; | 510 intptr_t class_id; |
| 505 ic_data.GetOneClassCheckAt(0, &class_id, &target); | 511 ic_data.GetOneClassCheckAt(0, &class_id, &target); |
| 506 return class_id; | 512 return class_id; |
| 507 } | 513 } |
| 508 | 514 |
| 509 | 515 |
| 510 void FlowGraphOptimizer::VisitLoadIndexed(LoadIndexedComp* comp) { | 516 void FlowGraphOptimizer::VisitLoadIndexed(LoadIndexedComp* comp, |
| 517 BindInstr* instr) { |
| 511 const intptr_t class_id = ReceiverClassId(comp); | 518 const intptr_t class_id = ReceiverClassId(comp); |
| 512 switch (class_id) { | 519 switch (class_id) { |
| 513 case kArray: | 520 case kArray: |
| 514 case kImmutableArray: | 521 case kImmutableArray: |
| 515 case kGrowableObjectArray: | 522 case kGrowableObjectArray: |
| 516 comp->set_receiver_type(static_cast<ObjectKind>(class_id)); | 523 comp->set_receiver_type(static_cast<ObjectKind>(class_id)); |
| 517 } | 524 } |
| 518 } | 525 } |
| 519 | 526 |
| 520 | 527 |
| 521 void FlowGraphOptimizer::VisitStoreIndexed(StoreIndexedComp* comp) { | 528 void FlowGraphOptimizer::VisitStoreIndexed(StoreIndexedComp* comp, |
| 529 BindInstr* instr) { |
| 522 if (FLAG_enable_type_checks) return; | 530 if (FLAG_enable_type_checks) return; |
| 523 | 531 |
| 524 const intptr_t class_id = ReceiverClassId(comp); | 532 const intptr_t class_id = ReceiverClassId(comp); |
| 525 switch (class_id) { | 533 switch (class_id) { |
| 526 case kArray: | 534 case kArray: |
| 527 case kGrowableObjectArray: | 535 case kGrowableObjectArray: |
| 528 comp->set_receiver_type(static_cast<ObjectKind>(class_id)); | 536 comp->set_receiver_type(static_cast<ObjectKind>(class_id)); |
| 529 } | 537 } |
| 530 } | 538 } |
| 531 | 539 |
| 532 | 540 |
| 533 static void TryFuseComparisonWithBranch(ComparisonComp* comp) { | 541 static void TryFuseComparisonWithBranch(BindInstr* instr, |
| 534 Instruction* instr = comp->instr(); | 542 ComparisonComp* comp) { |
| 535 Instruction* next_instr = instr->successor(); | 543 Instruction* next_instr = instr->successor(); |
| 536 if ((next_instr != NULL) && next_instr->IsBranch()) { | 544 if ((next_instr != NULL) && next_instr->IsBranch()) { |
| 537 BranchInstr* branch = next_instr->AsBranch(); | 545 BranchInstr* branch = next_instr->AsBranch(); |
| 538 UseVal* use = branch->value()->AsUse(); | 546 UseVal* use = branch->value()->AsUse(); |
| 539 if (instr == use->definition()) { | 547 if (instr == use->definition()) { |
| 540 comp->MarkFusedWithBranch(branch); | 548 comp->MarkFusedWithBranch(branch); |
| 541 branch->MarkFusedWithComparison(); | 549 branch->MarkFusedWithComparison(); |
| 542 return; | 550 return; |
| 543 } | 551 } |
| 544 } | 552 } |
| 545 if ((next_instr != NULL) && next_instr->IsBind()) { | 553 if ((next_instr != NULL) && next_instr->IsBind()) { |
| 546 Computation* next_comp = next_instr->AsBind()->computation(); | 554 Computation* next_comp = next_instr->AsBind()->computation(); |
| 547 if (next_comp->IsBooleanNegate()) { | 555 if (next_comp->IsBooleanNegate()) { |
| 548 Instruction* next_next_instr = next_instr->successor(); | 556 Instruction* next_next_instr = next_instr->successor(); |
| 549 if ((next_next_instr != NULL) && next_next_instr->IsBranch()) { | 557 if ((next_next_instr != NULL) && next_next_instr->IsBranch()) { |
| 550 BooleanNegateComp* negate = next_comp->AsBooleanNegate(); | 558 BooleanNegateComp* negate = next_comp->AsBooleanNegate(); |
| 551 BranchInstr* branch = next_next_instr->AsBranch(); | 559 BranchInstr* branch = next_next_instr->AsBranch(); |
| 552 if ((branch->value()->AsUse()->definition() == negate->instr()) && | 560 if ((branch->value()->AsUse()->definition() == next_instr) && |
| 553 (negate->value()->AsUse()->definition() == instr)) { | 561 (negate->value()->AsUse()->definition() == instr)) { |
| 554 comp->MarkFusedWithBranch(branch); | 562 comp->MarkFusedWithBranch(branch); |
| 555 branch->MarkFusedWithComparison(); | 563 branch->MarkFusedWithComparison(); |
| 556 branch->set_is_negated(true); | 564 branch->set_is_negated(true); |
| 557 instr->set_successor(next_next_instr); | 565 instr->set_successor(next_next_instr); |
| 558 return; | 566 return; |
| 559 } | 567 } |
| 560 } | 568 } |
| 561 } | 569 } |
| 562 } | 570 } |
| 563 } | 571 } |
| 564 | 572 |
| 565 | 573 |
| 566 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpComp* comp) { | 574 void FlowGraphOptimizer::VisitRelationalOp(RelationalOpComp* comp, |
| 575 BindInstr* instr) { |
| 567 if (!comp->HasICData()) return; | 576 if (!comp->HasICData()) return; |
| 568 | 577 |
| 569 const ICData& ic_data = *comp->ic_data(); | 578 const ICData& ic_data = *comp->ic_data(); |
| 570 if (ic_data.NumberOfChecks() == 0) return; | 579 if (ic_data.NumberOfChecks() == 0) return; |
| 571 // TODO(srdjan): Add multiple receiver type support. | 580 // TODO(srdjan): Add multiple receiver type support. |
| 572 if (ic_data.NumberOfChecks() != 1) return; | 581 if (ic_data.NumberOfChecks() != 1) return; |
| 573 ASSERT(HasOneTarget(ic_data)); | 582 ASSERT(HasOneTarget(ic_data)); |
| 574 | 583 |
| 575 if (HasOnlyTwoSmi(ic_data)) { | 584 if (HasOnlyTwoSmi(ic_data)) { |
| 576 comp->set_operands_class_id(kSmi); | 585 comp->set_operands_class_id(kSmi); |
| 577 } else if (HasOnlyTwoDouble(ic_data)) { | 586 } else if (HasOnlyTwoDouble(ic_data)) { |
| 578 comp->set_operands_class_id(kDouble); | 587 comp->set_operands_class_id(kDouble); |
| 579 } else { | 588 } else { |
| 580 return; | 589 return; |
| 581 } | 590 } |
| 582 | 591 |
| 583 // For smi and double comparisons if the next instruction is a conditional | 592 // For smi and double comparisons if the next instruction is a conditional |
| 584 // branch that uses the value of this comparison mark them as fused together | 593 // branch that uses the value of this comparison mark them as fused together |
| 585 // to avoid materializing a boolean value. | 594 // to avoid materializing a boolean value. |
| 586 TryFuseComparisonWithBranch(comp); | 595 TryFuseComparisonWithBranch(instr, comp); |
| 587 } | 596 } |
| 588 | 597 |
| 589 | 598 |
| 590 void FlowGraphOptimizer::VisitStrictCompare(StrictCompareComp* comp) { | 599 void FlowGraphOptimizer::VisitStrictCompare(StrictCompareComp* comp, |
| 591 TryFuseComparisonWithBranch(comp); | 600 BindInstr* instr) { |
| 601 TryFuseComparisonWithBranch(instr, comp); |
| 592 } | 602 } |
| 593 | 603 |
| 594 | 604 |
| 595 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareComp* comp) { | 605 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareComp* comp, |
| 606 BindInstr* instr) { |
| 596 if (comp->HasICData()) { | 607 if (comp->HasICData()) { |
| 597 // Replace binary checks with unary ones since EmitNative expects it. | 608 // Replace binary checks with unary ones since EmitNative expects it. |
| 598 ICData& unary_checks = | 609 ICData& unary_checks = |
| 599 ICData::Handle(ToUnaryClassChecks(*comp->ic_data())); | 610 ICData::Handle(ToUnaryClassChecks(*comp->ic_data())); |
| 600 comp->set_ic_data(&unary_checks); | 611 comp->set_ic_data(&unary_checks); |
| 601 } | 612 } |
| 602 | 613 |
| 603 TryFuseComparisonWithBranch(comp); | 614 TryFuseComparisonWithBranch(instr, comp); |
| 604 } | 615 } |
| 605 | 616 |
| 606 | 617 |
| 607 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { | 618 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| 608 instr->computation()->Accept(this); | 619 instr->computation()->Accept(this, instr); |
| 609 } | 620 } |
| 610 | 621 |
| 611 | 622 |
| 612 | 623 |
| 613 FlowGraphAnalyzer::FlowGraphAnalyzer( | 624 FlowGraphAnalyzer::FlowGraphAnalyzer( |
| 614 const GrowableArray<BlockEntryInstr*>& blocks) | 625 const GrowableArray<BlockEntryInstr*>& blocks) |
| 615 :blocks_(blocks), is_leaf_(false) {} | 626 :blocks_(blocks), is_leaf_(false) {} |
| 616 | 627 |
| 617 | 628 |
| 618 void FlowGraphAnalyzer::Analyze() { | 629 void FlowGraphAnalyzer::Analyze() { |
| 619 is_leaf_ = true; | 630 is_leaf_ = true; |
| 620 for (intptr_t i = 0; i < blocks_.length(); ++i) { | 631 for (intptr_t i = 0; i < blocks_.length(); ++i) { |
| 621 BlockEntryInstr* block_entry = blocks_[i]; | 632 BlockEntryInstr* block_entry = blocks_[i]; |
| 622 Instruction* instr = block_entry->successor(); | 633 Instruction* instr = block_entry->successor(); |
| 623 while ((instr != NULL) && !instr->IsBlockEntry()) { | 634 while ((instr != NULL) && !instr->IsBlockEntry()) { |
| 624 LocationSummary* locs = instr->locs(); | 635 LocationSummary* locs = instr->locs(); |
| 625 if (locs != NULL) { | 636 if (locs != NULL) { |
| 626 if (locs->is_call()) { | 637 if (locs->is_call()) { |
| 627 is_leaf_ = false; | 638 is_leaf_ = false; |
| 628 return; | 639 return; |
| 629 } | 640 } |
| 630 } | 641 } |
| 631 instr = instr->successor(); | 642 instr = instr->successor(); |
| 632 } | 643 } |
| 633 } | 644 } |
| 634 } | 645 } |
| 635 | 646 |
| 636 } // namespace dart | 647 } // namespace dart |
| OLD | NEW |