| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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/jit_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/branch_optimizer.h" | 8 #include "vm/branch_optimizer.h" |
| 9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| 11 #include "vm/cpu.h" | 11 #include "vm/cpu.h" |
| 12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/exceptions.h" | 13 #include "vm/exceptions.h" |
| 14 #include "vm/flow_graph_builder.h" | 14 #include "vm/flow_graph_builder.h" |
| 15 #include "vm/flow_graph_compiler.h" | 15 #include "vm/flow_graph_compiler.h" |
| (...skipping 24 matching lines...) Expand all Loading... |
| 40 return FlowGraphCompiler::SupportsUnboxedDoubles(); | 40 return FlowGraphCompiler::SupportsUnboxedDoubles(); |
| 41 } | 41 } |
| 42 | 42 |
| 43 | 43 |
| 44 static bool CanConvertUnboxedMintToDouble() { | 44 static bool CanConvertUnboxedMintToDouble() { |
| 45 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); | 45 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); |
| 46 } | 46 } |
| 47 | 47 |
| 48 | 48 |
| 49 // Optimize instance calls using ICData. | 49 // Optimize instance calls using ICData. |
| 50 void FlowGraphOptimizer::ApplyICData() { | 50 void JitOptimizer::ApplyICData() { |
| 51 VisitBlocks(); | 51 VisitBlocks(); |
| 52 } | 52 } |
| 53 | 53 |
| 54 | 54 |
| 55 // Optimize instance calls using cid. This is called after optimizer | 55 // Optimize instance calls using cid. This is called after optimizer |
| 56 // converted instance calls to instructions. Any remaining | 56 // converted instance calls to instructions. Any remaining |
| 57 // instance calls are either megamorphic calls, cannot be optimized or | 57 // instance calls are either megamorphic calls, cannot be optimized or |
| 58 // have no runtime type feedback collected. | 58 // have no runtime type feedback collected. |
| 59 // Attempts to convert an instance call (IC call) using propagated class-ids, | 59 // Attempts to convert an instance call (IC call) using propagated class-ids, |
| 60 // e.g., receiver class id, guarded-cid, or by guessing cid-s. | 60 // e.g., receiver class id, guarded-cid, or by guessing cid-s. |
| 61 void FlowGraphOptimizer::ApplyClassIds() { | 61 void JitOptimizer::ApplyClassIds() { |
| 62 ASSERT(current_iterator_ == NULL); | 62 ASSERT(current_iterator_ == NULL); |
| 63 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 63 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 64 !block_it.Done(); | 64 !block_it.Done(); |
| 65 block_it.Advance()) { | 65 block_it.Advance()) { |
| 66 ForwardInstructionIterator it(block_it.Current()); | 66 ForwardInstructionIterator it(block_it.Current()); |
| 67 current_iterator_ = ⁢ | 67 current_iterator_ = ⁢ |
| 68 for (; !it.Done(); it.Advance()) { | 68 for (; !it.Done(); it.Advance()) { |
| 69 Instruction* instr = it.Current(); | 69 Instruction* instr = it.Current(); |
| 70 if (instr->IsInstanceCall()) { | 70 if (instr->IsInstanceCall()) { |
| 71 InstanceCallInstr* call = instr->AsInstanceCall(); | 71 InstanceCallInstr* call = instr->AsInstanceCall(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 82 } | 82 } |
| 83 } | 83 } |
| 84 | 84 |
| 85 | 85 |
| 86 // TODO(srdjan): Test/support other number types as well. | 86 // TODO(srdjan): Test/support other number types as well. |
| 87 static bool IsNumberCid(intptr_t cid) { | 87 static bool IsNumberCid(intptr_t cid) { |
| 88 return (cid == kSmiCid) || (cid == kDoubleCid); | 88 return (cid == kSmiCid) || (cid == kDoubleCid); |
| 89 } | 89 } |
| 90 | 90 |
| 91 | 91 |
| 92 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { | 92 bool JitOptimizer::TryCreateICData(InstanceCallInstr* call) { |
| 93 ASSERT(call->HasICData()); | 93 ASSERT(call->HasICData()); |
| 94 if (call->ic_data()->NumberOfUsedChecks() > 0) { | 94 if (call->ic_data()->NumberOfUsedChecks() > 0) { |
| 95 // This occurs when an instance call has too many checks, will be converted | 95 // This occurs when an instance call has too many checks, will be converted |
| 96 // to megamorphic call. | 96 // to megamorphic call. |
| 97 return false; | 97 return false; |
| 98 } | 98 } |
| 99 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); | 99 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); |
| 100 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); | 100 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); |
| 101 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { | 101 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { |
| 102 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); | 102 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 call->set_ic_data(&ic_data); | 191 call->set_ic_data(&ic_data); |
| 192 return true; | 192 return true; |
| 193 } | 193 } |
| 194 } | 194 } |
| 195 } | 195 } |
| 196 | 196 |
| 197 return false; | 197 return false; |
| 198 } | 198 } |
| 199 | 199 |
| 200 | 200 |
| 201 const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data, | 201 const ICData& JitOptimizer::TrySpecializeICData(const ICData& ic_data, |
| 202 intptr_t cid) { | 202 intptr_t cid) { |
| 203 ASSERT(ic_data.NumArgsTested() == 1); | 203 ASSERT(ic_data.NumArgsTested() == 1); |
| 204 | 204 |
| 205 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { | 205 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { |
| 206 return ic_data; // Nothing to do | 206 return ic_data; // Nothing to do |
| 207 } | 207 } |
| 208 | 208 |
| 209 const Function& function = | 209 const Function& function = |
| 210 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid)); | 210 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid)); |
| 211 // TODO(fschneider): Try looking up the function on the class if it is | 211 // TODO(fschneider): Try looking up the function on the class if it is |
| 212 // not found in the ICData. | 212 // not found in the ICData. |
| 213 if (!function.IsNull()) { | 213 if (!function.IsNull()) { |
| 214 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New( | 214 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New( |
| 215 Function::Handle(Z, ic_data.Owner()), | 215 Function::Handle(Z, ic_data.Owner()), |
| 216 String::Handle(Z, ic_data.target_name()), | 216 String::Handle(Z, ic_data.target_name()), |
| 217 Object::empty_array(), // Dummy argument descriptor. | 217 Object::empty_array(), // Dummy argument descriptor. |
| 218 ic_data.deopt_id(), | 218 ic_data.deopt_id(), |
| 219 ic_data.NumArgsTested())); | 219 ic_data.NumArgsTested())); |
| 220 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); | 220 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); |
| 221 new_ic_data.AddReceiverCheck(cid, function); | 221 new_ic_data.AddReceiverCheck(cid, function); |
| 222 return new_ic_data; | 222 return new_ic_data; |
| 223 } | 223 } |
| 224 | 224 |
| 225 return ic_data; | 225 return ic_data; |
| 226 } | 226 } |
| 227 | 227 |
| 228 | 228 |
| 229 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( | 229 void JitOptimizer::SpecializePolymorphicInstanceCall( |
| 230 PolymorphicInstanceCallInstr* call) { | 230 PolymorphicInstanceCallInstr* call) { |
| 231 if (!FLAG_polymorphic_with_deopt) { | 231 if (!FLAG_polymorphic_with_deopt) { |
| 232 // Specialization adds receiver checks which can lead to deoptimization. | 232 // Specialization adds receiver checks which can lead to deoptimization. |
| 233 return; | 233 return; |
| 234 } | 234 } |
| 235 if (!call->with_checks()) { | 235 if (!call->with_checks()) { |
| 236 return; // Already specialized. | 236 return; // Already specialized. |
| 237 } | 237 } |
| 238 | 238 |
| 239 const intptr_t receiver_cid = | 239 const intptr_t receiver_cid = |
| (...skipping 28 matching lines...) Expand all Loading... |
| 268 | 268 |
| 269 static bool IsPositiveOrZeroSmiConst(Definition* d) { | 269 static bool IsPositiveOrZeroSmiConst(Definition* d) { |
| 270 ConstantInstr* const_instr = d->AsConstant(); | 270 ConstantInstr* const_instr = d->AsConstant(); |
| 271 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { | 271 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { |
| 272 return Smi::Cast(const_instr->value()).Value() >= 0; | 272 return Smi::Cast(const_instr->value()).Value() >= 0; |
| 273 } | 273 } |
| 274 return false; | 274 return false; |
| 275 } | 275 } |
| 276 | 276 |
| 277 | 277 |
| 278 void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp( | 278 void JitOptimizer::OptimizeLeftShiftBitAndSmiOp( |
| 279 Definition* bit_and_instr, | 279 Definition* bit_and_instr, |
| 280 Definition* left_instr, | 280 Definition* left_instr, |
| 281 Definition* right_instr) { | 281 Definition* right_instr) { |
| 282 ASSERT(bit_and_instr != NULL); | 282 ASSERT(bit_and_instr != NULL); |
| 283 ASSERT((left_instr != NULL) && (right_instr != NULL)); | 283 ASSERT((left_instr != NULL) && (right_instr != NULL)); |
| 284 | 284 |
| 285 // Check for pattern, smi_shift_left must be single-use. | 285 // Check for pattern, smi_shift_left must be single-use. |
| 286 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); | 286 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); |
| 287 if (!is_positive_or_zero) { | 287 if (!is_positive_or_zero) { |
| 288 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr); | 288 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 306 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr( | 306 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr( |
| 307 Token::kBIT_AND, | 307 Token::kBIT_AND, |
| 308 new(Z) Value(left_instr), | 308 new(Z) Value(left_instr), |
| 309 new(Z) Value(right_instr), | 309 new(Z) Value(right_instr), |
| 310 Thread::kNoDeoptId); // BIT_AND cannot deoptimize. | 310 Thread::kNoDeoptId); // BIT_AND cannot deoptimize. |
| 311 bit_and_instr->ReplaceWith(smi_op, current_iterator()); | 311 bit_and_instr->ReplaceWith(smi_op, current_iterator()); |
| 312 } | 312 } |
| 313 } | 313 } |
| 314 | 314 |
| 315 | 315 |
| 316 void FlowGraphOptimizer::AppendExtractNthOutputForMerged(Definition* instr, | 316 void JitOptimizer::AppendExtractNthOutputForMerged(Definition* instr, |
| 317 intptr_t index, | 317 intptr_t index, |
| 318 Representation rep, | 318 Representation rep, |
| 319 intptr_t cid) { | 319 intptr_t cid) { |
| 320 ExtractNthOutputInstr* extract = | 320 ExtractNthOutputInstr* extract = |
| 321 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid); | 321 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid); |
| 322 instr->ReplaceUsesWith(extract); | 322 instr->ReplaceUsesWith(extract); |
| 323 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue); | 323 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue); |
| 324 } | 324 } |
| 325 | 325 |
| 326 | 326 |
| 327 // Dart: | 327 // Dart: |
| 328 // var x = d % 10; | 328 // var x = d % 10; |
| 329 // var y = d ~/ 10; | 329 // var y = d ~/ 10; |
| 330 // var z = x + y; | 330 // var z = x + y; |
| 331 // | 331 // |
| 332 // IL: | 332 // IL: |
| 333 // v4 <- %(v2, v3) | 333 // v4 <- %(v2, v3) |
| 334 // v5 <- ~/(v2, v3) | 334 // v5 <- ~/(v2, v3) |
| 335 // v6 <- +(v4, v5) | 335 // v6 <- +(v4, v5) |
| 336 // | 336 // |
| 337 // IL optimized: | 337 // IL optimized: |
| 338 // v4 <- DIVMOD(v2, v3); | 338 // v4 <- DIVMOD(v2, v3); |
| 339 // v5 <- LoadIndexed(v4, 0); // ~/ result | 339 // v5 <- LoadIndexed(v4, 0); // ~/ result |
| 340 // v6 <- LoadIndexed(v4, 1); // % result | 340 // v6 <- LoadIndexed(v4, 1); // % result |
| 341 // v7 <- +(v5, v6) | 341 // v7 <- +(v5, v6) |
| 342 // Because of the environment it is important that merged instruction replaces | 342 // Because of the environment it is important that merged instruction replaces |
| 343 // first original instruction encountered. | 343 // first original instruction encountered. |
| 344 void FlowGraphOptimizer::TryMergeTruncDivMod( | 344 void JitOptimizer::TryMergeTruncDivMod( |
| 345 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { | 345 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { |
| 346 if (merge_candidates->length() < 2) { | 346 if (merge_candidates->length() < 2) { |
| 347 // Need at least a TRUNCDIV and a MOD. | 347 // Need at least a TRUNCDIV and a MOD. |
| 348 return; | 348 return; |
| 349 } | 349 } |
| 350 for (intptr_t i = 0; i < merge_candidates->length(); i++) { | 350 for (intptr_t i = 0; i < merge_candidates->length(); i++) { |
| 351 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; | 351 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; |
| 352 if (curr_instr == NULL) { | 352 if (curr_instr == NULL) { |
| 353 // Instruction was merged already. | 353 // Instruction was merged already. |
| 354 continue; | 354 continue; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 // more candidates are possible. | 395 // more candidates are possible. |
| 396 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod. | 396 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod. |
| 397 break; | 397 break; |
| 398 } | 398 } |
| 399 } | 399 } |
| 400 } | 400 } |
| 401 } | 401 } |
| 402 | 402 |
| 403 | 403 |
| 404 // Tries to merge MathUnary operations, in this case sinus and cosinus. | 404 // Tries to merge MathUnary operations, in this case sinus and cosinus. |
| 405 void FlowGraphOptimizer::TryMergeMathUnary( | 405 void JitOptimizer::TryMergeMathUnary( |
| 406 GrowableArray<MathUnaryInstr*>* merge_candidates) { | 406 GrowableArray<MathUnaryInstr*>* merge_candidates) { |
| 407 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() || | 407 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() || |
| 408 !FLAG_merge_sin_cos) { | 408 !FLAG_merge_sin_cos) { |
| 409 return; | 409 return; |
| 410 } | 410 } |
| 411 if (merge_candidates->length() < 2) { | 411 if (merge_candidates->length() < 2) { |
| 412 // Need at least a SIN and a COS. | 412 // Need at least a SIN and a COS. |
| 413 return; | 413 return; |
| 414 } | 414 } |
| 415 for (intptr_t i = 0; i < merge_candidates->length(); i++) { | 415 for (intptr_t i = 0; i < merge_candidates->length(); i++) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 456 break; | 456 break; |
| 457 } | 457 } |
| 458 } | 458 } |
| 459 } | 459 } |
| 460 } | 460 } |
| 461 | 461 |
| 462 | 462 |
| 463 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the | 463 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the |
| 464 // shift can be a truncating Smi shift-left and result is always Smi. | 464 // shift can be a truncating Smi shift-left and result is always Smi. |
| 465 // Merging occurs only per basic-block. | 465 // Merging occurs only per basic-block. |
| 466 void FlowGraphOptimizer::TryOptimizePatterns() { | 466 void JitOptimizer::TryOptimizePatterns() { |
| 467 if (!FLAG_truncating_left_shift) return; | 467 if (!FLAG_truncating_left_shift) return; |
| 468 ASSERT(current_iterator_ == NULL); | 468 ASSERT(current_iterator_ == NULL); |
| 469 GrowableArray<BinarySmiOpInstr*> div_mod_merge; | 469 GrowableArray<BinarySmiOpInstr*> div_mod_merge; |
| 470 GrowableArray<MathUnaryInstr*> sin_cos_merge; | 470 GrowableArray<MathUnaryInstr*> sin_cos_merge; |
| 471 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 471 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
| 472 !block_it.Done(); | 472 !block_it.Done(); |
| 473 block_it.Advance()) { | 473 block_it.Advance()) { |
| 474 // Merging only per basic-block. | 474 // Merging only per basic-block. |
| 475 div_mod_merge.Clear(); | 475 div_mod_merge.Clear(); |
| 476 sin_cos_merge.Clear(); | 476 sin_cos_merge.Clear(); |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 // Unboxed double operation can't handle case of two smis. | 642 // Unboxed double operation can't handle case of two smis. |
| 643 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | 643 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
| 644 return false; | 644 return false; |
| 645 } | 645 } |
| 646 | 646 |
| 647 // Check that it have seen only smis and doubles. | 647 // Check that it have seen only smis and doubles. |
| 648 return HasTwoDoubleOrSmi(ic_data); | 648 return HasTwoDoubleOrSmi(ic_data); |
| 649 } | 649 } |
| 650 | 650 |
| 651 | 651 |
| 652 void FlowGraphOptimizer::ReplaceCall(Definition* call, | 652 void JitOptimizer::ReplaceCall(Definition* call, |
| 653 Definition* replacement) { | 653 Definition* replacement) { |
| 654 // Remove the original push arguments. | 654 // Remove the original push arguments. |
| 655 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 655 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 656 PushArgumentInstr* push = call->PushArgumentAt(i); | 656 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 657 push->ReplaceUsesWith(push->value()->definition()); | 657 push->ReplaceUsesWith(push->value()->definition()); |
| 658 push->RemoveFromGraph(); | 658 push->RemoveFromGraph(); |
| 659 } | 659 } |
| 660 call->ReplaceWith(replacement, current_iterator()); | 660 call->ReplaceWith(replacement, current_iterator()); |
| 661 } | 661 } |
| 662 | 662 |
| 663 | 663 |
| 664 void FlowGraphOptimizer::AddCheckSmi(Definition* to_check, | 664 void JitOptimizer::AddCheckSmi(Definition* to_check, |
| 665 intptr_t deopt_id, | 665 intptr_t deopt_id, |
| 666 Environment* deopt_environment, | 666 Environment* deopt_environment, |
| 667 Instruction* insert_before) { | 667 Instruction* insert_before) { |
| 668 if (to_check->Type()->ToCid() != kSmiCid) { | 668 if (to_check->Type()->ToCid() != kSmiCid) { |
| 669 InsertBefore(insert_before, | 669 InsertBefore(insert_before, |
| 670 new(Z) CheckSmiInstr(new(Z) Value(to_check), | 670 new(Z) CheckSmiInstr(new(Z) Value(to_check), |
| 671 deopt_id, | 671 deopt_id, |
| 672 insert_before->token_pos()), | 672 insert_before->token_pos()), |
| 673 deopt_environment, | 673 deopt_environment, |
| 674 FlowGraph::kEffect); | 674 FlowGraph::kEffect); |
| 675 } | 675 } |
| 676 } | 676 } |
| 677 | 677 |
| 678 | 678 |
| 679 Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check, | 679 Instruction* JitOptimizer::GetCheckClass(Definition* to_check, |
| 680 const ICData& unary_checks, | 680 const ICData& unary_checks, |
| 681 intptr_t deopt_id, | 681 intptr_t deopt_id, |
| 682 TokenPosition token_pos) { | 682 TokenPosition token_pos) { |
| 683 if ((unary_checks.NumberOfUsedChecks() == 1) && | 683 if ((unary_checks.NumberOfUsedChecks() == 1) && |
| 684 unary_checks.HasReceiverClassId(kSmiCid)) { | 684 unary_checks.HasReceiverClassId(kSmiCid)) { |
| 685 return new(Z) CheckSmiInstr(new(Z) Value(to_check), | 685 return new(Z) CheckSmiInstr(new(Z) Value(to_check), |
| 686 deopt_id, | 686 deopt_id, |
| 687 token_pos); | 687 token_pos); |
| 688 } | 688 } |
| 689 return new(Z) CheckClassInstr( | 689 return new(Z) CheckClassInstr( |
| 690 new(Z) Value(to_check), deopt_id, unary_checks, token_pos); | 690 new(Z) Value(to_check), deopt_id, unary_checks, token_pos); |
| 691 } | 691 } |
| 692 | 692 |
| 693 | 693 |
| 694 void FlowGraphOptimizer::AddCheckClass(Definition* to_check, | 694 void JitOptimizer::AddCheckClass(Definition* to_check, |
| 695 const ICData& unary_checks, | 695 const ICData& unary_checks, |
| 696 intptr_t deopt_id, | 696 intptr_t deopt_id, |
| 697 Environment* deopt_environment, | 697 Environment* deopt_environment, |
| 698 Instruction* insert_before) { | 698 Instruction* insert_before) { |
| 699 // Type propagation has not run yet, we cannot eliminate the check. | 699 // Type propagation has not run yet, we cannot eliminate the check. |
| 700 Instruction* check = GetCheckClass( | 700 Instruction* check = GetCheckClass( |
| 701 to_check, unary_checks, deopt_id, insert_before->token_pos()); | 701 to_check, unary_checks, deopt_id, insert_before->token_pos()); |
| 702 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); | 702 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); |
| 703 } | 703 } |
| 704 | 704 |
| 705 | 705 |
| 706 void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) { | 706 void JitOptimizer::AddReceiverCheck(InstanceCallInstr* call) { |
| 707 AddCheckClass(call->ArgumentAt(0), | 707 AddCheckClass(call->ArgumentAt(0), |
| 708 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), | 708 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), |
| 709 call->deopt_id(), | 709 call->deopt_id(), |
| 710 call->env(), | 710 call->env(), |
| 711 call); | 711 call); |
| 712 } | 712 } |
| 713 | 713 |
| 714 | 714 |
| 715 static bool ArgIsAlways(intptr_t cid, | 715 static bool ArgIsAlways(intptr_t cid, |
| 716 const ICData& ic_data, | 716 const ICData& ic_data, |
| 717 intptr_t arg_number) { | 717 intptr_t arg_number) { |
| 718 ASSERT(ic_data.NumArgsTested() > arg_number); | 718 ASSERT(ic_data.NumArgsTested() > arg_number); |
| 719 if (ic_data.NumberOfUsedChecks() == 0) { | 719 if (ic_data.NumberOfUsedChecks() == 0) { |
| 720 return false; | 720 return false; |
| 721 } | 721 } |
| 722 const intptr_t num_checks = ic_data.NumberOfChecks(); | 722 const intptr_t num_checks = ic_data.NumberOfChecks(); |
| 723 for (intptr_t i = 0; i < num_checks; i++) { | 723 for (intptr_t i = 0; i < num_checks; i++) { |
| 724 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { | 724 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { |
| 725 return false; | 725 return false; |
| 726 } | 726 } |
| 727 } | 727 } |
| 728 return true; | 728 return true; |
| 729 } | 729 } |
| 730 | 730 |
| 731 | 731 |
| 732 bool FlowGraphOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { | 732 bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { |
| 733 // Check for monomorphic IC data. | 733 // Check for monomorphic IC data. |
| 734 if (!call->HasICData()) return false; | 734 if (!call->HasICData()) return false; |
| 735 const ICData& ic_data = | 735 const ICData& ic_data = |
| 736 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); | 736 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); |
| 737 if (ic_data.NumberOfChecks() != 1) { | 737 if (ic_data.NumberOfChecks() != 1) { |
| 738 return false; | 738 return false; |
| 739 } | 739 } |
| 740 return TryReplaceInstanceCallWithInline(call); | 740 return TryReplaceInstanceCallWithInline(call); |
| 741 } | 741 } |
| 742 | 742 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 754 } else { | 754 } else { |
| 755 return d->IsStringFromCharCode(); | 755 return d->IsStringFromCharCode(); |
| 756 } | 756 } |
| 757 } | 757 } |
| 758 | 758 |
| 759 | 759 |
| 760 // Returns true if the string comparison was converted into char-code | 760 // Returns true if the string comparison was converted into char-code |
| 761 // comparison. Conversion is only possible for strings of length one. | 761 // comparison. Conversion is only possible for strings of length one. |
| 762 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. | 762 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. |
| 763 // TODO(srdjan): Expand for two-byte and external strings. | 763 // TODO(srdjan): Expand for two-byte and external strings. |
| 764 bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, | 764 bool JitOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, |
| 765 Token::Kind op_kind) { | 765 Token::Kind op_kind) { |
| 766 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); | 766 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); |
| 767 // Check that left and right are length one strings (either string constants | 767 // Check that left and right are length one strings (either string constants |
| 768 // or results of string-from-char-code. | 768 // or results of string-from-char-code. |
| 769 Definition* left = call->ArgumentAt(0); | 769 Definition* left = call->ArgumentAt(0); |
| 770 Definition* right = call->ArgumentAt(1); | 770 Definition* right = call->ArgumentAt(1); |
| 771 Value* left_val = NULL; | 771 Value* left_val = NULL; |
| 772 Definition* to_remove_left = NULL; | 772 Definition* to_remove_left = NULL; |
| 773 if (IsLengthOneString(right)) { | 773 if (IsLengthOneString(right)) { |
| 774 // Swap, since we know that both arguments are strings | 774 // Swap, since we know that both arguments are strings |
| 775 Definition* temp = left; | 775 Definition* temp = left; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 841 to_remove_right->RemoveFromGraph(); | 841 to_remove_right->RemoveFromGraph(); |
| 842 } | 842 } |
| 843 return true; | 843 return true; |
| 844 } | 844 } |
| 845 return false; | 845 return false; |
| 846 } | 846 } |
| 847 | 847 |
| 848 | 848 |
| 849 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 849 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
| 850 | 850 |
| 851 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 851 bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
| 852 Token::Kind op_kind) { | 852 Token::Kind op_kind) { |
| 853 const ICData& ic_data = *call->ic_data(); | 853 const ICData& ic_data = *call->ic_data(); |
| 854 ASSERT(ic_data.NumArgsTested() == 2); | 854 ASSERT(ic_data.NumArgsTested() == 2); |
| 855 | 855 |
| 856 ASSERT(call->ArgumentCount() == 2); | 856 ASSERT(call->ArgumentCount() == 2); |
| 857 Definition* left = call->ArgumentAt(0); | 857 Definition* left = call->ArgumentAt(0); |
| 858 Definition* right = call->ArgumentAt(1); | 858 Definition* right = call->ArgumentAt(1); |
| 859 | 859 |
| 860 intptr_t cid = kIllegalCid; | 860 intptr_t cid = kIllegalCid; |
| 861 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { | 861 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
| 862 if (TryStringLengthOneEquality(call, op_kind)) { | 862 if (TryStringLengthOneEquality(call, op_kind)) { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 950 op_kind, | 950 op_kind, |
| 951 new(Z) Value(left), | 951 new(Z) Value(left), |
| 952 new(Z) Value(right), | 952 new(Z) Value(right), |
| 953 cid, | 953 cid, |
| 954 call->deopt_id()); | 954 call->deopt_id()); |
| 955 ReplaceCall(call, comp); | 955 ReplaceCall(call, comp); |
| 956 return true; | 956 return true; |
| 957 } | 957 } |
| 958 | 958 |
| 959 | 959 |
| 960 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 960 bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
| 961 Token::Kind op_kind) { | 961 Token::Kind op_kind) { |
| 962 const ICData& ic_data = *call->ic_data(); | 962 const ICData& ic_data = *call->ic_data(); |
| 963 ASSERT(ic_data.NumArgsTested() == 2); | 963 ASSERT(ic_data.NumArgsTested() == 2); |
| 964 | 964 |
| 965 ASSERT(call->ArgumentCount() == 2); | 965 ASSERT(call->ArgumentCount() == 2); |
| 966 Definition* left = call->ArgumentAt(0); | 966 Definition* left = call->ArgumentAt(0); |
| 967 Definition* right = call->ArgumentAt(1); | 967 Definition* right = call->ArgumentAt(1); |
| 968 | 968 |
| 969 intptr_t cid = kIllegalCid; | 969 intptr_t cid = kIllegalCid; |
| 970 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 970 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 971 InsertBefore(call, | 971 InsertBefore(call, |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1012 op_kind, | 1012 op_kind, |
| 1013 new(Z) Value(left), | 1013 new(Z) Value(left), |
| 1014 new(Z) Value(right), | 1014 new(Z) Value(right), |
| 1015 cid, | 1015 cid, |
| 1016 call->deopt_id()); | 1016 call->deopt_id()); |
| 1017 ReplaceCall(call, comp); | 1017 ReplaceCall(call, comp); |
| 1018 return true; | 1018 return true; |
| 1019 } | 1019 } |
| 1020 | 1020 |
| 1021 | 1021 |
| 1022 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 1022 bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
| 1023 Token::Kind op_kind) { | 1023 Token::Kind op_kind) { |
| 1024 intptr_t operands_type = kIllegalCid; | 1024 intptr_t operands_type = kIllegalCid; |
| 1025 ASSERT(call->HasICData()); | 1025 ASSERT(call->HasICData()); |
| 1026 const ICData& ic_data = *call->ic_data(); | 1026 const ICData& ic_data = *call->ic_data(); |
| 1027 switch (op_kind) { | 1027 switch (op_kind) { |
| 1028 case Token::kADD: | 1028 case Token::kADD: |
| 1029 case Token::kSUB: | 1029 case Token::kSUB: |
| 1030 case Token::kMUL: | 1030 case Token::kMUL: |
| 1031 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1031 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
| 1032 // Don't generate smi code if the IC data is marked because | 1032 // Don't generate smi code if the IC data is marked because |
| 1033 // of an overflow. | 1033 // of an overflow. |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1221 op_kind, | 1221 op_kind, |
| 1222 new(Z) Value(left), | 1222 new(Z) Value(left), |
| 1223 new(Z) Value(right), | 1223 new(Z) Value(right), |
| 1224 call->deopt_id()); | 1224 call->deopt_id()); |
| 1225 ReplaceCall(call, bin_op); | 1225 ReplaceCall(call, bin_op); |
| 1226 } | 1226 } |
| 1227 return true; | 1227 return true; |
| 1228 } | 1228 } |
| 1229 | 1229 |
| 1230 | 1230 |
| 1231 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, | 1231 bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, |
| 1232 Token::Kind op_kind) { | 1232 Token::Kind op_kind) { |
| 1233 ASSERT(call->ArgumentCount() == 1); | 1233 ASSERT(call->ArgumentCount() == 1); |
| 1234 Definition* input = call->ArgumentAt(0); | 1234 Definition* input = call->ArgumentAt(0); |
| 1235 Definition* unary_op = NULL; | 1235 Definition* unary_op = NULL; |
| 1236 if (HasOnlyOneSmi(*call->ic_data())) { | 1236 if (HasOnlyOneSmi(*call->ic_data())) { |
| 1237 InsertBefore(call, | 1237 InsertBefore(call, |
| 1238 new(Z) CheckSmiInstr(new(Z) Value(input), | 1238 new(Z) CheckSmiInstr(new(Z) Value(input), |
| 1239 call->deopt_id(), | 1239 call->deopt_id(), |
| 1240 call->token_pos()), | 1240 call->token_pos()), |
| 1241 call->env(), | 1241 call->env(), |
| 1242 FlowGraph::kEffect); | 1242 FlowGraph::kEffect); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1256 } else { | 1256 } else { |
| 1257 return false; | 1257 return false; |
| 1258 } | 1258 } |
| 1259 ASSERT(unary_op != NULL); | 1259 ASSERT(unary_op != NULL); |
| 1260 ReplaceCall(call, unary_op); | 1260 ReplaceCall(call, unary_op); |
| 1261 return true; | 1261 return true; |
| 1262 } | 1262 } |
| 1263 | 1263 |
| 1264 | 1264 |
| 1265 // Using field class | 1265 // Using field class |
| 1266 RawField* FlowGraphOptimizer::GetField(intptr_t class_id, | 1266 RawField* JitOptimizer::GetField(intptr_t class_id, |
| 1267 const String& field_name) { | 1267 const String& field_name) { |
| 1268 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); | 1268 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); |
| 1269 Field& field = Field::Handle(Z); | 1269 Field& field = Field::Handle(Z); |
| 1270 while (!cls.IsNull()) { | 1270 while (!cls.IsNull()) { |
| 1271 field = cls.LookupInstanceField(field_name); | 1271 field = cls.LookupInstanceField(field_name); |
| 1272 if (!field.IsNull()) { | 1272 if (!field.IsNull()) { |
| 1273 return field.raw(); | 1273 return field.raw(); |
| 1274 } | 1274 } |
| 1275 cls = cls.SuperClass(); | 1275 cls = cls.SuperClass(); |
| 1276 } | 1276 } |
| 1277 return Field::null(); | 1277 return Field::null(); |
| 1278 } | 1278 } |
| 1279 | 1279 |
| 1280 | 1280 |
| 1281 // Use CHA to determine if the call needs a class check: if the callee's | 1281 // Use CHA to determine if the call needs a class check: if the callee's |
| 1282 // receiver is the same as the caller's receiver and there are no overriden | 1282 // receiver is the same as the caller's receiver and there are no overriden |
| 1283 // callee functions, then no class check is needed. | 1283 // callee functions, then no class check is needed. |
| 1284 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( | 1284 bool JitOptimizer::InstanceCallNeedsClassCheck( |
| 1285 InstanceCallInstr* call, RawFunction::Kind kind) const { | 1285 InstanceCallInstr* call, RawFunction::Kind kind) const { |
| 1286 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { | 1286 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { |
| 1287 // Even if class or function are private, lazy class finalization | 1287 // Even if class or function are private, lazy class finalization |
| 1288 // may later add overriding methods. | 1288 // may later add overriding methods. |
| 1289 return true; | 1289 return true; |
| 1290 } | 1290 } |
| 1291 Definition* callee_receiver = call->ArgumentAt(0); | 1291 Definition* callee_receiver = call->ArgumentAt(0); |
| 1292 ASSERT(callee_receiver != NULL); | 1292 ASSERT(callee_receiver != NULL); |
| 1293 const Function& function = flow_graph_->function(); | 1293 const Function& function = flow_graph_->function(); |
| 1294 if (function.IsDynamicFunction() && | 1294 if (function.IsDynamicFunction() && |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1305 name.ToCString(), cls.ToCString()); | 1305 name.ToCString(), cls.ToCString()); |
| 1306 } | 1306 } |
| 1307 thread()->cha()->AddToLeafClasses(cls); | 1307 thread()->cha()->AddToLeafClasses(cls); |
| 1308 return false; | 1308 return false; |
| 1309 } | 1309 } |
| 1310 } | 1310 } |
| 1311 return true; | 1311 return true; |
| 1312 } | 1312 } |
| 1313 | 1313 |
| 1314 | 1314 |
| 1315 bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call, | 1315 bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { |
| 1316 bool allow_check) { | |
| 1317 ASSERT(call->HasICData()); | 1316 ASSERT(call->HasICData()); |
| 1318 const ICData& ic_data = *call->ic_data(); | 1317 const ICData& ic_data = *call->ic_data(); |
| 1319 ASSERT(ic_data.HasOneTarget()); | 1318 ASSERT(ic_data.HasOneTarget()); |
| 1320 GrowableArray<intptr_t> class_ids; | 1319 GrowableArray<intptr_t> class_ids; |
| 1321 ic_data.GetClassIdsAt(0, &class_ids); | 1320 ic_data.GetClassIdsAt(0, &class_ids); |
| 1322 ASSERT(class_ids.length() == 1); | 1321 ASSERT(class_ids.length() == 1); |
| 1323 // Inline implicit instance getter. | 1322 // Inline implicit instance getter. |
| 1324 const String& field_name = | 1323 const String& field_name = |
| 1325 String::Handle(Z, Field::NameFromGetter(call->function_name())); | 1324 String::Handle(Z, Field::NameFromGetter(call->function_name())); |
| 1326 const Field& field = | 1325 const Field& field = |
| 1327 Field::ZoneHandle(Z, GetField(class_ids[0], field_name)); | 1326 Field::ZoneHandle(Z, GetField(class_ids[0], field_name)); |
| 1328 ASSERT(!field.IsNull()); | 1327 ASSERT(!field.IsNull()); |
| 1329 | 1328 |
| 1330 if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) { | 1329 if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) { |
| 1331 if (!allow_check) { | |
| 1332 return false; | |
| 1333 } | |
| 1334 AddReceiverCheck(call); | 1330 AddReceiverCheck(call); |
| 1335 } | 1331 } |
| 1336 LoadFieldInstr* load = new(Z) LoadFieldInstr( | 1332 LoadFieldInstr* load = new(Z) LoadFieldInstr( |
| 1337 new(Z) Value(call->ArgumentAt(0)), | 1333 new(Z) Value(call->ArgumentAt(0)), |
| 1338 &field, | 1334 &field, |
| 1339 AbstractType::ZoneHandle(Z, field.type()), | 1335 AbstractType::ZoneHandle(Z, field.type()), |
| 1340 call->token_pos()); | 1336 call->token_pos()); |
| 1341 load->set_is_immutable(field.is_final()); | 1337 load->set_is_immutable(field.is_final()); |
| 1342 if (field.guarded_cid() != kIllegalCid) { | 1338 if (field.guarded_cid() != kIllegalCid) { |
| 1343 if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) { | 1339 if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1356 for (Value::Iterator it(load->input_use_list()); | 1352 for (Value::Iterator it(load->input_use_list()); |
| 1357 !it.Done(); | 1353 !it.Done(); |
| 1358 it.Advance()) { | 1354 it.Advance()) { |
| 1359 it.Current()->SetReachingType(NULL); | 1355 it.Current()->SetReachingType(NULL); |
| 1360 } | 1356 } |
| 1361 } | 1357 } |
| 1362 return true; | 1358 return true; |
| 1363 } | 1359 } |
| 1364 | 1360 |
| 1365 | 1361 |
| 1366 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, | 1362 bool JitOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, |
| 1367 MethodRecognizer::Kind getter) { | 1363 MethodRecognizer::Kind getter) { |
| 1368 if (!ShouldInlineSimd()) { | 1364 if (!ShouldInlineSimd()) { |
| 1369 return false; | 1365 return false; |
| 1370 } | 1366 } |
| 1371 AddCheckClass(call->ArgumentAt(0), | 1367 AddCheckClass(call->ArgumentAt(0), |
| 1372 ICData::ZoneHandle( | 1368 ICData::ZoneHandle( |
| 1373 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1369 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1374 call->deopt_id(), | 1370 call->deopt_id(), |
| 1375 call->env(), | 1371 call->env(), |
| 1376 call); | 1372 call); |
| 1377 intptr_t mask = 0; | 1373 intptr_t mask = 0; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1431 mask, | 1427 mask, |
| 1432 call->deopt_id()); | 1428 call->deopt_id()); |
| 1433 ReplaceCall(call, instr); | 1429 ReplaceCall(call, instr); |
| 1434 return true; | 1430 return true; |
| 1435 } | 1431 } |
| 1436 UNREACHABLE(); | 1432 UNREACHABLE(); |
| 1437 return false; | 1433 return false; |
| 1438 } | 1434 } |
| 1439 | 1435 |
| 1440 | 1436 |
| 1441 bool FlowGraphOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call, | 1437 bool JitOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call, |
| 1442 MethodRecognizer::Kind getter) { | 1438 MethodRecognizer::Kind getter) { |
| 1443 if (!ShouldInlineSimd()) { | 1439 if (!ShouldInlineSimd()) { |
| 1444 return false; | 1440 return false; |
| 1445 } | 1441 } |
| 1446 AddCheckClass(call->ArgumentAt(0), | 1442 AddCheckClass(call->ArgumentAt(0), |
| 1447 ICData::ZoneHandle( | 1443 ICData::ZoneHandle( |
| 1448 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1444 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1449 call->deopt_id(), | 1445 call->deopt_id(), |
| 1450 call->env(), | 1446 call->env(), |
| 1451 call); | 1447 call); |
| 1452 if ((getter == MethodRecognizer::kFloat64x2GetX) || | 1448 if ((getter == MethodRecognizer::kFloat64x2GetX) || |
| 1453 (getter == MethodRecognizer::kFloat64x2GetY)) { | 1449 (getter == MethodRecognizer::kFloat64x2GetY)) { |
| 1454 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr( | 1450 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr( |
| 1455 getter, | 1451 getter, |
| 1456 new(Z) Value(call->ArgumentAt(0)), | 1452 new(Z) Value(call->ArgumentAt(0)), |
| 1457 0, | 1453 0, |
| 1458 call->deopt_id()); | 1454 call->deopt_id()); |
| 1459 ReplaceCall(call, instr); | 1455 ReplaceCall(call, instr); |
| 1460 return true; | 1456 return true; |
| 1461 } | 1457 } |
| 1462 UNREACHABLE(); | 1458 UNREACHABLE(); |
| 1463 return false; | 1459 return false; |
| 1464 } | 1460 } |
| 1465 | 1461 |
| 1466 | 1462 |
| 1467 bool FlowGraphOptimizer::InlineInt32x4Getter(InstanceCallInstr* call, | 1463 bool JitOptimizer::InlineInt32x4Getter(InstanceCallInstr* call, |
| 1468 MethodRecognizer::Kind getter) { | 1464 MethodRecognizer::Kind getter) { |
| 1469 if (!ShouldInlineSimd()) { | 1465 if (!ShouldInlineSimd()) { |
| 1470 return false; | 1466 return false; |
| 1471 } | 1467 } |
| 1472 AddCheckClass(call->ArgumentAt(0), | 1468 AddCheckClass(call->ArgumentAt(0), |
| 1473 ICData::ZoneHandle( | 1469 ICData::ZoneHandle( |
| 1474 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1470 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| 1475 call->deopt_id(), | 1471 call->deopt_id(), |
| 1476 call->env(), | 1472 call->env(), |
| 1477 call); | 1473 call); |
| 1478 intptr_t mask = 0; | 1474 intptr_t mask = 0; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1532 Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr( | 1528 Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr( |
| 1533 getter, | 1529 getter, |
| 1534 new(Z) Value(call->ArgumentAt(0)), | 1530 new(Z) Value(call->ArgumentAt(0)), |
| 1535 call->deopt_id()); | 1531 call->deopt_id()); |
| 1536 ReplaceCall(call, instr); | 1532 ReplaceCall(call, instr); |
| 1537 return true; | 1533 return true; |
| 1538 } | 1534 } |
| 1539 } | 1535 } |
| 1540 | 1536 |
| 1541 | 1537 |
| 1542 bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, | 1538 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, |
| 1543 Token::Kind op_kind) { | 1539 Token::Kind op_kind) { |
| 1544 if (!ShouldInlineSimd()) { | 1540 if (!ShouldInlineSimd()) { |
| 1545 return false; | 1541 return false; |
| 1546 } | 1542 } |
| 1547 ASSERT(call->ArgumentCount() == 2); | 1543 ASSERT(call->ArgumentCount() == 2); |
| 1548 Definition* left = call->ArgumentAt(0); | 1544 Definition* left = call->ArgumentAt(0); |
| 1549 Definition* right = call->ArgumentAt(1); | 1545 Definition* right = call->ArgumentAt(1); |
| 1550 // Type check left. | 1546 // Type check left. |
| 1551 AddCheckClass(left, | 1547 AddCheckClass(left, |
| 1552 ICData::ZoneHandle( | 1548 ICData::ZoneHandle( |
| 1553 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1549 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1565 BinaryFloat32x4OpInstr* float32x4_bin_op = | 1561 BinaryFloat32x4OpInstr* float32x4_bin_op = |
| 1566 new(Z) BinaryFloat32x4OpInstr( | 1562 new(Z) BinaryFloat32x4OpInstr( |
| 1567 op_kind, new(Z) Value(left), new(Z) Value(right), | 1563 op_kind, new(Z) Value(left), new(Z) Value(right), |
| 1568 call->deopt_id()); | 1564 call->deopt_id()); |
| 1569 ReplaceCall(call, float32x4_bin_op); | 1565 ReplaceCall(call, float32x4_bin_op); |
| 1570 | 1566 |
| 1571 return true; | 1567 return true; |
| 1572 } | 1568 } |
| 1573 | 1569 |
| 1574 | 1570 |
| 1575 bool FlowGraphOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, | 1571 bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, |
| 1576 Token::Kind op_kind) { | 1572 Token::Kind op_kind) { |
| 1577 if (!ShouldInlineSimd()) { | 1573 if (!ShouldInlineSimd()) { |
| 1578 return false; | 1574 return false; |
| 1579 } | 1575 } |
| 1580 ASSERT(call->ArgumentCount() == 2); | 1576 ASSERT(call->ArgumentCount() == 2); |
| 1581 Definition* left = call->ArgumentAt(0); | 1577 Definition* left = call->ArgumentAt(0); |
| 1582 Definition* right = call->ArgumentAt(1); | 1578 Definition* right = call->ArgumentAt(1); |
| 1583 // Type check left. | 1579 // Type check left. |
| 1584 AddCheckClass(left, | 1580 AddCheckClass(left, |
| 1585 ICData::ZoneHandle( | 1581 ICData::ZoneHandle( |
| 1586 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1582 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1597 // Replace call. | 1593 // Replace call. |
| 1598 BinaryInt32x4OpInstr* int32x4_bin_op = | 1594 BinaryInt32x4OpInstr* int32x4_bin_op = |
| 1599 new(Z) BinaryInt32x4OpInstr( | 1595 new(Z) BinaryInt32x4OpInstr( |
| 1600 op_kind, new(Z) Value(left), new(Z) Value(right), | 1596 op_kind, new(Z) Value(left), new(Z) Value(right), |
| 1601 call->deopt_id()); | 1597 call->deopt_id()); |
| 1602 ReplaceCall(call, int32x4_bin_op); | 1598 ReplaceCall(call, int32x4_bin_op); |
| 1603 return true; | 1599 return true; |
| 1604 } | 1600 } |
| 1605 | 1601 |
| 1606 | 1602 |
| 1607 bool FlowGraphOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, | 1603 bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, |
| 1608 Token::Kind op_kind) { | 1604 Token::Kind op_kind) { |
| 1609 if (!ShouldInlineSimd()) { | 1605 if (!ShouldInlineSimd()) { |
| 1610 return false; | 1606 return false; |
| 1611 } | 1607 } |
| 1612 ASSERT(call->ArgumentCount() == 2); | 1608 ASSERT(call->ArgumentCount() == 2); |
| 1613 Definition* left = call->ArgumentAt(0); | 1609 Definition* left = call->ArgumentAt(0); |
| 1614 Definition* right = call->ArgumentAt(1); | 1610 Definition* right = call->ArgumentAt(1); |
| 1615 // Type check left. | 1611 // Type check left. |
| 1616 AddCheckClass(left, | 1612 AddCheckClass(left, |
| 1617 ICData::ZoneHandle( | 1613 ICData::ZoneHandle( |
| 1618 call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1614 call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1630 BinaryFloat64x2OpInstr* float64x2_bin_op = | 1626 BinaryFloat64x2OpInstr* float64x2_bin_op = |
| 1631 new(Z) BinaryFloat64x2OpInstr( | 1627 new(Z) BinaryFloat64x2OpInstr( |
| 1632 op_kind, new(Z) Value(left), new(Z) Value(right), | 1628 op_kind, new(Z) Value(left), new(Z) Value(right), |
| 1633 call->deopt_id()); | 1629 call->deopt_id()); |
| 1634 ReplaceCall(call, float64x2_bin_op); | 1630 ReplaceCall(call, float64x2_bin_op); |
| 1635 return true; | 1631 return true; |
| 1636 } | 1632 } |
| 1637 | 1633 |
| 1638 | 1634 |
| 1639 // Only unique implicit instance getters can be currently handled. | 1635 // Only unique implicit instance getters can be currently handled. |
| 1640 // Returns false if 'allow_check' is false and a check is needed. | 1636 bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
| 1641 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call, | |
| 1642 bool allow_check) { | |
| 1643 ASSERT(call->HasICData()); | 1637 ASSERT(call->HasICData()); |
| 1644 const ICData& ic_data = *call->ic_data(); | 1638 const ICData& ic_data = *call->ic_data(); |
| 1645 if (ic_data.NumberOfUsedChecks() == 0) { | 1639 if (ic_data.NumberOfUsedChecks() == 0) { |
| 1646 // No type feedback collected. | 1640 // No type feedback collected. |
| 1647 return false; | 1641 return false; |
| 1648 } | 1642 } |
| 1649 | 1643 |
| 1650 if (!ic_data.HasOneTarget()) { | 1644 if (!ic_data.HasOneTarget()) { |
| 1651 // Polymorphic sites are inlined like normal methods by conventional | 1645 // Polymorphic sites are inlined like normal methods by conventional |
| 1652 // inlining in FlowGraphInliner. | 1646 // inlining in FlowGraphInliner. |
| 1653 return false; | 1647 return false; |
| 1654 } | 1648 } |
| 1655 | 1649 |
| 1656 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); | 1650 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); |
| 1657 if (target.kind() != RawFunction::kImplicitGetter) { | 1651 if (target.kind() != RawFunction::kImplicitGetter) { |
| 1658 // Non-implicit getters are inlined like normal methods by conventional | 1652 // Non-implicit getters are inlined like normal methods by conventional |
| 1659 // inlining in FlowGraphInliner. | 1653 // inlining in FlowGraphInliner. |
| 1660 return false; | 1654 return false; |
| 1661 } | 1655 } |
| 1662 return InlineImplicitInstanceGetter(call, allow_check); | 1656 return InlineImplicitInstanceGetter(call); |
| 1663 } | 1657 } |
| 1664 | 1658 |
| 1665 | 1659 |
| 1666 bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline( | 1660 bool JitOptimizer::TryReplaceInstanceCallWithInline( |
| 1667 InstanceCallInstr* call) { | 1661 InstanceCallInstr* call) { |
| 1668 Function& target = Function::Handle(Z); | 1662 Function& target = Function::Handle(Z); |
| 1669 GrowableArray<intptr_t> class_ids; | 1663 GrowableArray<intptr_t> class_ids; |
| 1670 call->ic_data()->GetCheckAt(0, &class_ids, &target); | 1664 call->ic_data()->GetCheckAt(0, &class_ids, &target); |
| 1671 const intptr_t receiver_cid = class_ids[0]; | 1665 const intptr_t receiver_cid = class_ids[0]; |
| 1672 | 1666 |
| 1673 TargetEntryInstr* entry; | 1667 TargetEntryInstr* entry; |
| 1674 Definition* last; | 1668 Definition* last; |
| 1675 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_, | 1669 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_, |
| 1676 receiver_cid, | 1670 receiver_cid, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1700 last->LinkTo(call); | 1694 last->LinkTo(call); |
| 1701 // Remove through the iterator. | 1695 // Remove through the iterator. |
| 1702 ASSERT(current_iterator()->Current() == call); | 1696 ASSERT(current_iterator()->Current() == call); |
| 1703 current_iterator()->RemoveCurrentFromGraph(); | 1697 current_iterator()->RemoveCurrentFromGraph(); |
| 1704 call->set_previous(NULL); | 1698 call->set_previous(NULL); |
| 1705 call->set_next(NULL); | 1699 call->set_next(NULL); |
| 1706 return true; | 1700 return true; |
| 1707 } | 1701 } |
| 1708 | 1702 |
| 1709 | 1703 |
| 1710 void FlowGraphOptimizer::ReplaceWithMathCFunction( | 1704 void JitOptimizer::ReplaceWithMathCFunction( |
| 1711 InstanceCallInstr* call, | 1705 InstanceCallInstr* call, |
| 1712 MethodRecognizer::Kind recognized_kind) { | 1706 MethodRecognizer::Kind recognized_kind) { |
| 1713 AddReceiverCheck(call); | 1707 AddReceiverCheck(call); |
| 1714 ZoneGrowableArray<Value*>* args = | 1708 ZoneGrowableArray<Value*>* args = |
| 1715 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 1709 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 1716 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 1710 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 1717 args->Add(new(Z) Value(call->ArgumentAt(i))); | 1711 args->Add(new(Z) Value(call->ArgumentAt(i))); |
| 1718 } | 1712 } |
| 1719 InvokeMathCFunctionInstr* invoke = | 1713 InvokeMathCFunctionInstr* invoke = |
| 1720 new(Z) InvokeMathCFunctionInstr(args, | 1714 new(Z) InvokeMathCFunctionInstr(args, |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1741 case kTypedDataFloat32x4ArrayCid: | 1735 case kTypedDataFloat32x4ArrayCid: |
| 1742 case kTypedDataInt32x4ArrayCid: | 1736 case kTypedDataInt32x4ArrayCid: |
| 1743 return true; | 1737 return true; |
| 1744 default: | 1738 default: |
| 1745 return false; | 1739 return false; |
| 1746 } | 1740 } |
| 1747 } | 1741 } |
| 1748 | 1742 |
| 1749 | 1743 |
| 1750 // Inline only simple, frequently called core library methods. | 1744 // Inline only simple, frequently called core library methods. |
| 1751 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | 1745 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { |
| 1752 ASSERT(call->HasICData()); | 1746 ASSERT(call->HasICData()); |
| 1753 const ICData& ic_data = *call->ic_data(); | 1747 const ICData& ic_data = *call->ic_data(); |
| 1754 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) { | 1748 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) { |
| 1755 // No type feedback collected or multiple targets found. | 1749 // No type feedback collected or multiple targets found. |
| 1756 return false; | 1750 return false; |
| 1757 } | 1751 } |
| 1758 | 1752 |
| 1759 Function& target = Function::Handle(Z); | 1753 Function& target = Function::Handle(Z); |
| 1760 GrowableArray<intptr_t> class_ids; | 1754 GrowableArray<intptr_t> class_ids; |
| 1761 ic_data.GetCheckAt(0, &class_ids, &target); | 1755 ic_data.GetCheckAt(0, &class_ids, &target); |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1974 new(Z) Value(int32_mask), | 1968 new(Z) Value(int32_mask), |
| 1975 call->deopt_id()); | 1969 call->deopt_id()); |
| 1976 ReplaceCall(call, bit_and); | 1970 ReplaceCall(call, bit_and); |
| 1977 return true; | 1971 return true; |
| 1978 } | 1972 } |
| 1979 } | 1973 } |
| 1980 return false; | 1974 return false; |
| 1981 } | 1975 } |
| 1982 | 1976 |
| 1983 | 1977 |
| 1984 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( | 1978 bool JitOptimizer::TryInlineFloat32x4Constructor( |
| 1985 StaticCallInstr* call, | 1979 StaticCallInstr* call, |
| 1986 MethodRecognizer::Kind recognized_kind) { | 1980 MethodRecognizer::Kind recognized_kind) { |
| 1987 if (!ShouldInlineSimd()) { | 1981 if (!ShouldInlineSimd()) { |
| 1988 return false; | 1982 return false; |
| 1989 } | 1983 } |
| 1990 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { | 1984 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { |
| 1991 Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr(); | 1985 Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr(); |
| 1992 ReplaceCall(call, zero); | 1986 ReplaceCall(call, zero); |
| 1993 return true; | 1987 return true; |
| 1994 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { | 1988 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2017 Float64x2ToFloat32x4Instr* cast = | 2011 Float64x2ToFloat32x4Instr* cast = |
| 2018 new(Z) Float64x2ToFloat32x4Instr( | 2012 new(Z) Float64x2ToFloat32x4Instr( |
| 2019 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | 2013 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); |
| 2020 ReplaceCall(call, cast); | 2014 ReplaceCall(call, cast); |
| 2021 return true; | 2015 return true; |
| 2022 } | 2016 } |
| 2023 return false; | 2017 return false; |
| 2024 } | 2018 } |
| 2025 | 2019 |
| 2026 | 2020 |
| 2027 bool FlowGraphOptimizer::TryInlineFloat64x2Constructor( | 2021 bool JitOptimizer::TryInlineFloat64x2Constructor( |
| 2028 StaticCallInstr* call, | 2022 StaticCallInstr* call, |
| 2029 MethodRecognizer::Kind recognized_kind) { | 2023 MethodRecognizer::Kind recognized_kind) { |
| 2030 if (!ShouldInlineSimd()) { | 2024 if (!ShouldInlineSimd()) { |
| 2031 return false; | 2025 return false; |
| 2032 } | 2026 } |
| 2033 if (recognized_kind == MethodRecognizer::kFloat64x2Zero) { | 2027 if (recognized_kind == MethodRecognizer::kFloat64x2Zero) { |
| 2034 Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr(); | 2028 Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr(); |
| 2035 ReplaceCall(call, zero); | 2029 ReplaceCall(call, zero); |
| 2036 return true; | 2030 return true; |
| 2037 } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) { | 2031 } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2052 Float32x4ToFloat64x2Instr* cast = | 2046 Float32x4ToFloat64x2Instr* cast = |
| 2053 new(Z) Float32x4ToFloat64x2Instr( | 2047 new(Z) Float32x4ToFloat64x2Instr( |
| 2054 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | 2048 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); |
| 2055 ReplaceCall(call, cast); | 2049 ReplaceCall(call, cast); |
| 2056 return true; | 2050 return true; |
| 2057 } | 2051 } |
| 2058 return false; | 2052 return false; |
| 2059 } | 2053 } |
| 2060 | 2054 |
| 2061 | 2055 |
| 2062 bool FlowGraphOptimizer::TryInlineInt32x4Constructor( | 2056 bool JitOptimizer::TryInlineInt32x4Constructor( |
| 2063 StaticCallInstr* call, | 2057 StaticCallInstr* call, |
| 2064 MethodRecognizer::Kind recognized_kind) { | 2058 MethodRecognizer::Kind recognized_kind) { |
| 2065 if (!ShouldInlineSimd()) { | 2059 if (!ShouldInlineSimd()) { |
| 2066 return false; | 2060 return false; |
| 2067 } | 2061 } |
| 2068 if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) { | 2062 if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) { |
| 2069 Int32x4BoolConstructorInstr* con = | 2063 Int32x4BoolConstructorInstr* con = |
| 2070 new(Z) Int32x4BoolConstructorInstr( | 2064 new(Z) Int32x4BoolConstructorInstr( |
| 2071 new(Z) Value(call->ArgumentAt(1)), | 2065 new(Z) Value(call->ArgumentAt(1)), |
| 2072 new(Z) Value(call->ArgumentAt(2)), | 2066 new(Z) Value(call->ArgumentAt(2)), |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2089 new(Z) Value(call->ArgumentAt(3)), | 2083 new(Z) Value(call->ArgumentAt(3)), |
| 2090 new(Z) Value(call->ArgumentAt(4)), | 2084 new(Z) Value(call->ArgumentAt(4)), |
| 2091 call->deopt_id()); | 2085 call->deopt_id()); |
| 2092 ReplaceCall(call, con); | 2086 ReplaceCall(call, con); |
| 2093 return true; | 2087 return true; |
| 2094 } | 2088 } |
| 2095 return false; | 2089 return false; |
| 2096 } | 2090 } |
| 2097 | 2091 |
| 2098 | 2092 |
| 2099 bool FlowGraphOptimizer::TryInlineFloat32x4Method( | 2093 bool JitOptimizer::TryInlineFloat32x4Method( |
| 2100 InstanceCallInstr* call, | 2094 InstanceCallInstr* call, |
| 2101 MethodRecognizer::Kind recognized_kind) { | 2095 MethodRecognizer::Kind recognized_kind) { |
| 2102 if (!ShouldInlineSimd()) { | 2096 if (!ShouldInlineSimd()) { |
| 2103 return false; | 2097 return false; |
| 2104 } | 2098 } |
| 2105 ASSERT(call->HasICData()); | 2099 ASSERT(call->HasICData()); |
| 2106 switch (recognized_kind) { | 2100 switch (recognized_kind) { |
| 2107 case MethodRecognizer::kFloat32x4ShuffleX: | 2101 case MethodRecognizer::kFloat32x4ShuffleX: |
| 2108 case MethodRecognizer::kFloat32x4ShuffleY: | 2102 case MethodRecognizer::kFloat32x4ShuffleY: |
| 2109 case MethodRecognizer::kFloat32x4ShuffleZ: | 2103 case MethodRecognizer::kFloat32x4ShuffleZ: |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2253 case MethodRecognizer::kFloat32x4ShuffleMix: | 2247 case MethodRecognizer::kFloat32x4ShuffleMix: |
| 2254 case MethodRecognizer::kFloat32x4Shuffle: { | 2248 case MethodRecognizer::kFloat32x4Shuffle: { |
| 2255 return InlineFloat32x4Getter(call, recognized_kind); | 2249 return InlineFloat32x4Getter(call, recognized_kind); |
| 2256 } | 2250 } |
| 2257 default: | 2251 default: |
| 2258 return false; | 2252 return false; |
| 2259 } | 2253 } |
| 2260 } | 2254 } |
| 2261 | 2255 |
| 2262 | 2256 |
| 2263 bool FlowGraphOptimizer::TryInlineFloat64x2Method( | 2257 bool JitOptimizer::TryInlineFloat64x2Method( |
| 2264 InstanceCallInstr* call, | 2258 InstanceCallInstr* call, |
| 2265 MethodRecognizer::Kind recognized_kind) { | 2259 MethodRecognizer::Kind recognized_kind) { |
| 2266 if (!ShouldInlineSimd()) { | 2260 if (!ShouldInlineSimd()) { |
| 2267 return false; | 2261 return false; |
| 2268 } | 2262 } |
| 2269 ASSERT(call->HasICData()); | 2263 ASSERT(call->HasICData()); |
| 2270 switch (recognized_kind) { | 2264 switch (recognized_kind) { |
| 2271 case MethodRecognizer::kFloat64x2GetX: | 2265 case MethodRecognizer::kFloat64x2GetX: |
| 2272 case MethodRecognizer::kFloat64x2GetY: | 2266 case MethodRecognizer::kFloat64x2GetY: |
| 2273 ASSERT(call->ic_data()->HasReceiverClassId(kFloat64x2Cid)); | 2267 ASSERT(call->ic_data()->HasReceiverClassId(kFloat64x2Cid)); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2312 call->deopt_id()); | 2306 call->deopt_id()); |
| 2313 ReplaceCall(call, zeroArg); | 2307 ReplaceCall(call, zeroArg); |
| 2314 return true; | 2308 return true; |
| 2315 } | 2309 } |
| 2316 default: | 2310 default: |
| 2317 return false; | 2311 return false; |
| 2318 } | 2312 } |
| 2319 } | 2313 } |
| 2320 | 2314 |
| 2321 | 2315 |
| 2322 bool FlowGraphOptimizer::TryInlineInt32x4Method( | 2316 bool JitOptimizer::TryInlineInt32x4Method( |
| 2323 InstanceCallInstr* call, | 2317 InstanceCallInstr* call, |
| 2324 MethodRecognizer::Kind recognized_kind) { | 2318 MethodRecognizer::Kind recognized_kind) { |
| 2325 if (!ShouldInlineSimd()) { | 2319 if (!ShouldInlineSimd()) { |
| 2326 return false; | 2320 return false; |
| 2327 } | 2321 } |
| 2328 ASSERT(call->HasICData()); | 2322 ASSERT(call->HasICData()); |
| 2329 switch (recognized_kind) { | 2323 switch (recognized_kind) { |
| 2330 case MethodRecognizer::kInt32x4ShuffleMix: | 2324 case MethodRecognizer::kInt32x4ShuffleMix: |
| 2331 case MethodRecognizer::kInt32x4Shuffle: | 2325 case MethodRecognizer::kInt32x4Shuffle: |
| 2332 case MethodRecognizer::kInt32x4GetFlagX: | 2326 case MethodRecognizer::kInt32x4GetFlagX: |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2383 } | 2377 } |
| 2384 } | 2378 } |
| 2385 | 2379 |
| 2386 | 2380 |
| 2387 // If type tests specified by 'ic_data' do not depend on type arguments, | 2381 // If type tests specified by 'ic_data' do not depend on type arguments, |
| 2388 // return mapping cid->result in 'results' (i : cid; i + 1: result). | 2382 // return mapping cid->result in 'results' (i : cid; i + 1: result). |
| 2389 // If all tests yield the same result, return it otherwise return Bool::null. | 2383 // If all tests yield the same result, return it otherwise return Bool::null. |
| 2390 // If no mapping is possible, 'results' is empty. | 2384 // If no mapping is possible, 'results' is empty. |
| 2391 // An instance-of test returning all same results can be converted to a class | 2385 // An instance-of test returning all same results can be converted to a class |
| 2392 // check. | 2386 // check. |
| 2393 RawBool* FlowGraphOptimizer::InstanceOfAsBool( | 2387 RawBool* JitOptimizer::InstanceOfAsBool( |
| 2394 const ICData& ic_data, | 2388 const ICData& ic_data, |
| 2395 const AbstractType& type, | 2389 const AbstractType& type, |
| 2396 ZoneGrowableArray<intptr_t>* results) const { | 2390 ZoneGrowableArray<intptr_t>* results) const { |
| 2397 ASSERT(results->is_empty()); | 2391 ASSERT(results->is_empty()); |
| 2398 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. | 2392 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. |
| 2399 if (type.IsFunctionType() || type.IsDartFunctionType() || | 2393 if (type.IsFunctionType() || type.IsDartFunctionType() || |
| 2400 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) { | 2394 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) { |
| 2401 return Bool::null(); | 2395 return Bool::null(); |
| 2402 } | 2396 } |
| 2403 const Class& type_class = Class::Handle(Z, type.type_class()); | 2397 const Class& type_class = Class::Handle(Z, type.type_class()); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2442 if (is_subtype != prev.value()) { | 2436 if (is_subtype != prev.value()) { |
| 2443 results_differ = true; | 2437 results_differ = true; |
| 2444 } | 2438 } |
| 2445 } | 2439 } |
| 2446 } | 2440 } |
| 2447 return results_differ ? Bool::null() : prev.raw(); | 2441 return results_differ ? Bool::null() : prev.raw(); |
| 2448 } | 2442 } |
| 2449 | 2443 |
| 2450 | 2444 |
| 2451 // Returns true if checking against this type is a direct class id comparison. | 2445 // Returns true if checking against this type is a direct class id comparison. |
| 2452 bool FlowGraphOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { | 2446 bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { |
| 2453 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 2447 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
| 2454 // Requires CHA. | 2448 // Requires CHA. |
| 2455 if (!type.IsInstantiated()) return false; | 2449 if (!type.IsInstantiated()) return false; |
| 2456 // Function types have different type checking rules. | 2450 // Function types have different type checking rules. |
| 2457 if (type.IsFunctionType()) return false; | 2451 if (type.IsFunctionType()) return false; |
| 2458 const Class& type_class = Class::Handle(type.type_class()); | 2452 const Class& type_class = Class::Handle(type.type_class()); |
| 2459 // Could be an interface check? | 2453 // Could be an interface check? |
| 2460 if (CHA::IsImplemented(type_class)) return false; | 2454 if (CHA::IsImplemented(type_class)) return false; |
| 2461 // Check if there are subclasses. | 2455 // Check if there are subclasses. |
| 2462 if (CHA::HasSubclasses(type_class)) { | 2456 if (CHA::HasSubclasses(type_class)) { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2546 TryAddTest(results, kBigintCid, true); | 2540 TryAddTest(results, kBigintCid, true); |
| 2547 // Cannot deoptimize since all tests returning true have been added. | 2541 // Cannot deoptimize since all tests returning true have been added. |
| 2548 return false; | 2542 return false; |
| 2549 } | 2543 } |
| 2550 | 2544 |
| 2551 return true; // May deoptimize since we have not identified all 'true' tests. | 2545 return true; // May deoptimize since we have not identified all 'true' tests. |
| 2552 } | 2546 } |
| 2553 | 2547 |
| 2554 | 2548 |
| 2555 // TODO(srdjan): Use ICData to check if always true or false. | 2549 // TODO(srdjan): Use ICData to check if always true or false. |
| 2556 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 2550 void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
| 2557 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 2551 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
| 2558 Definition* left = call->ArgumentAt(0); | 2552 Definition* left = call->ArgumentAt(0); |
| 2559 Definition* type_args = NULL; | 2553 Definition* type_args = NULL; |
| 2560 AbstractType& type = AbstractType::ZoneHandle(Z); | 2554 AbstractType& type = AbstractType::ZoneHandle(Z); |
| 2561 bool negate = false; | 2555 bool negate = false; |
| 2562 if (call->ArgumentCount() == 2) { | 2556 if (call->ArgumentCount() == 2) { |
| 2563 type_args = flow_graph()->constant_null(); | 2557 type_args = flow_graph()->constant_null(); |
| 2564 if (call->function_name().raw() == | 2558 if (call->function_name().raw() == |
| 2565 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) { | 2559 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) { |
| 2566 type = Type::Number(); | 2560 type = Type::Number(); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2654 new(Z) Value(left), | 2648 new(Z) Value(left), |
| 2655 new(Z) Value(type_args), | 2649 new(Z) Value(type_args), |
| 2656 type, | 2650 type, |
| 2657 negate, | 2651 negate, |
| 2658 call->deopt_id()); | 2652 call->deopt_id()); |
| 2659 ReplaceCall(call, instance_of); | 2653 ReplaceCall(call, instance_of); |
| 2660 } | 2654 } |
| 2661 | 2655 |
| 2662 | 2656 |
| 2663 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). | 2657 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). |
| 2664 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { | 2658 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
| 2665 ASSERT(Token::IsTypeCastOperator(call->token_kind())); | 2659 ASSERT(Token::IsTypeCastOperator(call->token_kind())); |
| 2666 Definition* left = call->ArgumentAt(0); | 2660 Definition* left = call->ArgumentAt(0); |
| 2667 Definition* type_args = call->ArgumentAt(1); | 2661 Definition* type_args = call->ArgumentAt(1); |
| 2668 const AbstractType& type = | 2662 const AbstractType& type = |
| 2669 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); | 2663 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); |
| 2670 ASSERT(!type.IsMalformedOrMalbounded()); | 2664 ASSERT(!type.IsMalformedOrMalbounded()); |
| 2671 const ICData& unary_checks = | 2665 const ICData& unary_checks = |
| 2672 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); | 2666 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); |
| 2673 if ((unary_checks.NumberOfChecks() > 0) && | 2667 if ((unary_checks.NumberOfChecks() > 0) && |
| 2674 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { | 2668 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2697 new(Z) AssertAssignableInstr(call->token_pos(), | 2691 new(Z) AssertAssignableInstr(call->token_pos(), |
| 2698 new(Z) Value(left), | 2692 new(Z) Value(left), |
| 2699 new(Z) Value(type_args), | 2693 new(Z) Value(type_args), |
| 2700 type, | 2694 type, |
| 2701 dst_name, | 2695 dst_name, |
| 2702 call->deopt_id()); | 2696 call->deopt_id()); |
| 2703 ReplaceCall(call, assert_as); | 2697 ReplaceCall(call, assert_as); |
| 2704 } | 2698 } |
| 2705 | 2699 |
| 2706 | 2700 |
| 2707 bool FlowGraphOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) { | |
| 2708 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { | |
| 2709 if ((*inlining_black_list_)[i] == call_deopt_id) return true; | |
| 2710 } | |
| 2711 return false; | |
| 2712 } | |
| 2713 | |
| 2714 // Special optimizations when running in --noopt mode. | |
| 2715 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { | |
| 2716 // TODO(srdjan): Investigate other attempts, as they are not allowed to | |
| 2717 // deoptimize. | |
| 2718 | |
| 2719 // Type test is special as it always gets converted into inlined code. | |
| 2720 const Token::Kind op_kind = instr->token_kind(); | |
| 2721 if (Token::IsTypeTestOperator(op_kind)) { | |
| 2722 ReplaceWithInstanceOf(instr); | |
| 2723 return; | |
| 2724 } | |
| 2725 if (Token::IsTypeCastOperator(op_kind)) { | |
| 2726 ReplaceWithTypeCast(instr); | |
| 2727 return; | |
| 2728 } | |
| 2729 | |
| 2730 if ((op_kind == Token::kGET) && | |
| 2731 TryInlineInstanceGetter(instr, false /* no checks allowed */)) { | |
| 2732 return; | |
| 2733 } | |
| 2734 const ICData& unary_checks = | |
| 2735 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | |
| 2736 if ((unary_checks.NumberOfChecks() > 0) && | |
| 2737 (op_kind == Token::kSET) && | |
| 2738 TryInlineInstanceSetter(instr, unary_checks, false /* no checks */)) { | |
| 2739 return; | |
| 2740 } | |
| 2741 | |
| 2742 if (use_speculative_inlining_ && | |
| 2743 !IsBlackListedForInlining(instr->deopt_id()) && | |
| 2744 (unary_checks.NumberOfChecks() > 0)) { | |
| 2745 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { | |
| 2746 return; | |
| 2747 } | |
| 2748 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { | |
| 2749 return; | |
| 2750 } | |
| 2751 if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) { | |
| 2752 return; | |
| 2753 } | |
| 2754 | |
| 2755 if (Token::IsRelationalOperator(op_kind) && | |
| 2756 TryReplaceWithRelationalOp(instr, op_kind)) { | |
| 2757 return; | |
| 2758 } | |
| 2759 | |
| 2760 if (Token::IsBinaryOperator(op_kind) && | |
| 2761 TryReplaceWithBinaryOp(instr, op_kind)) { | |
| 2762 return; | |
| 2763 } | |
| 2764 if (Token::IsUnaryOperator(op_kind) && | |
| 2765 TryReplaceWithUnaryOp(instr, op_kind)) { | |
| 2766 return; | |
| 2767 } | |
| 2768 } | |
| 2769 | |
| 2770 bool has_one_target = | |
| 2771 (unary_checks.NumberOfChecks() > 0) && unary_checks.HasOneTarget(); | |
| 2772 if (has_one_target) { | |
| 2773 // Check if the single target is a polymorphic target, if it is, | |
| 2774 // we don't have one target. | |
| 2775 const Function& target = | |
| 2776 Function::Handle(Z, unary_checks.GetTargetAt(0)); | |
| 2777 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target); | |
| 2778 has_one_target = !polymorphic_target; | |
| 2779 } | |
| 2780 | |
| 2781 if (has_one_target) { | |
| 2782 RawFunction::Kind function_kind = | |
| 2783 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind(); | |
| 2784 if (!InstanceCallNeedsClassCheck(instr, function_kind)) { | |
| 2785 PolymorphicInstanceCallInstr* call = | |
| 2786 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | |
| 2787 /* with_checks = */ false); | |
| 2788 instr->ReplaceWith(call, current_iterator()); | |
| 2789 return; | |
| 2790 } | |
| 2791 } | |
| 2792 | |
| 2793 // More than one targets. Generate generic polymorphic call without | |
| 2794 // deoptimization. | |
| 2795 if (instr->ic_data()->NumberOfUsedChecks() > 0) { | |
| 2796 ASSERT(!FLAG_polymorphic_with_deopt); | |
| 2797 // OK to use checks with PolymorphicInstanceCallInstr since no | |
| 2798 // deoptimization is allowed. | |
| 2799 PolymorphicInstanceCallInstr* call = | |
| 2800 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | |
| 2801 /* with_checks = */ true); | |
| 2802 instr->ReplaceWith(call, current_iterator()); | |
| 2803 return; | |
| 2804 } | |
| 2805 | |
| 2806 // No IC data checks. Try resolve target using the propagated type. | |
| 2807 // If the propagated type has a method with the target name and there are | |
| 2808 // no overrides with that name according to CHA, call the method directly. | |
| 2809 const intptr_t receiver_cid = | |
| 2810 instr->PushArgumentAt(0)->value()->Type()->ToCid(); | |
| 2811 if (receiver_cid == kDynamicCid) return; | |
| 2812 const Class& receiver_class = Class::Handle(Z, | |
| 2813 isolate()->class_table()->At(receiver_cid)); | |
| 2814 | |
| 2815 const Array& args_desc_array = Array::Handle(Z, | |
| 2816 ArgumentsDescriptor::New(instr->ArgumentCount(), | |
| 2817 instr->argument_names())); | |
| 2818 ArgumentsDescriptor args_desc(args_desc_array); | |
| 2819 const Function& function = Function::Handle(Z, | |
| 2820 Resolver::ResolveDynamicForReceiverClass( | |
| 2821 receiver_class, | |
| 2822 instr->function_name(), | |
| 2823 args_desc)); | |
| 2824 if (function.IsNull()) { | |
| 2825 return; | |
| 2826 } | |
| 2827 if (!thread()->cha()->HasOverride(receiver_class, instr->function_name())) { | |
| 2828 if (FLAG_trace_cha) { | |
| 2829 THR_Print(" **(CHA) Instance call needs no check, " | |
| 2830 "no overrides of '%s' '%s'\n", | |
| 2831 instr->function_name().ToCString(), receiver_class.ToCString()); | |
| 2832 } | |
| 2833 thread()->cha()->AddToLeafClasses(receiver_class); | |
| 2834 | |
| 2835 // Create fake IC data with the resolved target. | |
| 2836 const ICData& ic_data = ICData::Handle( | |
| 2837 ICData::New(flow_graph_->function(), | |
| 2838 instr->function_name(), | |
| 2839 args_desc_array, | |
| 2840 Thread::kNoDeoptId, | |
| 2841 /* args_tested = */ 1)); | |
| 2842 ic_data.AddReceiverCheck(receiver_class.id(), function); | |
| 2843 PolymorphicInstanceCallInstr* call = | |
| 2844 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, | |
| 2845 /* with_checks = */ false); | |
| 2846 instr->ReplaceWith(call, current_iterator()); | |
| 2847 return; | |
| 2848 } | |
| 2849 } | |
| 2850 | |
| 2851 | |
| 2852 // Tries to optimize instance call by replacing it with a faster instruction | 2701 // Tries to optimize instance call by replacing it with a faster instruction |
| 2853 // (e.g, binary op, field load, ..). | 2702 // (e.g, binary op, field load, ..). |
| 2854 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 2703 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 2855 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { | 2704 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { |
| 2856 return; | 2705 return; |
| 2857 } | 2706 } |
| 2858 const Token::Kind op_kind = instr->token_kind(); | 2707 const Token::Kind op_kind = instr->token_kind(); |
| 2859 | 2708 |
| 2860 // Type test is special as it always gets converted into inlined code. | 2709 // Type test is special as it always gets converted into inlined code. |
| 2861 if (Token::IsTypeTestOperator(op_kind)) { | 2710 if (Token::IsTypeTestOperator(op_kind)) { |
| 2862 ReplaceWithInstanceOf(instr); | 2711 ReplaceWithInstanceOf(instr); |
| 2863 return; | 2712 return; |
| 2864 } | 2713 } |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2950 call_with_checks = true; | 2799 call_with_checks = true; |
| 2951 } | 2800 } |
| 2952 PolymorphicInstanceCallInstr* call = | 2801 PolymorphicInstanceCallInstr* call = |
| 2953 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | 2802 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, |
| 2954 call_with_checks); | 2803 call_with_checks); |
| 2955 instr->ReplaceWith(call, current_iterator()); | 2804 instr->ReplaceWith(call, current_iterator()); |
| 2956 } | 2805 } |
| 2957 } | 2806 } |
| 2958 | 2807 |
| 2959 | 2808 |
| 2960 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { | 2809 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { |
| 2961 if (!CanUnboxDouble()) { | 2810 if (!CanUnboxDouble()) { |
| 2962 return; | 2811 return; |
| 2963 } | 2812 } |
| 2964 MethodRecognizer::Kind recognized_kind = | 2813 MethodRecognizer::Kind recognized_kind = |
| 2965 MethodRecognizer::RecognizeKind(call->function()); | 2814 MethodRecognizer::RecognizeKind(call->function()); |
| 2966 MathUnaryInstr::MathUnaryKind unary_kind; | 2815 MathUnaryInstr::MathUnaryKind unary_kind; |
| 2967 switch (recognized_kind) { | 2816 switch (recognized_kind) { |
| 2968 case MethodRecognizer::kMathSqrt: | 2817 case MethodRecognizer::kMathSqrt: |
| 2969 unary_kind = MathUnaryInstr::kSqrt; | 2818 unary_kind = MathUnaryInstr::kSqrt; |
| 2970 break; | 2819 break; |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3123 default: | 2972 default: |
| 3124 break; | 2973 break; |
| 3125 } | 2974 } |
| 3126 } | 2975 } |
| 3127 } | 2976 } |
| 3128 } | 2977 } |
| 3129 } | 2978 } |
| 3130 } | 2979 } |
| 3131 | 2980 |
| 3132 | 2981 |
| 3133 void FlowGraphOptimizer::VisitStoreInstanceField( | 2982 void JitOptimizer::VisitStoreInstanceField( |
| 3134 StoreInstanceFieldInstr* instr) { | 2983 StoreInstanceFieldInstr* instr) { |
| 3135 if (instr->IsUnboxedStore()) { | 2984 if (instr->IsUnboxedStore()) { |
| 3136 ASSERT(instr->is_potential_unboxed_initialization_); | 2985 ASSERT(instr->is_potential_unboxed_initialization_); |
| 3137 // Determine if this field should be unboxed based on the usage of getter | 2986 // Determine if this field should be unboxed based on the usage of getter |
| 3138 // and setter functions: The heuristic requires that the setter has a | 2987 // and setter functions: The heuristic requires that the setter has a |
| 3139 // usage count of at least 1/kGetterSetterRatio of the getter usage count. | 2988 // usage count of at least 1/kGetterSetterRatio of the getter usage count. |
| 3140 // This is to avoid unboxing fields where the setter is never or rarely | 2989 // This is to avoid unboxing fields where the setter is never or rarely |
| 3141 // executed. | 2990 // executed. |
| 3142 const Field& field = Field::ZoneHandle(Z, instr->field().raw()); | 2991 const Field& field = Field::ZoneHandle(Z, instr->field().raw()); |
| 3143 const String& field_name = String::Handle(Z, field.name()); | 2992 const String& field_name = String::Handle(Z, field.name()); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3177 } | 3026 } |
| 3178 field.set_is_unboxing_candidate(false); | 3027 field.set_is_unboxing_candidate(false); |
| 3179 field.DeoptimizeDependentCode(); | 3028 field.DeoptimizeDependentCode(); |
| 3180 } else { | 3029 } else { |
| 3181 flow_graph()->parsed_function().AddToGuardedFields(&field); | 3030 flow_graph()->parsed_function().AddToGuardedFields(&field); |
| 3182 } | 3031 } |
| 3183 } | 3032 } |
| 3184 } | 3033 } |
| 3185 | 3034 |
| 3186 | 3035 |
| 3187 void FlowGraphOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { | 3036 void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { |
| 3188 // Replace generic allocation with a sequence of inlined allocation and | 3037 // Replace generic allocation with a sequence of inlined allocation and |
| 3189 // explicit initalizing stores. | 3038 // explicit initalizing stores. |
| 3190 AllocateUninitializedContextInstr* replacement = | 3039 AllocateUninitializedContextInstr* replacement = |
| 3191 new AllocateUninitializedContextInstr(instr->token_pos(), | 3040 new AllocateUninitializedContextInstr(instr->token_pos(), |
| 3192 instr->num_context_variables()); | 3041 instr->num_context_variables()); |
| 3193 instr->ReplaceWith(replacement, current_iterator()); | 3042 instr->ReplaceWith(replacement, current_iterator()); |
| 3194 | 3043 |
| 3195 StoreInstanceFieldInstr* store = | 3044 StoreInstanceFieldInstr* store = |
| 3196 new(Z) StoreInstanceFieldInstr(Context::parent_offset(), | 3045 new(Z) StoreInstanceFieldInstr(Context::parent_offset(), |
| 3197 new Value(replacement), | 3046 new Value(replacement), |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3212 instr->token_pos()); | 3061 instr->token_pos()); |
| 3213 // Storing into uninitialized memory; remember to prevent dead store | 3062 // Storing into uninitialized memory; remember to prevent dead store |
| 3214 // elimination and ensure proper GC barrier. | 3063 // elimination and ensure proper GC barrier. |
| 3215 store->set_is_object_reference_initialization(true); | 3064 store->set_is_object_reference_initialization(true); |
| 3216 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); | 3065 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); |
| 3217 cursor = store; | 3066 cursor = store; |
| 3218 } | 3067 } |
| 3219 } | 3068 } |
| 3220 | 3069 |
| 3221 | 3070 |
| 3222 void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { | 3071 void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { |
| 3223 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. | 3072 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. |
| 3224 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) | 3073 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) |
| 3225 if (!instr->can_pack_into_smi()) | 3074 if (!instr->can_pack_into_smi()) |
| 3226 instr->set_representation(kUnboxedMint); | 3075 instr->set_representation(kUnboxedMint); |
| 3227 #endif | 3076 #endif |
| 3228 } | 3077 } |
| 3229 | 3078 |
| 3230 | 3079 |
| 3231 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, | 3080 bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, |
| 3232 const ICData& unary_ic_data, | 3081 const ICData& unary_ic_data) { |
| 3233 bool allow_checks) { | |
| 3234 ASSERT((unary_ic_data.NumberOfChecks() > 0) && | 3082 ASSERT((unary_ic_data.NumberOfChecks() > 0) && |
| 3235 (unary_ic_data.NumArgsTested() == 1)); | 3083 (unary_ic_data.NumArgsTested() == 1)); |
| 3236 if (I->flags().type_checks()) { | 3084 if (I->flags().type_checks()) { |
| 3237 // Checked mode setters are inlined like normal methods by conventional | 3085 // Checked mode setters are inlined like normal methods by conventional |
| 3238 // inlining. | 3086 // inlining. |
| 3239 return false; | 3087 return false; |
| 3240 } | 3088 } |
| 3241 | 3089 |
| 3242 ASSERT(instr->HasICData()); | 3090 ASSERT(instr->HasICData()); |
| 3243 if (unary_ic_data.NumberOfChecks() == 0) { | 3091 if (unary_ic_data.NumberOfChecks() == 0) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3257 return false; | 3105 return false; |
| 3258 } | 3106 } |
| 3259 // Inline implicit instance setter. | 3107 // Inline implicit instance setter. |
| 3260 const String& field_name = | 3108 const String& field_name = |
| 3261 String::Handle(Z, Field::NameFromSetter(instr->function_name())); | 3109 String::Handle(Z, Field::NameFromSetter(instr->function_name())); |
| 3262 const Field& field = | 3110 const Field& field = |
| 3263 Field::ZoneHandle(Z, GetField(class_id, field_name)); | 3111 Field::ZoneHandle(Z, GetField(class_id, field_name)); |
| 3264 ASSERT(!field.IsNull()); | 3112 ASSERT(!field.IsNull()); |
| 3265 | 3113 |
| 3266 if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) { | 3114 if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) { |
| 3267 if (!allow_checks) { | |
| 3268 return false; | |
| 3269 } | |
| 3270 AddReceiverCheck(instr); | 3115 AddReceiverCheck(instr); |
| 3271 } | 3116 } |
| 3272 if (field.guarded_cid() != kDynamicCid) { | 3117 if (field.guarded_cid() != kDynamicCid) { |
| 3273 if (!allow_checks) { | |
| 3274 return false; | |
| 3275 } | |
| 3276 InsertBefore(instr, | 3118 InsertBefore(instr, |
| 3277 new(Z) GuardFieldClassInstr( | 3119 new(Z) GuardFieldClassInstr( |
| 3278 new(Z) Value(instr->ArgumentAt(1)), | 3120 new(Z) Value(instr->ArgumentAt(1)), |
| 3279 field, | 3121 field, |
| 3280 instr->deopt_id()), | 3122 instr->deopt_id()), |
| 3281 instr->env(), | 3123 instr->env(), |
| 3282 FlowGraph::kEffect); | 3124 FlowGraph::kEffect); |
| 3283 } | 3125 } |
| 3284 | 3126 |
| 3285 if (field.needs_length_check()) { | 3127 if (field.needs_length_check()) { |
| 3286 if (!allow_checks) { | |
| 3287 return false; | |
| 3288 } | |
| 3289 InsertBefore(instr, | 3128 InsertBefore(instr, |
| 3290 new(Z) GuardFieldLengthInstr( | 3129 new(Z) GuardFieldLengthInstr( |
| 3291 new(Z) Value(instr->ArgumentAt(1)), | 3130 new(Z) Value(instr->ArgumentAt(1)), |
| 3292 field, | 3131 field, |
| 3293 instr->deopt_id()), | 3132 instr->deopt_id()), |
| 3294 instr->env(), | 3133 instr->env(), |
| 3295 FlowGraph::kEffect); | 3134 FlowGraph::kEffect); |
| 3296 } | 3135 } |
| 3297 | 3136 |
| 3298 // Field guard was detached. | 3137 // Field guard was detached. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3309 | 3148 |
| 3310 // Discard the environment from the original instruction because the store | 3149 // Discard the environment from the original instruction because the store |
| 3311 // can't deoptimize. | 3150 // can't deoptimize. |
| 3312 instr->RemoveEnvironment(); | 3151 instr->RemoveEnvironment(); |
| 3313 ReplaceCall(instr, store); | 3152 ReplaceCall(instr, store); |
| 3314 return true; | 3153 return true; |
| 3315 } | 3154 } |
| 3316 | 3155 |
| 3317 | 3156 |
| 3318 } // namespace dart | 3157 } // namespace dart |
| OLD | NEW |