| 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 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 } | 151 } |
| 152 | 152 |
| 153 | 153 |
| 154 static bool HasTwoDouble(const ICData& ic_data) { | 154 static bool HasTwoDouble(const ICData& ic_data) { |
| 155 const Class& double_class = | 155 const Class& double_class = |
| 156 Class::Handle(Isolate::Current()->object_store()->double_class()); | 156 Class::Handle(Isolate::Current()->object_store()->double_class()); |
| 157 return ICDataHasTwoReceiverClasses(ic_data, double_class, double_class); | 157 return ICDataHasTwoReceiverClasses(ic_data, double_class, double_class); |
| 158 } | 158 } |
| 159 | 159 |
| 160 | 160 |
| 161 void FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallComp* comp, | 161 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallComp* comp, |
| 162 Token::Kind op_kind) { | 162 Token::Kind op_kind) { |
| 163 if (comp->ic_data()->NumberOfChecks() != 1) { | 163 if (comp->ic_data()->NumberOfChecks() != 1) { |
| 164 // TODO(srdjan): Not yet supported. | 164 // TODO(srdjan): Not yet supported. |
| 165 return; | 165 return false; |
| 166 } | 166 } |
| 167 | 167 |
| 168 BinaryOpComp::OperandsType operands_type; | 168 BinaryOpComp::OperandsType operands_type; |
| 169 | 169 |
| 170 if (HasTwoSmi(*comp->ic_data())) { | 170 if (HasTwoSmi(*comp->ic_data())) { |
| 171 if (op_kind == Token::kDIV || | 171 if (op_kind == Token::kDIV || |
| 172 op_kind == Token::kMOD) { | 172 op_kind == Token::kMOD) { |
| 173 // TODO(srdjan): Not yet supported. | 173 // TODO(srdjan): Not yet supported. |
| 174 return; | 174 return false; |
| 175 } | 175 } |
| 176 | 176 |
| 177 operands_type = BinaryOpComp::kSmiOperands; | 177 operands_type = BinaryOpComp::kSmiOperands; |
| 178 } else if (HasTwoDouble(*comp->ic_data())) { | 178 } else if (HasTwoDouble(*comp->ic_data())) { |
| 179 if (op_kind != Token::kADD && | 179 if (op_kind != Token::kADD && |
| 180 op_kind != Token::kSUB && | 180 op_kind != Token::kSUB && |
| 181 op_kind != Token::kMUL && | 181 op_kind != Token::kMUL && |
| 182 op_kind != Token::kDIV) { | 182 op_kind != Token::kDIV) { |
| 183 // TODO(vegorov): Not yet supported. | 183 // TODO(vegorov): Not yet supported. |
| 184 return; | 184 return false; |
| 185 } | 185 } |
| 186 | 186 |
| 187 operands_type = BinaryOpComp::kDoubleOperands; | 187 operands_type = BinaryOpComp::kDoubleOperands; |
| 188 } else { | 188 } else { |
| 189 // TODO(srdjan): Not yet supported. | 189 // TODO(srdjan): Not yet supported. |
| 190 return; | 190 return false; |
| 191 } | 191 } |
| 192 | 192 |
| 193 ASSERT(comp->instr() != NULL); | 193 ASSERT(comp->instr() != NULL); |
| 194 ASSERT(comp->InputCount() == 2); | 194 ASSERT(comp->InputCount() == 2); |
| 195 Value* left = comp->InputAt(0); | 195 Value* left = comp->InputAt(0); |
| 196 Value* right = comp->InputAt(1); | 196 Value* right = comp->InputAt(1); |
| 197 BinaryOpComp* bin_op = | 197 BinaryOpComp* bin_op = |
| 198 new BinaryOpComp(op_kind, | 198 new BinaryOpComp(op_kind, |
| 199 operands_type, | 199 operands_type, |
| 200 comp, | 200 comp, |
| 201 left, | 201 left, |
| 202 right); | 202 right); |
| 203 ASSERT(bin_op->ic_data() == NULL); | |
| 204 bin_op->set_ic_data(comp->ic_data()); | 203 bin_op->set_ic_data(comp->ic_data()); |
| 205 bin_op->set_instr(comp->instr()); | 204 comp->ReplaceWith(bin_op); |
| 206 comp->instr()->replace_computation(bin_op); | 205 return true; |
| 207 } | 206 } |
| 208 | 207 |
| 209 | 208 |
| 210 void FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallComp* comp, | 209 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallComp* comp, |
| 211 Token::Kind op_kind) { | 210 Token::Kind op_kind) { |
| 212 if (comp->ic_data()->NumberOfChecks() != 1) { | 211 if (comp->ic_data()->NumberOfChecks() != 1) { |
| 213 // TODO(srdjan): Not yet supported. | 212 // TODO(srdjan): Not yet supported. |
| 214 return; | 213 return false; |
| 215 } | 214 } |
| 216 ASSERT(comp->instr() != NULL); | 215 ASSERT(comp->instr() != NULL); |
| 217 ASSERT(comp->InputCount() == 1); | 216 ASSERT(comp->InputCount() == 1); |
| 218 Computation* unary_op = NULL; | 217 Computation* unary_op = NULL; |
| 219 if (HasOneSmi(*comp->ic_data())) { | 218 if (HasOneSmi(*comp->ic_data())) { |
| 220 unary_op = new UnarySmiOpComp(op_kind, comp, comp->InputAt(0)); | 219 unary_op = new UnarySmiOpComp(op_kind, comp, comp->InputAt(0)); |
| 221 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { | 220 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { |
| 222 unary_op = new NumberNegateComp(comp, comp->InputAt(0)); | 221 unary_op = new NumberNegateComp(comp, comp->InputAt(0)); |
| 223 } | 222 } |
| 224 if (unary_op != NULL) { | 223 if (unary_op != NULL) { |
| 225 ASSERT(unary_op->ic_data() == NULL); | |
| 226 unary_op->set_ic_data(comp->ic_data()); | 224 unary_op->set_ic_data(comp->ic_data()); |
| 227 unary_op->set_instr(comp->instr()); | 225 comp->ReplaceWith(unary_op); |
| 228 comp->instr()->replace_computation(unary_op); | 226 return true; |
| 229 } | 227 } |
| 228 return false; |
| 230 } | 229 } |
| 231 | 230 |
| 232 | 231 |
| 233 // Returns true if all targets are the same. | 232 // Returns true if all targets are the same. |
| 234 // TODO(srdjan): if targets are native use their C_function to compare. | 233 // TODO(srdjan): if targets are native use their C_function to compare. |
| 235 static bool HasOneTarget(const ICData& ic_data) { | 234 static bool HasOneTarget(const ICData& ic_data) { |
| 236 ASSERT(ic_data.NumberOfChecks() > 0); | 235 ASSERT(ic_data.NumberOfChecks() > 0); |
| 237 Function& prev_target = Function::Handle(); | 236 Function& prev_target = Function::Handle(); |
| 238 GrowableArray<const Class*> classes; | 237 GrowableArray<const Class*> classes; |
| 239 ic_data.GetCheckAt(0, &classes, &prev_target); | 238 ic_data.GetCheckAt(0, &classes, &prev_target); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 259 field = cls.LookupInstanceField(field_name); | 258 field = cls.LookupInstanceField(field_name); |
| 260 if (!field.IsNull()) { | 259 if (!field.IsNull()) { |
| 261 return field.raw(); | 260 return field.raw(); |
| 262 } | 261 } |
| 263 cls = cls.SuperClass(); | 262 cls = cls.SuperClass(); |
| 264 } | 263 } |
| 265 return Field::null(); | 264 return Field::null(); |
| 266 } | 265 } |
| 267 | 266 |
| 268 | 267 |
| 268 // Returns all receiver class-ids and corresponding tagets for the given |
| 269 // 'ic_data', sorted so that a smi class id is at index[0] if it exists. |
| 270 // 'targets' can be NULL in which case it is not collected, |
| 271 static void ExtractClassIdsAndTargets(const ICData& ic_data, |
| 272 ZoneGrowableArray<intptr_t>* class_ids, |
| 273 ZoneGrowableArray<Function*>* targets) { |
| 274 ASSERT(class_ids != NULL); |
| 275 class_ids->Clear(); |
| 276 if (targets != NULL) { |
| 277 targets->Clear(); |
| 278 } |
| 279 intptr_t smi_index = -1; |
| 280 Function& target = Function::Handle(); |
| 281 GrowableArray<const Class*> classes; |
| 282 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 283 ic_data.GetCheckAt(i, &classes, &target); |
| 284 // Collect receiver class only. |
| 285 const intptr_t class_id = (*classes[0]).id(); |
| 286 if (ic_data.num_args_tested() > 1) { |
| 287 // Check if we have not already entered the class-id. |
| 288 intptr_t duplicate_class_id = -1; |
| 289 for (intptr_t k = 0; k < class_ids->length(); k++) { |
| 290 if ((*class_ids)[k] == class_id) { |
| 291 duplicate_class_id = k; |
| 292 break; |
| 293 } |
| 294 } |
| 295 if (duplicate_class_id >= 0) { |
| 296 ASSERT((targets == NULL) || |
| 297 ((*targets)[duplicate_class_id]->raw() == target.raw())); |
| 298 continue; |
| 299 } |
| 300 } |
| 301 if (class_id == kSmi) { |
| 302 ASSERT(smi_index < 0); // Classes entered only once in ic_data. |
| 303 smi_index = class_ids->length(); |
| 304 } |
| 305 class_ids->Add(class_id); |
| 306 if (targets != NULL) { |
| 307 targets->Add(&Function::ZoneHandle(target.raw())); |
| 308 } |
| 309 } |
| 310 if (smi_index >= 0) { |
| 311 // Smi class id must be at index 0. |
| 312 intptr_t temp_id = (*class_ids)[0]; |
| 313 (*class_ids)[0] = (*class_ids)[smi_index]; |
| 314 (*class_ids)[smi_index] = temp_id; |
| 315 if (targets != NULL) { |
| 316 Function* temp_func = (*targets)[0]; |
| 317 (*targets)[0] = (*targets)[smi_index]; |
| 318 (*targets)[smi_index] = temp_func; |
| 319 } |
| 320 } |
| 321 } |
| 322 |
| 323 |
| 269 // Returns array of all class ids that are in ic_data. The result is | 324 // Returns array of all class ids that are in ic_data. The result is |
| 270 // normalized so that a smi class is at index 0 if it exists in the ic_data. | 325 // normalized so that a smi class is at index 0 if it exists in the ic_data. |
| 271 static ZoneGrowableArray<intptr_t>* ExtractClassIds(const ICData& ic_data) { | 326 static ZoneGrowableArray<intptr_t>* ExtractClassIds(const ICData& ic_data) { |
| 272 if (ic_data.NumberOfChecks() == 0) return NULL; | 327 if (ic_data.NumberOfChecks() == 0) return NULL; |
| 273 ZoneGrowableArray<intptr_t>* result = | 328 ZoneGrowableArray<intptr_t>* result = |
| 274 new ZoneGrowableArray<intptr_t>(ic_data.NumberOfChecks()); | 329 new ZoneGrowableArray<intptr_t>(ic_data.NumberOfChecks()); |
| 275 intptr_t smi_index = -1; | 330 ExtractClassIdsAndTargets(ic_data, result, NULL); |
| 276 Function& target = Function::Handle(); | |
| 277 Class& cls = Class::Handle(); | |
| 278 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | |
| 279 ic_data.GetOneClassCheckAt(i, &cls, &target); | |
| 280 result->Add(cls.id()); | |
| 281 if (cls.id() == kSmi) { | |
| 282 ASSERT(smi_index < 0); // Classes entered only once in ic_data. | |
| 283 smi_index = i; | |
| 284 } | |
| 285 } | |
| 286 if (smi_index >= 0) { | |
| 287 // Smi class id must be at index 0. | |
| 288 intptr_t temp = (*result)[0]; | |
| 289 (*result)[0] = (*result)[smi_index]; | |
| 290 (*result)[smi_index] = temp; | |
| 291 } | |
| 292 return result; | 331 return result; |
| 293 } | 332 } |
| 294 | 333 |
| 295 | 334 |
| 296 // Only unique implicit instance getters can be currently handled. | 335 // Only unique implicit instance getters can be currently handled. |
| 297 void FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallComp* comp) { | 336 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallComp* comp) { |
| 298 ASSERT(comp->HasICData()); | 337 ASSERT(comp->HasICData()); |
| 299 const ICData& ic_data = *comp->ic_data(); | 338 const ICData& ic_data = *comp->ic_data(); |
| 300 if (ic_data.NumberOfChecks() == 0) { | 339 if (ic_data.NumberOfChecks() == 0) { |
| 301 // No type feedback collected. | 340 // No type feedback collected. |
| 302 return; | 341 return false; |
| 303 } | 342 } |
| 304 Function& target = Function::Handle(); | 343 Function& target = Function::Handle(); |
| 305 GrowableArray<const Class*> classes; | 344 GrowableArray<const Class*> classes; |
| 306 ic_data.GetCheckAt(0, &classes, &target); | 345 ic_data.GetCheckAt(0, &classes, &target); |
| 307 ASSERT(classes.length() == 1); | 346 ASSERT(classes.length() == 1); |
| 308 | 347 |
| 309 if (target.kind() == RawFunction::kImplicitGetter) { | 348 if (target.kind() == RawFunction::kImplicitGetter) { |
| 310 if (!HasOneTarget(ic_data)) { | 349 if (!HasOneTarget(ic_data)) { |
| 311 // TODO(srdjan): Implement for mutiple targets. | 350 // TODO(srdjan): Implement for mutiple targets. |
| 312 return; | 351 return false; |
| 313 } | 352 } |
| 314 // Inline implicit instance getter. | 353 // Inline implicit instance getter. |
| 315 const String& field_name = | 354 const String& field_name = |
| 316 String::Handle(Field::NameFromGetter(comp->function_name())); | 355 String::Handle(Field::NameFromGetter(comp->function_name())); |
| 317 const Field& field = Field::Handle(GetField(*classes[0], field_name)); | 356 const Field& field = Field::Handle(GetField(*classes[0], field_name)); |
| 318 ASSERT(!field.IsNull()); | 357 ASSERT(!field.IsNull()); |
| 319 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( | 358 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( |
| 320 field, comp->InputAt(0), comp, ExtractClassIds(ic_data)); | 359 field, comp->InputAt(0), comp, ExtractClassIds(ic_data)); |
| 321 // Replace 'comp' with 'load'. | 360 comp->ReplaceWith(load); |
| 322 load->set_instr(comp->instr()); | 361 return true; |
| 323 comp->instr()->replace_computation(load); | |
| 324 return; | |
| 325 } | 362 } |
| 326 | 363 |
| 327 // Not an implicit getter. | 364 // Not an implicit getter. |
| 328 MethodRecognizer::Kind recognized_kind = | 365 MethodRecognizer::Kind recognized_kind = |
| 329 MethodRecognizer::RecognizeKind(target); | 366 MethodRecognizer::RecognizeKind(target); |
| 330 | 367 |
| 331 // VM objects length getter. | 368 // VM objects length getter. |
| 332 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || | 369 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || |
| 333 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || | 370 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || |
| 334 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { | 371 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { |
| 335 if (!HasOneTarget(ic_data)) { | 372 if (!HasOneTarget(ic_data)) { |
| 336 // TODO(srdjan): Implement for mutiple targets. | 373 // TODO(srdjan): Implement for mutiple targets. |
| 337 return; | 374 return false; |
| 338 } | 375 } |
| 339 intptr_t length_offset = -1; | 376 intptr_t length_offset = -1; |
| 340 switch (recognized_kind) { | 377 switch (recognized_kind) { |
| 341 case MethodRecognizer::kObjectArrayLength: | 378 case MethodRecognizer::kObjectArrayLength: |
| 342 case MethodRecognizer::kImmutableArrayLength: | 379 case MethodRecognizer::kImmutableArrayLength: |
| 343 length_offset = Array::length_offset(); | 380 length_offset = Array::length_offset(); |
| 344 break; | 381 break; |
| 345 case MethodRecognizer::kGrowableArrayLength: | 382 case MethodRecognizer::kGrowableArrayLength: |
| 346 length_offset = GrowableObjectArray::length_offset(); | 383 length_offset = GrowableObjectArray::length_offset(); |
| 347 break; | 384 break; |
| 348 default: | 385 default: |
| 349 UNREACHABLE(); | 386 UNREACHABLE(); |
| 350 } | 387 } |
| 351 LoadVMFieldComp* load = new LoadVMFieldComp( | 388 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 352 comp->InputAt(0), | 389 comp->InputAt(0), |
| 353 length_offset, | 390 length_offset, |
| 354 Type::ZoneHandle(Type::IntInterface()), | 391 Type::ZoneHandle(Type::IntInterface()), |
| 355 comp, | 392 comp, |
| 356 ExtractClassIds(ic_data)); | 393 ExtractClassIds(ic_data)); |
| 357 load->set_instr(comp->instr()); | 394 comp->ReplaceWith(load); |
| 358 comp->instr()->replace_computation(load); | 395 return true; |
| 359 return; | |
| 360 } | 396 } |
| 361 | 397 |
| 362 if (recognized_kind == MethodRecognizer::kStringBaseLength) { | 398 if (recognized_kind == MethodRecognizer::kStringBaseLength) { |
| 363 ASSERT(HasOneTarget(ic_data)); | 399 ASSERT(HasOneTarget(ic_data)); |
| 364 LoadVMFieldComp* load = new LoadVMFieldComp( | 400 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 365 comp->InputAt(0), | 401 comp->InputAt(0), |
| 366 String::length_offset(), | 402 String::length_offset(), |
| 367 Type::ZoneHandle(Type::IntInterface()), | 403 Type::ZoneHandle(Type::IntInterface()), |
| 368 comp, | 404 comp, |
| 369 ExtractClassIds(ic_data)); | 405 ExtractClassIds(ic_data)); |
| 370 load->set_instr(comp->instr()); | 406 comp->ReplaceWith(load); |
| 371 comp->instr()->replace_computation(load); | 407 return true; |
| 372 return; | |
| 373 } | 408 } |
| 409 return false; |
| 374 } | 410 } |
| 375 | 411 |
| 376 | 412 |
| 377 // Inline only simple, frequently called core library methods. | 413 // Inline only simple, frequently called core library methods. |
| 378 void FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallComp* comp) { | 414 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallComp* comp) { |
| 379 ASSERT(comp->HasICData()); | 415 ASSERT(comp->HasICData()); |
| 380 const ICData& ic_data = *comp->ic_data(); | 416 const ICData& ic_data = *comp->ic_data(); |
| 381 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { | 417 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { |
| 382 // No type feedback collected. | 418 // No type feedback collected. |
| 383 return; | 419 return false; |
| 384 } | 420 } |
| 385 Function& target = Function::Handle(); | 421 Function& target = Function::Handle(); |
| 386 GrowableArray<const Class*> classes; | 422 GrowableArray<const Class*> classes; |
| 387 ic_data.GetCheckAt(0, &classes, &target); | 423 ic_data.GetCheckAt(0, &classes, &target); |
| 388 ASSERT(classes.length() == 1); | |
| 389 MethodRecognizer::Kind recognized_kind = | 424 MethodRecognizer::Kind recognized_kind = |
| 390 MethodRecognizer::RecognizeKind(target); | 425 MethodRecognizer::RecognizeKind(target); |
| 391 | 426 |
| 392 ObjectKind from_kind; | 427 ObjectKind from_kind; |
| 393 if (recognized_kind == MethodRecognizer::kDoubleToDouble) { | 428 if (recognized_kind == MethodRecognizer::kDoubleToDouble) { |
| 394 from_kind = kDouble; | 429 from_kind = kDouble; |
| 395 } else if (recognized_kind == MethodRecognizer::kIntegerToDouble) { | 430 } else if (recognized_kind == MethodRecognizer::kIntegerToDouble) { |
| 396 from_kind = kSmi; | 431 from_kind = kSmi; |
| 397 } else { | 432 } else { |
| 398 return; | 433 return false; |
| 399 } | 434 } |
| 400 | 435 |
| 401 if (classes[0]->id() != from_kind) { | 436 if (classes[0]->id() != from_kind) { |
| 402 return; | 437 return false; |
| 403 } | 438 } |
| 404 | |
| 405 ToDoubleComp* coerce = new ToDoubleComp( | 439 ToDoubleComp* coerce = new ToDoubleComp( |
| 406 comp->InputAt(0), from_kind, comp); | 440 comp->InputAt(0), from_kind, comp); |
| 407 coerce->set_instr(comp->instr()); | 441 coerce->set_instr(comp->instr()); |
| 408 comp->instr()->replace_computation(coerce); | 442 comp->instr()->replace_computation(coerce); |
| 443 return true; |
| 409 } | 444 } |
| 410 | 445 |
| 411 | 446 |
| 412 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { | 447 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { |
| 413 if (comp->HasICData()) { | 448 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { |
| 414 const String& function_name = comp->function_name(); | 449 const String& function_name = comp->function_name(); |
| 415 Token::Kind op_kind = Token::GetBinaryOp(function_name); | 450 Token::Kind op_kind = Token::GetBinaryOp(function_name); |
| 416 if (op_kind != Token::kILLEGAL) { | 451 if ((op_kind != Token::kILLEGAL) && TryReplaceWithBinaryOp(comp, op_kind)) { |
| 417 TryReplaceWithBinaryOp(comp, op_kind); | |
| 418 return; | 452 return; |
| 419 } | 453 } |
| 420 op_kind = Token::GetUnaryOp(function_name); | 454 op_kind = Token::GetUnaryOp(function_name); |
| 421 if (op_kind != Token::kILLEGAL) { | 455 if ((op_kind != Token::kILLEGAL) && TryReplaceWithUnaryOp(comp, op_kind)) { |
| 422 TryReplaceWithUnaryOp(comp, op_kind); | |
| 423 return; | 456 return; |
| 424 } | 457 } |
| 425 if (Field::IsGetterName(function_name)) { | 458 if ((Field::IsGetterName(function_name)) && TryInlineInstanceGetter(comp)) { |
| 426 TryInlineInstanceGetter(comp); | |
| 427 return; | 459 return; |
| 428 } | 460 } |
| 429 TryInlineInstanceMethod(comp); | 461 if (TryInlineInstanceMethod(comp)) { |
| 462 return; |
| 463 } |
| 464 const intptr_t kMaxChecks = 4; |
| 465 if (comp->ic_data()->num_args_tested() <= kMaxChecks) { |
| 466 ZoneGrowableArray<intptr_t>* class_ids = |
| 467 new ZoneGrowableArray<intptr_t>(); |
| 468 ZoneGrowableArray<Function*>* targets = |
| 469 new ZoneGrowableArray<Function*>(); |
| 470 ExtractClassIdsAndTargets(*comp->ic_data(), class_ids, targets); |
| 471 PolymorphicInstanceCallComp* call = |
| 472 new PolymorphicInstanceCallComp(comp, *class_ids, *targets); |
| 473 comp->ReplaceWith(call); |
| 474 } |
| 430 } | 475 } |
| 431 } | 476 } |
| 432 | 477 |
| 433 | 478 |
| 434 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp) { | 479 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp) { |
| 435 MethodRecognizer::Kind recognized_kind = | 480 MethodRecognizer::Kind recognized_kind = |
| 436 MethodRecognizer::RecognizeKind(comp->function()); | 481 MethodRecognizer::RecognizeKind(comp->function()); |
| 437 if (recognized_kind == MethodRecognizer::kMathSqrt) { | 482 if (recognized_kind == MethodRecognizer::kMathSqrt) { |
| 438 // TODO(srdjan): Implement this. | 483 // TODO(srdjan): Implement this. |
| 439 } | 484 } |
| 440 } | 485 } |
| 441 | 486 |
| 442 | 487 |
| 443 void FlowGraphOptimizer::TryInlineInstanceSetter(InstanceSetterComp* comp) { | 488 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceSetterComp* comp) { |
| 444 ASSERT(comp->HasICData()); | 489 ASSERT(comp->HasICData()); |
| 445 const ICData& ic_data = *comp->ic_data(); | 490 const ICData& ic_data = *comp->ic_data(); |
| 446 if (ic_data.NumberOfChecks() == 0) { | 491 if (ic_data.NumberOfChecks() == 0) { |
| 447 // No type feedback collected. | 492 // No type feedback collected. |
| 448 return; | 493 return false; |
| 449 } | 494 } |
| 450 if (!HasOneTarget(ic_data)) { | 495 if (!HasOneTarget(ic_data)) { |
| 451 // TODO(srdjan): Implement when not all targets are the sa,e. | 496 // TODO(srdjan): Implement when not all targets are the sa,e. |
| 452 return; | 497 return false; |
| 453 } | 498 } |
| 454 Function& target = Function::Handle(); | 499 Function& target = Function::Handle(); |
| 455 Class& cls = Class::Handle(); | 500 Class& cls = Class::Handle(); |
| 456 ic_data.GetOneClassCheckAt(0, &cls, &target); | 501 ic_data.GetOneClassCheckAt(0, &cls, &target); |
| 457 if (target.kind() != RawFunction::kImplicitSetter) { | 502 if (target.kind() != RawFunction::kImplicitSetter) { |
| 458 // Not an implicit setter. | 503 // Not an implicit setter. |
| 459 // TODO(srdjan): Inline special setters. | 504 // TODO(srdjan): Inline special setters. |
| 460 return; | 505 return false; |
| 461 } | 506 } |
| 462 // Inline implicit instance setter. | 507 // Inline implicit instance setter. |
| 463 const Field& field = Field::Handle(GetField(cls, comp->field_name())); | 508 const Field& field = Field::Handle(GetField(cls, comp->field_name())); |
| 464 ASSERT(!field.IsNull()); | 509 ASSERT(!field.IsNull()); |
| 465 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( | 510 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( |
| 466 field, | 511 field, |
| 467 comp->InputAt(0), | 512 comp->InputAt(0), |
| 468 comp->InputAt(1), | 513 comp->InputAt(1), |
| 469 comp, | 514 comp, |
| 470 ExtractClassIds(ic_data)); | 515 ExtractClassIds(ic_data)); |
| 471 // Replace 'comp' with 'store'. | 516 comp->ReplaceWith(store); |
| 472 store->set_instr(comp->instr()); | 517 return true; |
| 473 comp->instr()->replace_computation(store); | |
| 474 } | 518 } |
| 475 | 519 |
| 476 | 520 |
| 477 | 521 |
| 478 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { | 522 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { |
| 479 // TODO(srdjan): Add assigneable check node if --enable_type_checks. | 523 // TODO(srdjan): Add assigneable check node if --enable_type_checks. |
| 480 if (comp->HasICData() && !FLAG_enable_type_checks) { | 524 if (comp->HasICData() && !FLAG_enable_type_checks) { |
| 481 TryInlineInstanceSetter(comp); | 525 TryInlineInstanceSetter(comp); |
| 482 } | 526 } |
| 483 } | 527 } |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 instr->computation()->Accept(this); | 632 instr->computation()->Accept(this); |
| 589 } | 633 } |
| 590 | 634 |
| 591 | 635 |
| 592 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { | 636 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| 593 instr->computation()->Accept(this); | 637 instr->computation()->Accept(this); |
| 594 } | 638 } |
| 595 | 639 |
| 596 | 640 |
| 597 } // namespace dart | 641 } // namespace dart |
| OLD | NEW |