Chromium Code Reviews| 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 static void ExtractClassIdsAndTargets(const ICData& ic_data, | |
| 271 ZoneGrowableArray<intptr_t>* class_ids, | |
| 272 ZoneGrowableArray<Function*>* targets) { | |
| 273 ASSERT(class_ids != NULL); | |
| 274 ASSERT(targets != NULL); | |
| 275 class_ids->Clear(); | |
| 276 targets->Clear(); | |
| 277 intptr_t smi_index = -1; | |
| 278 Function& target = Function::Handle(); | |
| 279 GrowableArray<const Class*> classes; | |
| 280 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | |
| 281 ic_data.GetCheckAt(i, &classes, &target); | |
| 282 // Collect receiver class only. | |
| 283 const intptr_t class_id = (*classes[0]).id(); | |
| 284 if (ic_data.num_args_tested() > 1) { | |
| 285 // Check if we have not already entered the class-id. | |
| 286 Function* target_found = NULL; | |
| 287 for (intptr_t k = 0; k < class_ids->length(); k++) { | |
| 288 if ((*class_ids)[k] == class_id) { | |
| 289 target_found = (*targets)[k]; | |
| 290 break; | |
| 291 } | |
| 292 } | |
| 293 if (target_found != NULL) { | |
| 294 ASSERT(target_found->raw() == target.raw()); | |
| 295 continue; | |
| 296 } | |
| 297 } | |
| 298 if (class_id == kSmi) { | |
| 299 ASSERT(smi_index < 0); // Classes entered only once in ic_data. | |
| 300 smi_index = class_ids->length(); | |
| 301 } | |
| 302 class_ids->Add(class_id); | |
| 303 targets->Add(&Function::ZoneHandle(target.raw())); | |
| 304 } | |
| 305 if (smi_index >= 0) { | |
| 306 // Smi class id must be at index 0. | |
| 307 intptr_t temp_id = (*class_ids)[0]; | |
| 308 Function* temp_func = (*targets)[0]; | |
| 309 (*class_ids)[0] = (*class_ids)[smi_index]; | |
| 310 (*targets)[0] = (*targets)[smi_index]; | |
| 311 (*class_ids)[smi_index] = temp_id; | |
| 312 (*targets)[smi_index] = temp_func; | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 | |
| 269 // Returns array of all class ids that are in ic_data. The result is | 317 // 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. | 318 // 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) { | 319 static ZoneGrowableArray<intptr_t>* ExtractClassIds(const ICData& ic_data) { |
| 272 if (ic_data.NumberOfChecks() == 0) return NULL; | 320 if (ic_data.NumberOfChecks() == 0) return NULL; |
| 273 ZoneGrowableArray<intptr_t>* result = | 321 ZoneGrowableArray<intptr_t>* result = |
| 274 new ZoneGrowableArray<intptr_t>(ic_data.NumberOfChecks()); | 322 new ZoneGrowableArray<intptr_t>(ic_data.NumberOfChecks()); |
| 275 intptr_t smi_index = -1; | 323 ZoneGrowableArray<Function*>* dummy = |
| 276 Function& target = Function::Handle(); | 324 new ZoneGrowableArray<Function*>(ic_data.NumberOfChecks()); |
| 277 Class& cls = Class::Handle(); | 325 ExtractClassIdsAndTargets(ic_data, result, dummy); |
|
Vyacheslav Egorov (Google)
2012/06/13 09:02:27
how about passing NULL instead of dummy? Collectin
srdjan
2012/06/13 18:34:24
Done.
| |
| 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; | 326 return result; |
| 293 } | 327 } |
| 294 | 328 |
| 295 | 329 |
| 296 // Only unique implicit instance getters can be currently handled. | 330 // Only unique implicit instance getters can be currently handled. |
| 297 void FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallComp* comp) { | 331 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallComp* comp) { |
| 298 ASSERT(comp->HasICData()); | 332 ASSERT(comp->HasICData()); |
| 299 const ICData& ic_data = *comp->ic_data(); | 333 const ICData& ic_data = *comp->ic_data(); |
| 300 if (ic_data.NumberOfChecks() == 0) { | 334 if (ic_data.NumberOfChecks() == 0) { |
| 301 // No type feedback collected. | 335 // No type feedback collected. |
| 302 return; | 336 return false; |
| 303 } | 337 } |
| 304 Function& target = Function::Handle(); | 338 Function& target = Function::Handle(); |
| 305 GrowableArray<const Class*> classes; | 339 GrowableArray<const Class*> classes; |
| 306 ic_data.GetCheckAt(0, &classes, &target); | 340 ic_data.GetCheckAt(0, &classes, &target); |
| 307 ASSERT(classes.length() == 1); | 341 ASSERT(classes.length() == 1); |
| 308 | 342 |
| 309 if (target.kind() == RawFunction::kImplicitGetter) { | 343 if (target.kind() == RawFunction::kImplicitGetter) { |
| 310 if (!HasOneTarget(ic_data)) { | 344 if (!HasOneTarget(ic_data)) { |
| 311 // TODO(srdjan): Implement for mutiple targets. | 345 // TODO(srdjan): Implement for mutiple targets. |
| 312 return; | 346 return false; |
| 313 } | 347 } |
| 314 // Inline implicit instance getter. | 348 // Inline implicit instance getter. |
| 315 const String& field_name = | 349 const String& field_name = |
| 316 String::Handle(Field::NameFromGetter(comp->function_name())); | 350 String::Handle(Field::NameFromGetter(comp->function_name())); |
| 317 const Field& field = Field::Handle(GetField(*classes[0], field_name)); | 351 const Field& field = Field::Handle(GetField(*classes[0], field_name)); |
| 318 ASSERT(!field.IsNull()); | 352 ASSERT(!field.IsNull()); |
| 319 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( | 353 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( |
| 320 field, comp->InputAt(0), comp, ExtractClassIds(ic_data)); | 354 field, comp->InputAt(0), comp, ExtractClassIds(ic_data)); |
| 321 // Replace 'comp' with 'load'. | 355 comp->ReplaceWith(load); |
| 322 load->set_instr(comp->instr()); | 356 return true; |
| 323 comp->instr()->replace_computation(load); | |
| 324 return; | |
| 325 } | 357 } |
| 326 | 358 |
| 327 // Not an implicit getter. | 359 // Not an implicit getter. |
| 328 MethodRecognizer::Kind recognized_kind = | 360 MethodRecognizer::Kind recognized_kind = |
| 329 MethodRecognizer::RecognizeKind(target); | 361 MethodRecognizer::RecognizeKind(target); |
| 330 | 362 |
| 331 // VM objects length getter. | 363 // VM objects length getter. |
| 332 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || | 364 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || |
| 333 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || | 365 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || |
| 334 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { | 366 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { |
| 335 if (!HasOneTarget(ic_data)) { | 367 if (!HasOneTarget(ic_data)) { |
| 336 // TODO(srdjan): Implement for mutiple targets. | 368 // TODO(srdjan): Implement for mutiple targets. |
| 337 return; | 369 return false; |
| 338 } | 370 } |
| 339 intptr_t length_offset = -1; | 371 intptr_t length_offset = -1; |
| 340 switch (recognized_kind) { | 372 switch (recognized_kind) { |
| 341 case MethodRecognizer::kObjectArrayLength: | 373 case MethodRecognizer::kObjectArrayLength: |
| 342 case MethodRecognizer::kImmutableArrayLength: | 374 case MethodRecognizer::kImmutableArrayLength: |
| 343 length_offset = Array::length_offset(); | 375 length_offset = Array::length_offset(); |
| 344 break; | 376 break; |
| 345 case MethodRecognizer::kGrowableArrayLength: | 377 case MethodRecognizer::kGrowableArrayLength: |
| 346 length_offset = GrowableObjectArray::length_offset(); | 378 length_offset = GrowableObjectArray::length_offset(); |
| 347 break; | 379 break; |
| 348 default: | 380 default: |
| 349 UNREACHABLE(); | 381 UNREACHABLE(); |
| 350 } | 382 } |
| 351 LoadVMFieldComp* load = new LoadVMFieldComp( | 383 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 352 comp->InputAt(0), | 384 comp->InputAt(0), |
| 353 length_offset, | 385 length_offset, |
| 354 Type::ZoneHandle(Type::IntInterface()), | 386 Type::ZoneHandle(Type::IntInterface()), |
| 355 comp, | 387 comp, |
| 356 ExtractClassIds(ic_data)); | 388 ExtractClassIds(ic_data)); |
| 357 load->set_instr(comp->instr()); | 389 comp->ReplaceWith(load); |
| 358 comp->instr()->replace_computation(load); | 390 return true; |
| 359 return; | |
| 360 } | 391 } |
| 361 | 392 |
| 362 if (recognized_kind == MethodRecognizer::kStringBaseLength) { | 393 if (recognized_kind == MethodRecognizer::kStringBaseLength) { |
| 363 ASSERT(HasOneTarget(ic_data)); | 394 ASSERT(HasOneTarget(ic_data)); |
| 364 LoadVMFieldComp* load = new LoadVMFieldComp( | 395 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 365 comp->InputAt(0), | 396 comp->InputAt(0), |
| 366 String::length_offset(), | 397 String::length_offset(), |
| 367 Type::ZoneHandle(Type::IntInterface()), | 398 Type::ZoneHandle(Type::IntInterface()), |
| 368 comp, | 399 comp, |
| 369 ExtractClassIds(ic_data)); | 400 ExtractClassIds(ic_data)); |
| 370 load->set_instr(comp->instr()); | 401 comp->ReplaceWith(load); |
| 371 comp->instr()->replace_computation(load); | 402 return true; |
| 372 return; | |
| 373 } | 403 } |
| 404 return false; | |
| 374 } | 405 } |
| 375 | 406 |
| 376 | 407 |
| 377 // Inline only simple, frequently called core library methods. | 408 // Inline only simple, frequently called core library methods. |
| 378 void FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallComp* comp) { | 409 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallComp* comp) { |
| 379 ASSERT(comp->HasICData()); | 410 ASSERT(comp->HasICData()); |
| 380 const ICData& ic_data = *comp->ic_data(); | 411 const ICData& ic_data = *comp->ic_data(); |
| 381 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { | 412 if ((ic_data.NumberOfChecks() == 0) || !HasOneTarget(ic_data)) { |
| 382 // No type feedback collected. | 413 // No type feedback collected. |
| 383 return; | 414 return false; |
| 384 } | 415 } |
| 385 Function& target = Function::Handle(); | 416 Function& target = Function::Handle(); |
| 386 GrowableArray<const Class*> classes; | 417 GrowableArray<const Class*> classes; |
| 387 ic_data.GetCheckAt(0, &classes, &target); | 418 ic_data.GetCheckAt(0, &classes, &target); |
| 388 ASSERT(classes.length() == 1); | |
| 389 MethodRecognizer::Kind recognized_kind = | 419 MethodRecognizer::Kind recognized_kind = |
| 390 MethodRecognizer::RecognizeKind(target); | 420 MethodRecognizer::RecognizeKind(target); |
| 391 if (recognized_kind == MethodRecognizer::kDoubleToDouble) { | 421 if (recognized_kind == MethodRecognizer::kDoubleToDouble) { |
| 392 // TODO(srdjan): Implement. | 422 // TODO(srdjan): Implement. |
| 393 } | 423 } |
| 394 if (recognized_kind == MethodRecognizer::kIntegerToDouble) { | 424 if (recognized_kind == MethodRecognizer::kIntegerToDouble) { |
| 395 // TODO(srdjan): Implement. | 425 // TODO(srdjan): Implement. |
| 396 } | 426 } |
| 427 return false; | |
| 397 } | 428 } |
| 398 | 429 |
| 399 | 430 |
| 400 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { | 431 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp) { |
| 401 if (comp->HasICData()) { | 432 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { |
| 402 const String& function_name = comp->function_name(); | 433 const String& function_name = comp->function_name(); |
| 403 Token::Kind op_kind = Token::GetBinaryOp(function_name); | 434 Token::Kind op_kind = Token::GetBinaryOp(function_name); |
|
Vyacheslav Egorov (Google)
2012/06/13 09:02:27
Can we just store op_kind in the InstanceCallComp
srdjan
2012/06/13 18:34:24
Yes, next CL.
| |
| 404 if (op_kind != Token::kILLEGAL) { | 435 if ((op_kind != Token::kILLEGAL) && TryReplaceWithBinaryOp(comp, op_kind)) { |
| 405 TryReplaceWithBinaryOp(comp, op_kind); | |
| 406 return; | 436 return; |
| 407 } | 437 } |
| 408 op_kind = Token::GetUnaryOp(function_name); | 438 op_kind = Token::GetUnaryOp(function_name); |
| 409 if (op_kind != Token::kILLEGAL) { | 439 if ((op_kind != Token::kILLEGAL) && TryReplaceWithUnaryOp(comp, op_kind)) { |
| 410 TryReplaceWithUnaryOp(comp, op_kind); | |
| 411 return; | 440 return; |
| 412 } | 441 } |
| 413 if (Field::IsGetterName(function_name)) { | 442 if ((Field::IsGetterName(function_name)) && TryInlineInstanceGetter(comp)) { |
| 414 TryInlineInstanceGetter(comp); | |
| 415 return; | 443 return; |
| 416 } | 444 } |
| 417 TryInlineInstanceMethod(comp); | 445 if (TryInlineInstanceMethod(comp)) { |
| 446 return; | |
| 447 } | |
| 448 const intptr_t kMaxChecks = 4; | |
| 449 if (comp->ic_data()->num_args_tested() <= kMaxChecks) { | |
| 450 ZoneGrowableArray<intptr_t>* class_ids = | |
| 451 new ZoneGrowableArray<intptr_t>(); | |
| 452 ZoneGrowableArray<Function*>* targets = | |
| 453 new ZoneGrowableArray<Function*>(); | |
| 454 ExtractClassIdsAndTargets(*comp->ic_data(), class_ids, targets); | |
| 455 CheckedInstanceCallComp* call = | |
| 456 new CheckedInstanceCallComp(comp, *class_ids, *targets); | |
| 457 comp->ReplaceWith(call); | |
| 458 } | |
| 418 } | 459 } |
| 419 } | 460 } |
| 420 | 461 |
| 421 | 462 |
| 422 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp) { | 463 void FlowGraphOptimizer::VisitStaticCall(StaticCallComp* comp) { |
| 423 MethodRecognizer::Kind recognized_kind = | 464 MethodRecognizer::Kind recognized_kind = |
| 424 MethodRecognizer::RecognizeKind(comp->function()); | 465 MethodRecognizer::RecognizeKind(comp->function()); |
| 425 if (recognized_kind == MethodRecognizer::kMathSqrt) { | 466 if (recognized_kind == MethodRecognizer::kMathSqrt) { |
| 426 // TODO(srdjan): Implement this. | 467 // TODO(srdjan): Implement this. |
| 427 } | 468 } |
| 428 } | 469 } |
| 429 | 470 |
| 430 | 471 |
| 431 void FlowGraphOptimizer::TryInlineInstanceSetter(InstanceSetterComp* comp) { | 472 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceSetterComp* comp) { |
| 432 ASSERT(comp->HasICData()); | 473 ASSERT(comp->HasICData()); |
| 433 const ICData& ic_data = *comp->ic_data(); | 474 const ICData& ic_data = *comp->ic_data(); |
| 434 if (ic_data.NumberOfChecks() == 0) { | 475 if (ic_data.NumberOfChecks() == 0) { |
| 435 // No type feedback collected. | 476 // No type feedback collected. |
| 436 return; | 477 return false; |
| 437 } | 478 } |
| 438 if (!HasOneTarget(ic_data)) { | 479 if (!HasOneTarget(ic_data)) { |
| 439 // TODO(srdjan): Implement when not all targets are the sa,e. | 480 // TODO(srdjan): Implement when not all targets are the sa,e. |
| 440 return; | 481 return false; |
| 441 } | 482 } |
| 442 Function& target = Function::Handle(); | 483 Function& target = Function::Handle(); |
| 443 Class& cls = Class::Handle(); | 484 Class& cls = Class::Handle(); |
| 444 ic_data.GetOneClassCheckAt(0, &cls, &target); | 485 ic_data.GetOneClassCheckAt(0, &cls, &target); |
| 445 if (target.kind() != RawFunction::kImplicitSetter) { | 486 if (target.kind() != RawFunction::kImplicitSetter) { |
| 446 // Not an implicit setter. | 487 // Not an implicit setter. |
| 447 // TODO(srdjan): Inline special setters. | 488 // TODO(srdjan): Inline special setters. |
| 448 return; | 489 return false; |
| 449 } | 490 } |
| 450 // Inline implicit instance setter. | 491 // Inline implicit instance setter. |
| 451 const Field& field = Field::Handle(GetField(cls, comp->field_name())); | 492 const Field& field = Field::Handle(GetField(cls, comp->field_name())); |
| 452 ASSERT(!field.IsNull()); | 493 ASSERT(!field.IsNull()); |
| 453 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( | 494 StoreInstanceFieldComp* store = new StoreInstanceFieldComp( |
| 454 field, | 495 field, |
| 455 comp->InputAt(0), | 496 comp->InputAt(0), |
| 456 comp->InputAt(1), | 497 comp->InputAt(1), |
| 457 comp, | 498 comp, |
| 458 ExtractClassIds(ic_data)); | 499 ExtractClassIds(ic_data)); |
| 459 // Replace 'comp' with 'store'. | 500 comp->ReplaceWith(store); |
| 460 store->set_instr(comp->instr()); | 501 return true; |
| 461 comp->instr()->replace_computation(store); | |
| 462 } | 502 } |
| 463 | 503 |
| 464 | 504 |
| 465 | 505 |
| 466 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { | 506 void FlowGraphOptimizer::VisitInstanceSetter(InstanceSetterComp* comp) { |
| 467 // TODO(srdjan): Add assigneable check node if --enable_type_checks. | 507 // TODO(srdjan): Add assigneable check node if --enable_type_checks. |
| 468 if (comp->HasICData() && !FLAG_enable_type_checks) { | 508 if (comp->HasICData() && !FLAG_enable_type_checks) { |
| 469 TryInlineInstanceSetter(comp); | 509 TryInlineInstanceSetter(comp); |
| 470 } | 510 } |
| 471 } | 511 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 503 ASSERT(HasOneTarget(ic_data)); | 543 ASSERT(HasOneTarget(ic_data)); |
| 504 | 544 |
| 505 if (HasTwoSmi(ic_data)) { | 545 if (HasTwoSmi(ic_data)) { |
| 506 comp->set_operands_class_id(kSmi); | 546 comp->set_operands_class_id(kSmi); |
| 507 } else if (HasTwoDouble(ic_data)) { | 547 } else if (HasTwoDouble(ic_data)) { |
| 508 comp->set_operands_class_id(kDouble); | 548 comp->set_operands_class_id(kDouble); |
| 509 } | 549 } |
| 510 } | 550 } |
| 511 | 551 |
| 512 | 552 |
| 553 void FlowGraphOptimizer::VisitEqualityCompare(EqualityCompareComp* comp) { | |
| 554 if (!comp->HasICData()) return; | |
| 555 const ICData& ic_data = *comp->ic_data(); | |
| 556 if (ic_data.NumberOfChecks() != 1) return; | |
| 557 ASSERT(HasOneTarget(ic_data)); | |
| 558 if (HasTwoSmi(ic_data)) { | |
| 559 comp->set_operands_class_id(kSmi); | |
| 560 } | |
| 561 } | |
| 562 | |
| 563 | |
| 513 void FlowGraphOptimizer::VisitDo(DoInstr* instr) { | 564 void FlowGraphOptimizer::VisitDo(DoInstr* instr) { |
| 514 instr->computation()->Accept(this); | 565 instr->computation()->Accept(this); |
| 515 } | 566 } |
| 516 | 567 |
| 517 | 568 |
| 518 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { | 569 void FlowGraphOptimizer::VisitBind(BindInstr* instr) { |
| 519 instr->computation()->Accept(this); | 570 instr->computation()->Accept(this); |
| 520 } | 571 } |
| 521 | 572 |
| 522 | 573 |
| 523 } // namespace dart | 574 } // namespace dart |
| OLD | NEW |