Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: runtime/vm/jit_optimizer.cc

Issue 1732483002: Rename FlowGraphOptimizer -> JitOptimizer, clean up optimizer code. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/jit_optimizer.h ('k') | runtime/vm/vm_sources.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/jit_optimizer.h ('k') | runtime/vm/vm_sources.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698