| 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 17 matching lines...) Expand all Loading... |
| 28 for (intptr_t i = 0; i < block_order_.length(); ++i) { | 28 for (intptr_t i = 0; i < block_order_.length(); ++i) { |
| 29 Instruction* instr = block_order_[i]->Accept(this); | 29 Instruction* instr = block_order_[i]->Accept(this); |
| 30 // Optimize all successors until an exit, branch, or a block entry. | 30 // Optimize all successors until an exit, branch, or a block entry. |
| 31 while ((instr != NULL) && !instr->IsBlockEntry()) { | 31 while ((instr != NULL) && !instr->IsBlockEntry()) { |
| 32 instr = instr->Accept(this); | 32 instr = instr->Accept(this); |
| 33 } | 33 } |
| 34 } | 34 } |
| 35 } | 35 } |
| 36 | 36 |
| 37 | 37 |
| 38 static bool ICDataHasReceiverClass(const ICData& ic_data, intptr_t class_id) { | 38 static bool ICDataHasReceiverClassId(const ICData& ic_data, intptr_t class_id) { |
| 39 ASSERT(ic_data.num_args_tested() > 0); | 39 ASSERT(ic_data.num_args_tested() > 0); |
| 40 Function& target = Function::Handle(); | |
| 41 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 40 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 42 intptr_t test_class_id; | 41 const intptr_t test_class_id = ic_data.GetReceiverClassIdAt(i); |
| 43 ic_data.GetOneClassCheckAt(i, &test_class_id, &target); | |
| 44 if (test_class_id == class_id) { | 42 if (test_class_id == class_id) { |
| 45 return true; | 43 return true; |
| 46 } | 44 } |
| 47 } | 45 } |
| 48 return false; | 46 return false; |
| 49 } | 47 } |
| 50 | 48 |
| 51 | 49 |
| 52 static bool ICDataHasReceiverArgumentClasses(const ICData& ic_data, | 50 static bool ICDataHasReceiverArgumentClasses(const ICData& ic_data, |
| 53 intptr_t receiver_class_id, | 51 intptr_t receiver_class_id, |
| 54 intptr_t argument_class_id) { | 52 intptr_t argument_class_id) { |
| 55 if (ic_data.num_args_tested() != 2) { | 53 ASSERT(receiver_class_id != kIllegalObjectKind); |
| 56 return false; | 54 ASSERT(argument_class_id != kIllegalObjectKind); |
| 57 } | 55 if (ic_data.num_args_tested() != 2) return false; |
| 56 |
| 58 Function& target = Function::Handle(); | 57 Function& target = Function::Handle(); |
| 59 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 58 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 60 GrowableArray<intptr_t> class_ids; | 59 GrowableArray<intptr_t> class_ids; |
| 61 ic_data.GetCheckAt(i, &class_ids, &target); | 60 ic_data.GetCheckAt(i, &class_ids, &target); |
| 62 ASSERT(class_ids.length() == 2); | 61 ASSERT(class_ids.length() == 2); |
| 63 if (class_ids[0] == receiver_class_id) { | 62 if ((class_ids[0] == receiver_class_id) && |
| 64 if (class_ids[1] == argument_class_id) { | 63 (class_ids[1] == argument_class_id)) { |
| 65 return true; | 64 return true; |
| 66 } | |
| 67 } | 65 } |
| 68 } | 66 } |
| 69 return false; | 67 return false; |
| 70 } | 68 } |
| 71 | 69 |
| 72 | 70 |
| 73 static bool HasOneSmi(const ICData& ic_data) { | 71 static bool HasOneSmi(const ICData& ic_data) { |
| 74 return ICDataHasReceiverClass(ic_data, kSmi); | 72 return ICDataHasReceiverClassId(ic_data, kSmi); |
| 75 } | 73 } |
| 76 | 74 |
| 77 | 75 |
| 78 static bool HasTwoSmi(const ICData& ic_data) { | 76 static bool HasTwoSmi(const ICData& ic_data) { |
| 79 return ICDataHasReceiverArgumentClasses(ic_data, kSmi, kSmi); | 77 return ICDataHasReceiverArgumentClasses(ic_data, kSmi, kSmi); |
| 80 } | 78 } |
| 81 | 79 |
| 82 | 80 |
| 83 static bool HasMintSmi(const ICData& ic_data) { | 81 static bool HasMintSmi(const ICData& ic_data) { |
| 84 return ICDataHasReceiverArgumentClasses(ic_data, kMint, kSmi); | 82 return ICDataHasReceiverArgumentClasses(ic_data, kMint, kSmi); |
| 85 } | 83 } |
| 86 | 84 |
| 87 | 85 |
| 88 static bool HasOneDouble(const ICData& ic_data) { | 86 static bool HasOneDouble(const ICData& ic_data) { |
| 89 return ICDataHasReceiverClass(ic_data, kDouble); | 87 return ICDataHasReceiverClassId(ic_data, kDouble); |
| 90 } | 88 } |
| 91 | 89 |
| 92 | 90 |
| 93 static bool HasTwoDouble(const ICData& ic_data) { | 91 static bool HasTwoDouble(const ICData& ic_data) { |
| 94 return ICDataHasReceiverArgumentClasses(ic_data, kDouble, kDouble); | 92 return ICDataHasReceiverArgumentClasses(ic_data, kDouble, kDouble); |
| 95 } | 93 } |
| 96 | 94 |
| 97 | 95 |
| 98 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallComp* comp, | 96 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallComp* comp, |
| 99 Token::Kind op_kind) { | 97 Token::Kind op_kind) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 174 return true; | 172 return true; |
| 175 } | 173 } |
| 176 return false; | 174 return false; |
| 177 } | 175 } |
| 178 | 176 |
| 179 | 177 |
| 180 // Returns true if all targets are the same. | 178 // Returns true if all targets are the same. |
| 181 // TODO(srdjan): if targets are native use their C_function to compare. | 179 // TODO(srdjan): if targets are native use their C_function to compare. |
| 182 static bool HasOneTarget(const ICData& ic_data) { | 180 static bool HasOneTarget(const ICData& ic_data) { |
| 183 ASSERT(ic_data.NumberOfChecks() > 0); | 181 ASSERT(ic_data.NumberOfChecks() > 0); |
| 184 Function& prev_target = Function::Handle(); | 182 const Function& first_target = Function::Handle(ic_data.GetTargetAt(0)); |
| 185 GrowableArray<intptr_t> class_ids; | 183 Function& test_target = Function::Handle(); |
| 186 ic_data.GetCheckAt(0, &class_ids, &prev_target); | |
| 187 ASSERT(!prev_target.IsNull()); | |
| 188 Function& target = Function::Handle(); | |
| 189 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { | 184 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { |
| 190 ic_data.GetCheckAt(i, &class_ids, &target); | 185 test_target = ic_data.GetTargetAt(i); |
| 191 ASSERT(!target.IsNull()); | 186 if (first_target.raw() != test_target.raw()) { |
| 192 if (prev_target.raw() != target.raw()) { | |
| 193 return false; | 187 return false; |
| 194 } | 188 } |
| 195 prev_target = target.raw(); | |
| 196 } | 189 } |
| 197 return true; | 190 return true; |
| 198 } | 191 } |
| 199 | 192 |
| 200 | 193 |
| 201 // Using field class | 194 // Using field class |
| 202 static RawField* GetField(intptr_t class_id, const String& field_name) { | 195 static RawField* GetField(intptr_t class_id, const String& field_name) { |
| 203 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); | 196 Class& cls = Class::Handle(Isolate::Current()->class_table()->At(class_id)); |
| 204 Field& field = Field::Handle(); | 197 Field& field = Field::Handle(); |
| 205 while (!cls.IsNull()) { | 198 while (!cls.IsNull()) { |
| 206 field = cls.LookupInstanceField(field_name); | 199 field = cls.LookupInstanceField(field_name); |
| 207 if (!field.IsNull()) { | 200 if (!field.IsNull()) { |
| 208 return field.raw(); | 201 return field.raw(); |
| 209 } | 202 } |
| 210 cls = cls.SuperClass(); | 203 cls = cls.SuperClass(); |
| 211 } | 204 } |
| 212 return Field::null(); | 205 return Field::null(); |
| 213 } | 206 } |
| 214 | 207 |
| 215 | 208 |
| 216 // Returns all receiver class-ids and corresponding tagets for the given | 209 // Returns ICData with num_args_checked == 1. If necessary creates a new ICData |
| 217 // 'ic_data', sorted so that a smi class id is at index[0] if it exists. | 210 // object that contains unique receiver class-ids |
| 218 // 'targets' can be NULL in which case it is not collected, | 211 static RawICData* ToUnaryClassChecks(const ICData& ic_data) { |
| 219 static void ExtractClassIdsAndTargets(const ICData& ic_data, | 212 ASSERT(!ic_data.IsNull()); |
| 220 ZoneGrowableArray<intptr_t>* class_ids, | 213 ASSERT(ic_data.num_args_tested() != 0); |
| 221 ZoneGrowableArray<Function*>* targets) { | 214 if (ic_data.num_args_tested() == 1) return ic_data.raw(); |
| 222 ASSERT(class_ids != NULL); | 215 const intptr_t kNumArgsTested = 1; |
| 223 class_ids->Clear(); | 216 ICData& result = ICData::Handle(ICData::New( |
| 224 if (targets != NULL) { | 217 Function::Handle(ic_data.function()), |
| 225 targets->Clear(); | 218 String::Handle(ic_data.target_name()), |
| 226 } | 219 ic_data.id(), |
| 227 intptr_t smi_index = -1; | 220 kNumArgsTested)); |
| 228 Function& target = Function::Handle(); | |
| 229 GrowableArray<intptr_t> unsorted_class_ids; | |
| 230 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 221 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 231 ic_data.GetCheckAt(i, &unsorted_class_ids, &target); | 222 const intptr_t class_id = ic_data.GetReceiverClassIdAt(i); |
| 232 // Collect receiver class only. | 223 intptr_t duplicate_class_id = -1; |
| 233 const intptr_t class_id = unsorted_class_ids[0]; | 224 for (intptr_t k = 0; k < result.NumberOfChecks(); k++) { |
| 234 if (ic_data.num_args_tested() > 1) { | 225 if (class_id == result.GetReceiverClassIdAt(k)) { |
| 235 // Check if we have not already entered the class-id. | 226 duplicate_class_id = k; |
| 236 intptr_t duplicate_class_id = -1; | 227 break; |
| 237 for (intptr_t k = 0; k < class_ids->length(); k++) { | |
| 238 if ((*class_ids)[k] == class_id) { | |
| 239 duplicate_class_id = k; | |
| 240 break; | |
| 241 } | |
| 242 } | |
| 243 if (duplicate_class_id >= 0) { | |
| 244 ASSERT((targets == NULL) || | |
| 245 ((*targets)[duplicate_class_id]->raw() == target.raw())); | |
| 246 continue; | |
| 247 } | 228 } |
| 248 } | 229 } |
| 249 if (class_id == kSmi) { | 230 if (duplicate_class_id >= 0) { |
| 250 ASSERT(smi_index < 0); // Classes entered only once in ic_data. | 231 ASSERT(result.GetTargetAt(duplicate_class_id) == ic_data.GetTargetAt(i)); |
| 251 smi_index = class_ids->length(); | 232 } else { |
| 252 } | 233 // This will make sure that Smi is first if it exists. |
| 253 class_ids->Add(class_id); | 234 result.AddReceiverCheck(class_id, |
| 254 if (targets != NULL) { | 235 Function::Handle(ic_data.GetTargetAt(i))); |
| 255 targets->Add(&Function::ZoneHandle(target.raw())); | |
| 256 } | 236 } |
| 257 } | 237 } |
| 258 if (smi_index >= 0) { | 238 return result.raw(); |
| 259 // Smi class id must be at index 0. | |
| 260 intptr_t temp_id = (*class_ids)[0]; | |
| 261 (*class_ids)[0] = (*class_ids)[smi_index]; | |
| 262 (*class_ids)[smi_index] = temp_id; | |
| 263 if (targets != NULL) { | |
| 264 Function* temp_func = (*targets)[0]; | |
| 265 (*targets)[0] = (*targets)[smi_index]; | |
| 266 (*targets)[smi_index] = temp_func; | |
| 267 } | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 | |
| 272 // Returns array of all class ids that are in ic_data. The result is | |
| 273 // normalized so that a smi class is at index 0 if it exists in the ic_data. | |
| 274 static ZoneGrowableArray<intptr_t>* ExtractClassIds(const ICData& ic_data) { | |
| 275 if (ic_data.NumberOfChecks() == 0) return NULL; | |
| 276 ZoneGrowableArray<intptr_t>* result = | |
| 277 new ZoneGrowableArray<intptr_t>(ic_data.NumberOfChecks()); | |
| 278 ExtractClassIdsAndTargets(ic_data, result, NULL); | |
| 279 return result; | |
| 280 } | 239 } |
| 281 | 240 |
| 282 | 241 |
| 283 // Only unique implicit instance getters can be currently handled. | 242 // Only unique implicit instance getters can be currently handled. |
| 284 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallComp* comp) { | 243 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallComp* comp) { |
| 285 ASSERT(comp->HasICData()); | 244 ASSERT(comp->HasICData()); |
| 286 const ICData& ic_data = *comp->ic_data(); | 245 const ICData& ic_data = *comp->ic_data(); |
| 287 if (ic_data.NumberOfChecks() == 0) { | 246 if (ic_data.NumberOfChecks() == 0) { |
| 288 // No type feedback collected. | 247 // No type feedback collected. |
| 289 return false; | 248 return false; |
| 290 } | 249 } |
| 291 Function& target = Function::Handle(); | 250 Function& target = Function::Handle(); |
| 292 GrowableArray<intptr_t> class_ids; | 251 GrowableArray<intptr_t> class_ids; |
| 293 ic_data.GetCheckAt(0, &class_ids, &target); | 252 ic_data.GetCheckAt(0, &class_ids, &target); |
| 294 ASSERT(class_ids.length() == 1); | 253 ASSERT(class_ids.length() == 1); |
| 295 | 254 |
| 296 if (target.kind() == RawFunction::kImplicitGetter) { | 255 if (target.kind() == RawFunction::kImplicitGetter) { |
| 297 if (!HasOneTarget(ic_data)) { | 256 if (!HasOneTarget(ic_data)) { |
| 298 // TODO(srdjan): Implement for mutiple targets. | 257 // TODO(srdjan): Implement for mutiple targets. |
| 299 return false; | 258 return false; |
| 300 } | 259 } |
| 301 // Inline implicit instance getter. | 260 // Inline implicit instance getter. |
| 302 const String& field_name = | 261 const String& field_name = |
| 303 String::Handle(Field::NameFromGetter(comp->function_name())); | 262 String::Handle(Field::NameFromGetter(comp->function_name())); |
| 304 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); | 263 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); |
| 305 ASSERT(!field.IsNull()); | 264 ASSERT(!field.IsNull()); |
| 306 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( | 265 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( |
| 307 field, comp->InputAt(0), comp, ExtractClassIds(ic_data)); | 266 field, comp->InputAt(0), comp); |
| 267 load->set_ic_data(comp->ic_data()); |
| 308 comp->ReplaceWith(load); | 268 comp->ReplaceWith(load); |
| 309 return true; | 269 return true; |
| 310 } | 270 } |
| 311 | 271 |
| 312 // Not an implicit getter. | 272 // Not an implicit getter. |
| 313 MethodRecognizer::Kind recognized_kind = | 273 MethodRecognizer::Kind recognized_kind = |
| 314 MethodRecognizer::RecognizeKind(target); | 274 MethodRecognizer::RecognizeKind(target); |
| 315 | 275 |
| 316 // VM objects length getter. | 276 // VM objects length getter. |
| 317 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || | 277 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || |
| (...skipping 11 matching lines...) Expand all Loading... |
| 329 break; | 289 break; |
| 330 case MethodRecognizer::kGrowableArrayLength: | 290 case MethodRecognizer::kGrowableArrayLength: |
| 331 length_offset = GrowableObjectArray::length_offset(); | 291 length_offset = GrowableObjectArray::length_offset(); |
| 332 break; | 292 break; |
| 333 default: | 293 default: |
| 334 UNREACHABLE(); | 294 UNREACHABLE(); |
| 335 } | 295 } |
| 336 LoadVMFieldComp* load = new LoadVMFieldComp( | 296 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 337 comp->InputAt(0), | 297 comp->InputAt(0), |
| 338 length_offset, | 298 length_offset, |
| 339 Type::ZoneHandle(Type::IntInterface()), | 299 Type::ZoneHandle(Type::IntInterface())); |
| 340 comp, | 300 load->set_original(comp); |
| 341 ExtractClassIds(ic_data)); | 301 load->set_ic_data(comp->ic_data()); |
| 342 comp->ReplaceWith(load); | 302 comp->ReplaceWith(load); |
| 343 return true; | 303 return true; |
| 344 } | 304 } |
| 345 | 305 |
| 346 if (recognized_kind == MethodRecognizer::kStringBaseLength) { | 306 if (recognized_kind == MethodRecognizer::kStringBaseLength) { |
| 347 ASSERT(HasOneTarget(ic_data)); | 307 ASSERT(HasOneTarget(ic_data)); |
| 348 LoadVMFieldComp* load = new LoadVMFieldComp( | 308 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 349 comp->InputAt(0), | 309 comp->InputAt(0), |
| 350 String::length_offset(), | 310 String::length_offset(), |
| 351 Type::ZoneHandle(Type::IntInterface()), | 311 Type::ZoneHandle(Type::IntInterface())); |
| 352 comp, | 312 load->set_original(comp); |
| 353 ExtractClassIds(ic_data)); | 313 load->set_ic_data(comp->ic_data()); |
| 354 comp->ReplaceWith(load); | 314 comp->ReplaceWith(load); |
| 355 return true; | 315 return true; |
| 356 } | 316 } |
| 357 return false; | 317 return false; |
| 358 } | 318 } |
| 359 | 319 |
| 360 | 320 |
| 361 // Inline only simple, frequently called core library methods. | 321 // Inline only simple, frequently called core library methods. |
| 362 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallComp* comp) { | 322 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallComp* comp) { |
| 363 ASSERT(comp->HasICData()); | 323 ASSERT(comp->HasICData()); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 return; | 365 return; |
| 406 } | 366 } |
| 407 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(comp)) { | 367 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(comp)) { |
| 408 return; | 368 return; |
| 409 } | 369 } |
| 410 if (TryInlineInstanceMethod(comp)) { | 370 if (TryInlineInstanceMethod(comp)) { |
| 411 return; | 371 return; |
| 412 } | 372 } |
| 413 const intptr_t kMaxChecks = 4; | 373 const intptr_t kMaxChecks = 4; |
| 414 if (comp->ic_data()->num_args_tested() <= kMaxChecks) { | 374 if (comp->ic_data()->num_args_tested() <= kMaxChecks) { |
| 415 ZoneGrowableArray<intptr_t>* class_ids = | 375 PolymorphicInstanceCallComp* call = new PolymorphicInstanceCallComp(comp); |
| 416 new ZoneGrowableArray<intptr_t>(); | 376 ICData& unary_checks = |
| 417 ZoneGrowableArray<Function*>* targets = | 377 ICData::Handle(ToUnaryClassChecks(*comp->ic_data())); |
| 418 new ZoneGrowableArray<Function*>(); | 378 call->set_ic_data(&unary_checks); |
| 419 ExtractClassIdsAndTargets(*comp->ic_data(), class_ids, targets); | |
| 420 PolymorphicInstanceCallComp* call = | |
| 421 new PolymorphicInstanceCallComp(comp, *class_ids, *targets); | |
| 422 comp->ReplaceWith(call); | 379 comp->ReplaceWith(call); |
| 423 } | 380 } |
| 424 } | 381 } |
| 425 } | 382 } |
| 426 | 383 |
| 427 | 384 |
| 428 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp) { | 385 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp) { |
| 429 MethodRecognizer::Kind recognized_kind = | 386 MethodRecognizer::Kind recognized_kind = |
| 430 MethodRecognizer::RecognizeKind(comp->function()); | 387 MethodRecognizer::RecognizeKind(comp->function()); |
| 431 if (recognized_kind == MethodRecognizer::kMathSqrt) { | 388 if (recognized_kind == MethodRecognizer::kMathSqrt) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 453 // TODO(srdjan): Inline special setters. | 410 // TODO(srdjan): Inline special setters. |
| 454 return false; | 411 return false; |
| 455 } | 412 } |
| 456 // Inline implicit instance setter. | 413 // Inline implicit instance setter. |
| 457 const Field& field = Field::Handle(GetField(class_id, comp->field_name())); | 414 const Field& field = Field::Handle(GetField(class_id, comp->field_name())); |
| 458 ASSERT(!field.IsNull()); | 415 ASSERT(!field.IsNull()); |
| 459 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( | 416 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( |
| 460 field, | 417 field, |
| 461 comp->InputAt(0), | 418 comp->InputAt(0), |
| 462 comp->InputAt(1), | 419 comp->InputAt(1), |
| 463 comp, | 420 comp); |
| 464 ExtractClassIds(ic_data)); | 421 store->set_ic_data(comp->ic_data()); |
| 465 comp->ReplaceWith(store); | 422 comp->ReplaceWith(store); |
| 466 return true; | 423 return true; |
| 467 } | 424 } |
| 468 | 425 |
| 469 | 426 |
| 470 | 427 |
| 471 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { | 428 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { |
| 472 // TODO(srdjan): Add assigneable check node if --enable_type_checks. | 429 // TODO(srdjan): Add assigneable check node if --enable_type_checks. |
| 473 if (comp->HasICData() && !FLAG_enable_type_checks) { | 430 if (comp->HasICData() && !FLAG_enable_type_checks) { |
| 474 TryInlineInstanceSetter(comp); | 431 TryInlineInstanceSetter(comp); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 | 521 |
| 565 void FlowGraphOptimizer::VisitStrictCompareComp(StrictCompareComp* comp) { | 522 void FlowGraphOptimizer::VisitStrictCompareComp(StrictCompareComp* comp) { |
| 566 // TODO(vegorov): recognize the pattern with BooleanNegate between comparsion | 523 // TODO(vegorov): recognize the pattern with BooleanNegate between comparsion |
| 567 // and a branch. | 524 // and a branch. |
| 568 TryFuseComparisonWithBranch(comp); | 525 TryFuseComparisonWithBranch(comp); |
| 569 } | 526 } |
| 570 | 527 |
| 571 | 528 |
| 572 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareComp* comp) { | 529 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareComp* comp) { |
| 573 const intptr_t kMaxChecks = 4; | 530 const intptr_t kMaxChecks = 4; |
| 574 if (comp->ic_data()->num_args_tested() <= kMaxChecks) { | 531 if (comp->HasICData() && (comp->ic_data()->num_args_tested() <= kMaxChecks)) { |
| 575 ZoneGrowableArray<intptr_t>* class_ids = | 532 // Replace binary checks with unary ones. |
| 576 new ZoneGrowableArray<intptr_t>(); | 533 ICData& unary_checks = |
| 577 ZoneGrowableArray<Function*>* targets = | 534 ICData::Handle(ToUnaryClassChecks(*comp->ic_data())); |
| 578 new ZoneGrowableArray<Function*>(); | 535 comp->set_ic_data(&unary_checks); |
| 579 ExtractClassIdsAndTargets(*comp->ic_data(), class_ids, targets); | |
| 580 comp->SetPolymorphicTargets(class_ids, targets); | |
| 581 } | 536 } |
| 582 | 537 |
| 583 // TODO(vegorov): recognize the pattern with BooleanNegate between comparsion | 538 // TODO(vegorov): recognize the pattern with BooleanNegate between comparsion |
| 584 // and a branch. | 539 // and a branch. |
| 585 TryFuseComparisonWithBranch(comp); | 540 TryFuseComparisonWithBranch(comp); |
| 586 } | 541 } |
| 587 | 542 |
| 588 | 543 |
| 589 void FlowGraphOptimizer::VisitDo(DoInstr* instr) { | 544 void FlowGraphOptimizer::VisitDo(DoInstr* instr) { |
| 590 instr->computation()->Accept(this); | 545 instr->computation()->Accept(this); |
| 591 } | 546 } |
| 592 | 547 |
| 593 | 548 |
| 594 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { | 549 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| 595 instr->computation()->Accept(this); | 550 instr->computation()->Accept(this); |
| 596 } | 551 } |
| 597 | 552 |
| 598 | 553 |
| 599 } // namespace dart | 554 } // namespace dart |
| OLD | NEW |