| 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 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 return ICDataHasReceiverClassId(ic_data, kDouble); | 107 return ICDataHasReceiverClassId(ic_data, kDouble); |
| 108 } | 108 } |
| 109 | 109 |
| 110 | 110 |
| 111 static bool HasOnlyTwoDouble(const ICData& ic_data) { | 111 static bool HasOnlyTwoDouble(const ICData& ic_data) { |
| 112 return (ic_data.NumberOfChecks() == 1) && | 112 return (ic_data.NumberOfChecks() == 1) && |
| 113 ICDataHasReceiverArgumentClassIds(ic_data, kDouble, kDouble); | 113 ICDataHasReceiverArgumentClassIds(ic_data, kDouble, kDouble); |
| 114 } | 114 } |
| 115 | 115 |
| 116 | 116 |
| 117 static void RemovePushArguments(InstanceCallComp* comp) { |
| 118 // Remove original push arguments. |
| 119 for (intptr_t i = 0; i < comp->ArgumentCount(); ++i) { |
| 120 comp->ArgumentAt(i)->RemoveFromGraph(); |
| 121 } |
| 122 } |
| 123 |
| 124 |
| 117 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, | 125 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(BindInstr* instr, |
| 118 InstanceCallComp* comp, | 126 InstanceCallComp* comp, |
| 119 Token::Kind op_kind) { | 127 Token::Kind op_kind) { |
| 120 BinaryOpComp::OperandsType operands_type = BinaryOpComp::kDynamicOperands; | 128 BinaryOpComp::OperandsType operands_type = BinaryOpComp::kDynamicOperands; |
| 121 ASSERT(comp->HasICData()); | 129 ASSERT(comp->HasICData()); |
| 122 const ICData& ic_data = *comp->ic_data(); | 130 const ICData& ic_data = *comp->ic_data(); |
| 123 switch (op_kind) { | 131 switch (op_kind) { |
| 124 case Token::kADD: | 132 case Token::kADD: |
| 125 case Token::kSUB: | 133 case Token::kSUB: |
| 126 case Token::kMUL: | 134 case Token::kMUL: |
| (...skipping 29 matching lines...) Expand all Loading... |
| 156 if (HasOnlyTwoSmi(ic_data)) { | 164 if (HasOnlyTwoSmi(ic_data)) { |
| 157 operands_type = BinaryOpComp::kSmiOperands; | 165 operands_type = BinaryOpComp::kSmiOperands; |
| 158 } else { | 166 } else { |
| 159 return false; | 167 return false; |
| 160 } | 168 } |
| 161 break; | 169 break; |
| 162 default: | 170 default: |
| 163 UNREACHABLE(); | 171 UNREACHABLE(); |
| 164 }; | 172 }; |
| 165 | 173 |
| 166 ASSERT(comp->InputCount() == 2); | 174 ASSERT(comp->ArgumentCount() == 2); |
| 167 Value* left = comp->InputAt(0); | 175 Value* left = comp->ArgumentAt(0)->value(); |
| 168 Value* right = comp->InputAt(1); | 176 Value* right = comp->ArgumentAt(1)->value(); |
| 169 BinaryOpComp* bin_op = | 177 BinaryOpComp* bin_op = |
| 170 new BinaryOpComp(op_kind, | 178 new BinaryOpComp(op_kind, |
| 171 operands_type, | 179 operands_type, |
| 172 comp, | 180 comp, |
| 173 left, | 181 left, |
| 174 right); | 182 right); |
| 175 bin_op->set_ic_data(comp->ic_data()); | 183 bin_op->set_ic_data(comp->ic_data()); |
| 176 instr->set_computation(bin_op); | 184 instr->set_computation(bin_op); |
| 185 RemovePushArguments(comp); |
| 177 return true; | 186 return true; |
| 178 } | 187 } |
| 179 | 188 |
| 180 | 189 |
| 181 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(BindInstr* instr, | 190 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(BindInstr* instr, |
| 182 InstanceCallComp* comp, | 191 InstanceCallComp* comp, |
| 183 Token::Kind op_kind) { | 192 Token::Kind op_kind) { |
| 184 if (comp->ic_data()->NumberOfChecks() != 1) { | 193 if (comp->ic_data()->NumberOfChecks() != 1) { |
| 185 // TODO(srdjan): Not yet supported. | 194 // TODO(srdjan): Not yet supported. |
| 186 return false; | 195 return false; |
| 187 } | 196 } |
| 188 ASSERT(comp->InputCount() == 1); | 197 ASSERT(comp->ArgumentCount() == 1); |
| 189 Computation* unary_op = NULL; | 198 Computation* unary_op = NULL; |
| 190 if (HasOneSmi(*comp->ic_data())) { | 199 if (HasOneSmi(*comp->ic_data())) { |
| 191 unary_op = new UnarySmiOpComp(op_kind, comp, comp->InputAt(0)); | 200 unary_op = new UnarySmiOpComp(op_kind, comp, comp->ArgumentAt(0)->value()); |
| 192 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { | 201 } else if (HasOneDouble(*comp->ic_data()) && (op_kind == Token::kNEGATE)) { |
| 193 unary_op = new NumberNegateComp(comp, comp->InputAt(0)); | 202 unary_op = new NumberNegateComp(comp, comp->ArgumentAt(0)->value()); |
| 194 } | 203 } |
| 195 if (unary_op != NULL) { | 204 if (unary_op == NULL) return false; |
| 196 unary_op->set_ic_data(comp->ic_data()); | 205 |
| 197 instr->set_computation(unary_op); | 206 unary_op->set_ic_data(comp->ic_data()); |
| 198 return true; | 207 instr->set_computation(unary_op); |
| 199 } | 208 RemovePushArguments(comp); |
| 200 return false; | 209 return true; |
| 201 } | 210 } |
| 202 | 211 |
| 203 | 212 |
| 204 // Returns true if all targets are the same. | 213 // Returns true if all targets are the same. |
| 205 // TODO(srdjan): if targets are native use their C_function to compare. | 214 // TODO(srdjan): if targets are native use their C_function to compare. |
| 206 static bool HasOneTarget(const ICData& ic_data) { | 215 static bool HasOneTarget(const ICData& ic_data) { |
| 207 ASSERT(ic_data.NumberOfChecks() > 0); | 216 ASSERT(ic_data.NumberOfChecks() > 0); |
| 208 const Function& first_target = Function::Handle(ic_data.GetTargetAt(0)); | 217 const Function& first_target = Function::Handle(ic_data.GetTargetAt(0)); |
| 209 Function& test_target = Function::Handle(); | 218 Function& test_target = Function::Handle(); |
| 210 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { | 219 for (intptr_t i = 1; i < ic_data.NumberOfChecks(); i++) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 if (!HasOneTarget(ic_data)) { | 259 if (!HasOneTarget(ic_data)) { |
| 251 // TODO(srdjan): Implement for mutiple targets. | 260 // TODO(srdjan): Implement for mutiple targets. |
| 252 return false; | 261 return false; |
| 253 } | 262 } |
| 254 // Inline implicit instance getter. | 263 // Inline implicit instance getter. |
| 255 const String& field_name = | 264 const String& field_name = |
| 256 String::Handle(Field::NameFromGetter(comp->function_name())); | 265 String::Handle(Field::NameFromGetter(comp->function_name())); |
| 257 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); | 266 const Field& field = Field::Handle(GetField(class_ids[0], field_name)); |
| 258 ASSERT(!field.IsNull()); | 267 ASSERT(!field.IsNull()); |
| 259 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( | 268 LoadInstanceFieldComp* load = new LoadInstanceFieldComp( |
| 260 field, comp->InputAt(0), comp); | 269 field, comp->ArgumentAt(0)->value(), comp); |
| 261 load->set_ic_data(comp->ic_data()); | 270 load->set_ic_data(comp->ic_data()); |
| 262 instr->set_computation(load); | 271 instr->set_computation(load); |
| 272 RemovePushArguments(comp); |
| 263 return true; | 273 return true; |
| 264 } | 274 } |
| 265 | 275 |
| 266 // Not an implicit getter. | 276 // Not an implicit getter. |
| 267 MethodRecognizer::Kind recognized_kind = | 277 MethodRecognizer::Kind recognized_kind = |
| 268 MethodRecognizer::RecognizeKind(target); | 278 MethodRecognizer::RecognizeKind(target); |
| 269 | 279 |
| 270 // VM objects length getter. | 280 // VM objects length getter. |
| 271 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || | 281 if ((recognized_kind == MethodRecognizer::kObjectArrayLength) || |
| 272 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || | 282 (recognized_kind == MethodRecognizer::kImmutableArrayLength) || |
| 273 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { | 283 (recognized_kind == MethodRecognizer::kGrowableArrayLength)) { |
| 274 if (!HasOneTarget(ic_data)) { | 284 if (!HasOneTarget(ic_data)) { |
| 275 // TODO(srdjan): Implement for mutiple targets. | 285 // TODO(srdjan): Implement for mutiple targets. |
| 276 return false; | 286 return false; |
| 277 } | 287 } |
| 278 intptr_t length_offset = -1; | 288 intptr_t length_offset = -1; |
| 279 switch (recognized_kind) { | 289 switch (recognized_kind) { |
| 280 case MethodRecognizer::kObjectArrayLength: | 290 case MethodRecognizer::kObjectArrayLength: |
| 281 case MethodRecognizer::kImmutableArrayLength: | 291 case MethodRecognizer::kImmutableArrayLength: |
| 282 length_offset = Array::length_offset(); | 292 length_offset = Array::length_offset(); |
| 283 break; | 293 break; |
| 284 case MethodRecognizer::kGrowableArrayLength: | 294 case MethodRecognizer::kGrowableArrayLength: |
| 285 length_offset = GrowableObjectArray::length_offset(); | 295 length_offset = GrowableObjectArray::length_offset(); |
| 286 break; | 296 break; |
| 287 default: | 297 default: |
| 288 UNREACHABLE(); | 298 UNREACHABLE(); |
| 289 } | 299 } |
| 290 LoadVMFieldComp* load = new LoadVMFieldComp( | 300 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 291 comp->InputAt(0), | 301 comp->ArgumentAt(0)->value(), |
| 292 length_offset, | 302 length_offset, |
| 293 Type::ZoneHandle(Type::IntInterface())); | 303 Type::ZoneHandle(Type::IntInterface())); |
| 294 load->set_original(comp); | 304 load->set_original(comp); |
| 295 load->set_ic_data(comp->ic_data()); | 305 load->set_ic_data(comp->ic_data()); |
| 296 instr->set_computation(load); | 306 instr->set_computation(load); |
| 307 RemovePushArguments(comp); |
| 297 return true; | 308 return true; |
| 298 } | 309 } |
| 299 | 310 |
| 300 if (recognized_kind == MethodRecognizer::kStringBaseLength) { | 311 if (recognized_kind == MethodRecognizer::kStringBaseLength) { |
| 301 if (!HasOneTarget(ic_data)) { | 312 if (!HasOneTarget(ic_data)) { |
| 302 // Target is not only StringBase_get_length. | 313 // Target is not only StringBase_get_length. |
| 303 return false; | 314 return false; |
| 304 } | 315 } |
| 305 ASSERT(HasOneTarget(ic_data)); | 316 ASSERT(HasOneTarget(ic_data)); |
| 306 LoadVMFieldComp* load = new LoadVMFieldComp( | 317 LoadVMFieldComp* load = new LoadVMFieldComp( |
| 307 comp->InputAt(0), | 318 comp->ArgumentAt(0)->value(), |
| 308 String::length_offset(), | 319 String::length_offset(), |
| 309 Type::ZoneHandle(Type::IntInterface())); | 320 Type::ZoneHandle(Type::IntInterface())); |
| 310 load->set_original(comp); | 321 load->set_original(comp); |
| 311 load->set_ic_data(comp->ic_data()); | 322 load->set_ic_data(comp->ic_data()); |
| 312 instr->set_computation(load); | 323 instr->set_computation(load); |
| 324 RemovePushArguments(comp); |
| 313 return true; | 325 return true; |
| 314 } | 326 } |
| 315 return false; | 327 return false; |
| 316 } | 328 } |
| 317 | 329 |
| 318 | 330 |
| 319 // Inline only simple, frequently called core library methods. | 331 // Inline only simple, frequently called core library methods. |
| 320 bool FlowGraphOptimizer::TryInlineInstanceMethod(BindInstr* instr, | 332 bool FlowGraphOptimizer::TryInlineInstanceMethod(BindInstr* instr, |
| 321 InstanceCallComp* comp) { | 333 InstanceCallComp* comp) { |
| 322 ASSERT(comp->HasICData()); | 334 ASSERT(comp->HasICData()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 337 } else if (recognized_kind == MethodRecognizer::kIntegerToDouble) { | 349 } else if (recognized_kind == MethodRecognizer::kIntegerToDouble) { |
| 338 from_kind = kSmi; | 350 from_kind = kSmi; |
| 339 } else { | 351 } else { |
| 340 return false; | 352 return false; |
| 341 } | 353 } |
| 342 | 354 |
| 343 if (class_ids[0] != from_kind) { | 355 if (class_ids[0] != from_kind) { |
| 344 return false; | 356 return false; |
| 345 } | 357 } |
| 346 ToDoubleComp* coerce = new ToDoubleComp( | 358 ToDoubleComp* coerce = new ToDoubleComp( |
| 347 comp->InputAt(0), from_kind, comp); | 359 comp->ArgumentAt(0)->value(), from_kind, comp); |
| 348 instr->set_computation(coerce); | 360 instr->set_computation(coerce); |
| 361 RemovePushArguments(comp); |
| 349 return true; | 362 return true; |
| 350 } | 363 } |
| 351 | 364 |
| 352 | 365 |
| 353 | 366 |
| 354 | 367 |
| 355 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp, | 368 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallComp* comp, |
| 356 BindInstr* instr) { | 369 BindInstr* instr) { |
| 357 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { | 370 if (comp->HasICData() && (comp->ic_data()->NumberOfChecks() > 0)) { |
| 358 const Token::Kind op_kind = comp->token_kind(); | 371 const Token::Kind op_kind = comp->token_kind(); |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 LocationSummary* locs = it.Current()->locs(); | 553 LocationSummary* locs = it.Current()->locs(); |
| 541 if ((locs != NULL) && locs->is_call()) { | 554 if ((locs != NULL) && locs->is_call()) { |
| 542 is_leaf_ = false; | 555 is_leaf_ = false; |
| 543 return; | 556 return; |
| 544 } | 557 } |
| 545 } | 558 } |
| 546 } | 559 } |
| 547 } | 560 } |
| 548 | 561 |
| 549 } // namespace dart | 562 } // namespace dart |
| OLD | NEW |