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

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

Issue 2974233002: VM: Re-format to use at most one newline between functions (Closed)
Patch Set: Rebase and merge Created 3 years, 5 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/aot_optimizer.h ('k') | runtime/vm/assembler.h » ('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/aot_optimizer.h" 5 #include "vm/aot_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"
(...skipping 29 matching lines...) Expand all
40 // Quick access to the current isolate and zone. 40 // Quick access to the current isolate and zone.
41 #define I (isolate()) 41 #define I (isolate())
42 #define Z (zone()) 42 #define Z (zone())
43 43
44 #ifdef DART_PRECOMPILER 44 #ifdef DART_PRECOMPILER
45 45
46 static bool ShouldInlineSimd() { 46 static bool ShouldInlineSimd() {
47 return FlowGraphCompiler::SupportsUnboxedSimd128(); 47 return FlowGraphCompiler::SupportsUnboxedSimd128();
48 } 48 }
49 49
50
51 static bool CanUnboxDouble() { 50 static bool CanUnboxDouble() {
52 return FlowGraphCompiler::SupportsUnboxedDoubles(); 51 return FlowGraphCompiler::SupportsUnboxedDoubles();
53 } 52 }
54 53
55
56 static bool CanConvertUnboxedMintToDouble() { 54 static bool CanConvertUnboxedMintToDouble() {
57 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); 55 return FlowGraphCompiler::CanConvertUnboxedMintToDouble();
58 } 56 }
59 57
60
61 // Returns named function that is a unique dynamic target, i.e., 58 // Returns named function that is a unique dynamic target, i.e.,
62 // - the target is identified by its name alone, since it occurs only once. 59 // - the target is identified by its name alone, since it occurs only once.
63 // - target's class has no subclasses, and neither is subclassed, i.e., 60 // - target's class has no subclasses, and neither is subclassed, i.e.,
64 // the receiver type can be only the function's class. 61 // the receiver type can be only the function's class.
65 // Returns Function::null() if there is no unique dynamic target for 62 // Returns Function::null() if there is no unique dynamic target for
66 // given 'fname'. 'fname' must be a symbol. 63 // given 'fname'. 'fname' must be a symbol.
67 static void GetUniqueDynamicTarget(Isolate* isolate, 64 static void GetUniqueDynamicTarget(Isolate* isolate,
68 const String& fname, 65 const String& fname,
69 Object* function) { 66 Object* function) {
70 UniqueFunctionsSet functions_set( 67 UniqueFunctionsSet functions_set(
71 isolate->object_store()->unique_dynamic_targets()); 68 isolate->object_store()->unique_dynamic_targets());
72 ASSERT(fname.IsSymbol()); 69 ASSERT(fname.IsSymbol());
73 *function = functions_set.GetOrNull(fname); 70 *function = functions_set.GetOrNull(fname);
74 ASSERT(functions_set.Release().raw() == 71 ASSERT(functions_set.Release().raw() ==
75 isolate->object_store()->unique_dynamic_targets()); 72 isolate->object_store()->unique_dynamic_targets());
76 } 73 }
77 74
78
79 AotOptimizer::AotOptimizer(Precompiler* precompiler, 75 AotOptimizer::AotOptimizer(Precompiler* precompiler,
80 FlowGraph* flow_graph, 76 FlowGraph* flow_graph,
81 bool use_speculative_inlining, 77 bool use_speculative_inlining,
82 GrowableArray<intptr_t>* inlining_black_list) 78 GrowableArray<intptr_t>* inlining_black_list)
83 : FlowGraphVisitor(flow_graph->reverse_postorder()), 79 : FlowGraphVisitor(flow_graph->reverse_postorder()),
84 precompiler_(precompiler), 80 precompiler_(precompiler),
85 flow_graph_(flow_graph), 81 flow_graph_(flow_graph),
86 use_speculative_inlining_(use_speculative_inlining), 82 use_speculative_inlining_(use_speculative_inlining),
87 inlining_black_list_(inlining_black_list), 83 inlining_black_list_(inlining_black_list),
88 has_unique_no_such_method_(false) { 84 has_unique_no_such_method_(false) {
89 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); 85 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL));
90 Function& target_function = Function::Handle(); 86 Function& target_function = Function::Handle();
91 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { 87 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) {
92 GetUniqueDynamicTarget(isolate(), Symbols::NoSuchMethod(), 88 GetUniqueDynamicTarget(isolate(), Symbols::NoSuchMethod(),
93 &target_function); 89 &target_function);
94 has_unique_no_such_method_ = !target_function.IsNull(); 90 has_unique_no_such_method_ = !target_function.IsNull();
95 } 91 }
96 } 92 }
97 93
98
99 // Optimize instance calls using ICData. 94 // Optimize instance calls using ICData.
100 void AotOptimizer::ApplyICData() { 95 void AotOptimizer::ApplyICData() {
101 VisitBlocks(); 96 VisitBlocks();
102 } 97 }
103 98
104
105 bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) { 99 bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) {
106 if ((precompiler_ == NULL) || !precompiler_->get_runtime_type_is_unique()) { 100 if ((precompiler_ == NULL) || !precompiler_->get_runtime_type_is_unique()) {
107 return false; 101 return false;
108 } 102 }
109 103
110 if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) { 104 if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) {
111 return false; 105 return false;
112 } 106 }
113 107
114 // There is only a single function Object.get:runtimeType that can be invoked 108 // There is only a single function Object.get:runtimeType that can be invoked
115 // by this call. Convert dynamic invocation to a static one. 109 // by this call. Convert dynamic invocation to a static one.
116 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); 110 const Class& cls = Class::Handle(Z, I->object_store()->object_class());
117 const Function& function = 111 const Function& function =
118 Function::Handle(Z, call->ResolveForReceiverClass(cls)); 112 Function::Handle(Z, call->ResolveForReceiverClass(cls));
119 ASSERT(!function.IsNull()); 113 ASSERT(!function.IsNull());
120 const Function& target = Function::ZoneHandle(Z, function.raw()); 114 const Function& target = Function::ZoneHandle(Z, function.raw());
121 StaticCallInstr* static_call = StaticCallInstr::FromCall(Z, call, target); 115 StaticCallInstr* static_call = StaticCallInstr::FromCall(Z, call, target);
122 static_call->set_result_cid(kTypeCid); 116 static_call->set_result_cid(kTypeCid);
123 call->ReplaceWith(static_call, current_iterator()); 117 call->ReplaceWith(static_call, current_iterator());
124 return true; 118 return true;
125 } 119 }
126 120
127
128 // Optimize instance calls using cid. This is called after optimizer 121 // Optimize instance calls using cid. This is called after optimizer
129 // converted instance calls to instructions. Any remaining 122 // converted instance calls to instructions. Any remaining
130 // instance calls are either megamorphic calls, cannot be optimized or 123 // instance calls are either megamorphic calls, cannot be optimized or
131 // have no runtime type feedback collected. 124 // have no runtime type feedback collected.
132 // Attempts to convert an instance call (IC call) using propagated class-ids, 125 // Attempts to convert an instance call (IC call) using propagated class-ids,
133 // e.g., receiver class id, guarded-cid, or by guessing cid-s. 126 // e.g., receiver class id, guarded-cid, or by guessing cid-s.
134 void AotOptimizer::ApplyClassIds() { 127 void AotOptimizer::ApplyClassIds() {
135 ASSERT(current_iterator_ == NULL); 128 ASSERT(current_iterator_ == NULL);
136 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 129 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
137 !block_it.Done(); block_it.Advance()) { 130 !block_it.Done(); block_it.Advance()) {
138 ForwardInstructionIterator it(block_it.Current()); 131 ForwardInstructionIterator it(block_it.Current());
139 current_iterator_ = &it; 132 current_iterator_ = &it;
140 for (; !it.Done(); it.Advance()) { 133 for (; !it.Done(); it.Advance()) {
141 Instruction* instr = it.Current(); 134 Instruction* instr = it.Current();
142 if (instr->IsInstanceCall()) { 135 if (instr->IsInstanceCall()) {
143 InstanceCallInstr* call = instr->AsInstanceCall(); 136 InstanceCallInstr* call = instr->AsInstanceCall();
144 if (call->HasICData()) { 137 if (call->HasICData()) {
145 if (TryCreateICData(call)) { 138 if (TryCreateICData(call)) {
146 VisitInstanceCall(call); 139 VisitInstanceCall(call);
147 } 140 }
148 } 141 }
149 } 142 }
150 } 143 }
151 current_iterator_ = NULL; 144 current_iterator_ = NULL;
152 } 145 }
153 } 146 }
154 147
155
156 // TODO(srdjan): Test/support other number types as well. 148 // TODO(srdjan): Test/support other number types as well.
157 static bool IsNumberCid(intptr_t cid) { 149 static bool IsNumberCid(intptr_t cid) {
158 return (cid == kSmiCid) || (cid == kDoubleCid); 150 return (cid == kSmiCid) || (cid == kDoubleCid);
159 } 151 }
160 152
161
162 bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) { 153 bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) {
163 ASSERT(call->HasICData()); 154 ASSERT(call->HasICData());
164 if (call->ic_data()->NumberOfUsedChecks() > 0) { 155 if (call->ic_data()->NumberOfUsedChecks() > 0) {
165 // This occurs when an instance call has too many checks, will be converted 156 // This occurs when an instance call has too many checks, will be converted
166 // to megamorphic call. 157 // to megamorphic call.
167 return false; 158 return false;
168 } 159 }
169 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); 160 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested());
170 const intptr_t receiver_idx = call->FirstParamIndex(); 161 const intptr_t receiver_idx = call->FirstParamIndex();
171 ASSERT(call->ic_data()->NumArgsTested() <= 162 ASSERT(call->ic_data()->NumArgsTested() <=
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 } 265 }
275 } 266 }
276 return true; 267 return true;
277 } 268 }
278 } 269 }
279 } 270 }
280 271
281 return false; 272 return false;
282 } 273 }
283 274
284
285 static bool ClassIdIsOneOf(intptr_t class_id, 275 static bool ClassIdIsOneOf(intptr_t class_id,
286 const GrowableArray<intptr_t>& class_ids) { 276 const GrowableArray<intptr_t>& class_ids) {
287 for (intptr_t i = 0; i < class_ids.length(); i++) { 277 for (intptr_t i = 0; i < class_ids.length(); i++) {
288 ASSERT(class_ids[i] != kIllegalCid); 278 ASSERT(class_ids[i] != kIllegalCid);
289 if (class_ids[i] == class_id) { 279 if (class_ids[i] == class_id) {
290 return true; 280 return true;
291 } 281 }
292 } 282 }
293 return false; 283 return false;
294 } 284 }
295 285
296
297 // Returns true if ICData tests two arguments and all ICData cids are in the 286 // Returns true if ICData tests two arguments and all ICData cids are in the
298 // required sets 'receiver_class_ids' or 'argument_class_ids', respectively. 287 // required sets 'receiver_class_ids' or 'argument_class_ids', respectively.
299 static bool ICDataHasOnlyReceiverArgumentClassIds( 288 static bool ICDataHasOnlyReceiverArgumentClassIds(
300 const ICData& ic_data, 289 const ICData& ic_data,
301 const GrowableArray<intptr_t>& receiver_class_ids, 290 const GrowableArray<intptr_t>& receiver_class_ids,
302 const GrowableArray<intptr_t>& argument_class_ids) { 291 const GrowableArray<intptr_t>& argument_class_ids) {
303 if (ic_data.NumArgsTested() != 2) { 292 if (ic_data.NumArgsTested() != 2) {
304 return false; 293 return false;
305 } 294 }
306 const intptr_t len = ic_data.NumberOfChecks(); 295 const intptr_t len = ic_data.NumberOfChecks();
307 GrowableArray<intptr_t> class_ids; 296 GrowableArray<intptr_t> class_ids;
308 for (intptr_t i = 0; i < len; i++) { 297 for (intptr_t i = 0; i < len; i++) {
309 if (ic_data.IsUsedAt(i)) { 298 if (ic_data.IsUsedAt(i)) {
310 ic_data.GetClassIdsAt(i, &class_ids); 299 ic_data.GetClassIdsAt(i, &class_ids);
311 ASSERT(class_ids.length() == 2); 300 ASSERT(class_ids.length() == 2);
312 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || 301 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) ||
313 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { 302 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) {
314 return false; 303 return false;
315 } 304 }
316 } 305 }
317 } 306 }
318 return true; 307 return true;
319 } 308 }
320 309
321
322 static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data, 310 static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data,
323 intptr_t receiver_class_id, 311 intptr_t receiver_class_id,
324 intptr_t argument_class_id) { 312 intptr_t argument_class_id) {
325 if (ic_data.NumArgsTested() != 2) { 313 if (ic_data.NumArgsTested() != 2) {
326 return false; 314 return false;
327 } 315 }
328 const intptr_t len = ic_data.NumberOfChecks(); 316 const intptr_t len = ic_data.NumberOfChecks();
329 for (intptr_t i = 0; i < len; i++) { 317 for (intptr_t i = 0; i < len; i++) {
330 if (ic_data.IsUsedAt(i)) { 318 if (ic_data.IsUsedAt(i)) {
331 GrowableArray<intptr_t> class_ids; 319 GrowableArray<intptr_t> class_ids;
332 ic_data.GetClassIdsAt(i, &class_ids); 320 ic_data.GetClassIdsAt(i, &class_ids);
333 ASSERT(class_ids.length() == 2); 321 ASSERT(class_ids.length() == 2);
334 if ((class_ids[0] == receiver_class_id) && 322 if ((class_ids[0] == receiver_class_id) &&
335 (class_ids[1] == argument_class_id)) { 323 (class_ids[1] == argument_class_id)) {
336 return true; 324 return true;
337 } 325 }
338 } 326 }
339 } 327 }
340 return false; 328 return false;
341 } 329 }
342 330
343
344 static bool HasOnlyOneSmi(const ICData& ic_data) { 331 static bool HasOnlyOneSmi(const ICData& ic_data) {
345 return (ic_data.NumberOfUsedChecks() == 1) && 332 return (ic_data.NumberOfUsedChecks() == 1) &&
346 ic_data.HasReceiverClassId(kSmiCid); 333 ic_data.HasReceiverClassId(kSmiCid);
347 } 334 }
348 335
349
350 static bool HasOnlySmiOrMint(const ICData& ic_data) { 336 static bool HasOnlySmiOrMint(const ICData& ic_data) {
351 if (ic_data.NumberOfUsedChecks() == 1) { 337 if (ic_data.NumberOfUsedChecks() == 1) {
352 return ic_data.HasReceiverClassId(kSmiCid) || 338 return ic_data.HasReceiverClassId(kSmiCid) ||
353 ic_data.HasReceiverClassId(kMintCid); 339 ic_data.HasReceiverClassId(kMintCid);
354 } 340 }
355 return (ic_data.NumberOfUsedChecks() == 2) && 341 return (ic_data.NumberOfUsedChecks() == 2) &&
356 ic_data.HasReceiverClassId(kSmiCid) && 342 ic_data.HasReceiverClassId(kSmiCid) &&
357 ic_data.HasReceiverClassId(kMintCid); 343 ic_data.HasReceiverClassId(kMintCid);
358 } 344 }
359 345
360
361 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) { 346 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
362 if (ic_data.NumberOfUsedChecks() != 1) { 347 if (ic_data.NumberOfUsedChecks() != 1) {
363 return false; 348 return false;
364 } 349 }
365 GrowableArray<intptr_t> first; 350 GrowableArray<intptr_t> first;
366 GrowableArray<intptr_t> second; 351 GrowableArray<intptr_t> second;
367 ic_data.GetUsedCidsForTwoArgs(&first, &second); 352 ic_data.GetUsedCidsForTwoArgs(&first, &second);
368 return (first[0] == cid) && (second[0] == cid); 353 return (first[0] == cid) && (second[0] == cid);
369 } 354 }
370 355
371 // Returns false if the ICData contains anything other than the 4 combinations 356 // Returns false if the ICData contains anything other than the 4 combinations
372 // of Mint and Smi for the receiver and argument classes. 357 // of Mint and Smi for the receiver and argument classes.
373 static bool HasTwoMintOrSmi(const ICData& ic_data) { 358 static bool HasTwoMintOrSmi(const ICData& ic_data) {
374 GrowableArray<intptr_t> first; 359 GrowableArray<intptr_t> first;
375 GrowableArray<intptr_t> second; 360 GrowableArray<intptr_t> second;
376 ic_data.GetUsedCidsForTwoArgs(&first, &second); 361 ic_data.GetUsedCidsForTwoArgs(&first, &second);
377 for (intptr_t i = 0; i < first.length(); i++) { 362 for (intptr_t i = 0; i < first.length(); i++) {
378 if ((first[i] != kSmiCid) && (first[i] != kMintCid)) { 363 if ((first[i] != kSmiCid) && (first[i] != kMintCid)) {
379 return false; 364 return false;
380 } 365 }
381 if ((second[i] != kSmiCid) && (second[i] != kMintCid)) { 366 if ((second[i] != kSmiCid) && (second[i] != kMintCid)) {
382 return false; 367 return false;
383 } 368 }
384 } 369 }
385 return true; 370 return true;
386 } 371 }
387 372
388
389 // Returns false if the ICData contains anything other than the 4 combinations 373 // Returns false if the ICData contains anything other than the 4 combinations
390 // of Double and Smi for the receiver and argument classes. 374 // of Double and Smi for the receiver and argument classes.
391 static bool HasTwoDoubleOrSmi(const ICData& ic_data) { 375 static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
392 GrowableArray<intptr_t> class_ids(2); 376 GrowableArray<intptr_t> class_ids(2);
393 class_ids.Add(kSmiCid); 377 class_ids.Add(kSmiCid);
394 class_ids.Add(kDoubleCid); 378 class_ids.Add(kDoubleCid);
395 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); 379 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
396 } 380 }
397 381
398
399 static bool HasOnlyOneDouble(const ICData& ic_data) { 382 static bool HasOnlyOneDouble(const ICData& ic_data) {
400 return (ic_data.NumberOfUsedChecks() == 1) && 383 return (ic_data.NumberOfUsedChecks() == 1) &&
401 ic_data.HasReceiverClassId(kDoubleCid); 384 ic_data.HasReceiverClassId(kDoubleCid);
402 } 385 }
403 386
404
405 static bool ShouldSpecializeForDouble(const ICData& ic_data) { 387 static bool ShouldSpecializeForDouble(const ICData& ic_data) {
406 // Don't specialize for double if we can't unbox them. 388 // Don't specialize for double if we can't unbox them.
407 if (!CanUnboxDouble()) { 389 if (!CanUnboxDouble()) {
408 return false; 390 return false;
409 } 391 }
410 392
411 // Unboxed double operation can't handle case of two smis. 393 // Unboxed double operation can't handle case of two smis.
412 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 394 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
413 return false; 395 return false;
414 } 396 }
415 397
416 // Check that it have seen only smis and doubles. 398 // Check that it have seen only smis and doubles.
417 return HasTwoDoubleOrSmi(ic_data); 399 return HasTwoDoubleOrSmi(ic_data);
418 } 400 }
419 401
420
421 void AotOptimizer::ReplaceCall(Definition* call, Definition* replacement) { 402 void AotOptimizer::ReplaceCall(Definition* call, Definition* replacement) {
422 // Remove the original push arguments. 403 // Remove the original push arguments.
423 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 404 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
424 PushArgumentInstr* push = call->PushArgumentAt(i); 405 PushArgumentInstr* push = call->PushArgumentAt(i);
425 push->ReplaceUsesWith(push->value()->definition()); 406 push->ReplaceUsesWith(push->value()->definition());
426 push->RemoveFromGraph(); 407 push->RemoveFromGraph();
427 } 408 }
428 call->ReplaceWith(replacement, current_iterator()); 409 call->ReplaceWith(replacement, current_iterator());
429 } 410 }
430 411
431
432 void AotOptimizer::AddCheckSmi(Definition* to_check, 412 void AotOptimizer::AddCheckSmi(Definition* to_check,
433 intptr_t deopt_id, 413 intptr_t deopt_id,
434 Environment* deopt_environment, 414 Environment* deopt_environment,
435 Instruction* insert_before) { 415 Instruction* insert_before) {
436 if (to_check->Type()->ToCid() != kSmiCid) { 416 if (to_check->Type()->ToCid() != kSmiCid) {
437 InsertBefore(insert_before, 417 InsertBefore(insert_before,
438 new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, 418 new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id,
439 insert_before->token_pos()), 419 insert_before->token_pos()),
440 deopt_environment, FlowGraph::kEffect); 420 deopt_environment, FlowGraph::kEffect);
441 } 421 }
442 } 422 }
443 423
444
445 void AotOptimizer::AddCheckClass(Definition* to_check, 424 void AotOptimizer::AddCheckClass(Definition* to_check,
446 const Cids& cids, 425 const Cids& cids,
447 intptr_t deopt_id, 426 intptr_t deopt_id,
448 Environment* deopt_environment, 427 Environment* deopt_environment,
449 Instruction* insert_before) { 428 Instruction* insert_before) {
450 // Type propagation has not run yet, we cannot eliminate the check. 429 // Type propagation has not run yet, we cannot eliminate the check.
451 Instruction* check = flow_graph_->CreateCheckClass( 430 Instruction* check = flow_graph_->CreateCheckClass(
452 to_check, cids, deopt_id, insert_before->token_pos()); 431 to_check, cids, deopt_id, insert_before->token_pos());
453 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); 432 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect);
454 } 433 }
455 434
456
457 void AotOptimizer::AddChecksForArgNr(InstanceCallInstr* call, 435 void AotOptimizer::AddChecksForArgNr(InstanceCallInstr* call,
458 Definition* instr, 436 Definition* instr,
459 int argument_number) { 437 int argument_number) {
460 const Cids* cids = Cids::Create(Z, *call->ic_data(), argument_number); 438 const Cids* cids = Cids::Create(Z, *call->ic_data(), argument_number);
461 AddCheckClass(instr, *cids, call->deopt_id(), call->env(), call); 439 AddCheckClass(instr, *cids, call->deopt_id(), call->env(), call);
462 } 440 }
463 441
464
465 static bool ArgIsAlways(intptr_t cid, 442 static bool ArgIsAlways(intptr_t cid,
466 const ICData& ic_data, 443 const ICData& ic_data,
467 intptr_t arg_number) { 444 intptr_t arg_number) {
468 ASSERT(ic_data.NumArgsTested() > arg_number); 445 ASSERT(ic_data.NumArgsTested() > arg_number);
469 if (ic_data.NumberOfUsedChecks() == 0) { 446 if (ic_data.NumberOfUsedChecks() == 0) {
470 return false; 447 return false;
471 } 448 }
472 const intptr_t num_checks = ic_data.NumberOfChecks(); 449 const intptr_t num_checks = ic_data.NumberOfChecks();
473 for (intptr_t i = 0; i < num_checks; i++) { 450 for (intptr_t i = 0; i < num_checks; i++) {
474 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { 451 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) {
475 return false; 452 return false;
476 } 453 }
477 } 454 }
478 return true; 455 return true;
479 } 456 }
480 457
481
482 bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call, 458 bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call,
483 const ICData* unary_checks) { 459 const ICData* unary_checks) {
484 // Check for monomorphic IC data. 460 // Check for monomorphic IC data.
485 ASSERT(unary_checks->NumberOfChecks() > 0); 461 ASSERT(unary_checks->NumberOfChecks() > 0);
486 if (unary_checks->NumberOfChecksIs(1)) { 462 if (unary_checks->NumberOfChecksIs(1)) {
487 return false; 463 return false;
488 } 464 }
489 return FlowGraphInliner::TryReplaceInstanceCallWithInline( 465 return FlowGraphInliner::TryReplaceInstanceCallWithInline(
490 flow_graph_, current_iterator(), call); 466 flow_graph_, current_iterator(), call);
491 } 467 }
492 468
493
494 // Return true if d is a string of length one (a constant or result from 469 // Return true if d is a string of length one (a constant or result from
495 // from string-from-char-code instruction. 470 // from string-from-char-code instruction.
496 static bool IsLengthOneString(Definition* d) { 471 static bool IsLengthOneString(Definition* d) {
497 if (d->IsConstant()) { 472 if (d->IsConstant()) {
498 const Object& obj = d->AsConstant()->value(); 473 const Object& obj = d->AsConstant()->value();
499 if (obj.IsString()) { 474 if (obj.IsString()) {
500 return String::Cast(obj).Length() == 1; 475 return String::Cast(obj).Length() == 1;
501 } else { 476 } else {
502 return false; 477 return false;
503 } 478 }
504 } else { 479 } else {
505 return d->IsOneByteStringFromCharCode(); 480 return d->IsOneByteStringFromCharCode();
506 } 481 }
507 } 482 }
508 483
509
510 // Returns true if the string comparison was converted into char-code 484 // Returns true if the string comparison was converted into char-code
511 // comparison. Conversion is only possible for strings of length one. 485 // comparison. Conversion is only possible for strings of length one.
512 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. 486 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes.
513 // TODO(srdjan): Expand for two-byte and external strings. 487 // TODO(srdjan): Expand for two-byte and external strings.
514 bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, 488 bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call,
515 Token::Kind op_kind) { 489 Token::Kind op_kind) {
516 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); 490 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid));
517 // Check that left and right are length one strings (either string constants 491 // Check that left and right are length one strings (either string constants
518 // or results of string-from-char-code. 492 // or results of string-from-char-code.
519 Definition* left = call->ArgumentAt(0); 493 Definition* left = call->ArgumentAt(0);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 if ((to_remove_right != NULL) && 554 if ((to_remove_right != NULL) &&
581 (to_remove_right->input_use_list() == NULL)) { 555 (to_remove_right->input_use_list() == NULL)) {
582 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null()); 556 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null());
583 to_remove_right->RemoveFromGraph(); 557 to_remove_right->RemoveFromGraph();
584 } 558 }
585 return true; 559 return true;
586 } 560 }
587 return false; 561 return false;
588 } 562 }
589 563
590
591 static bool SmiFitsInDouble() { 564 static bool SmiFitsInDouble() {
592 return kSmiBits < 53; 565 return kSmiBits < 53;
593 } 566 }
594 567
595
596 static bool IsGetRuntimeType(Definition* defn) { 568 static bool IsGetRuntimeType(Definition* defn) {
597 StaticCallInstr* call = defn->AsStaticCall(); 569 StaticCallInstr* call = defn->AsStaticCall();
598 return (call != NULL) && (call->function().recognized_kind() == 570 return (call != NULL) && (call->function().recognized_kind() ==
599 MethodRecognizer::kObjectRuntimeType); 571 MethodRecognizer::kObjectRuntimeType);
600 } 572 }
601 573
602
603 // Recognize a.runtimeType == b.runtimeType and fold it into 574 // Recognize a.runtimeType == b.runtimeType and fold it into
604 // Object._haveSameRuntimeType(a, b). 575 // Object._haveSameRuntimeType(a, b).
605 // Note: this optimization is not speculative. 576 // Note: this optimization is not speculative.
606 bool AotOptimizer::TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call) { 577 bool AotOptimizer::TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call) {
607 const ICData& ic_data = *call->ic_data(); 578 const ICData& ic_data = *call->ic_data();
608 ASSERT(ic_data.NumArgsTested() == 2); 579 ASSERT(ic_data.NumArgsTested() == 2);
609 580
610 ASSERT(call->type_args_len() == 0); 581 ASSERT(call->type_args_len() == 0);
611 ASSERT(call->ArgumentCount() == 2); 582 ASSERT(call->ArgumentCount() == 2);
612 Definition* left = call->ArgumentAt(0); 583 Definition* left = call->ArgumentAt(0);
(...skipping 23 matching lines...) Expand all
636 Object::null_array(), // argument_names 607 Object::null_array(), // argument_names
637 args, call->deopt_id(), call->CallCount()); 608 args, call->deopt_id(), call->CallCount());
638 static_call->set_result_cid(kBoolCid); 609 static_call->set_result_cid(kBoolCid);
639 ReplaceCall(call, static_call); 610 ReplaceCall(call, static_call);
640 return true; 611 return true;
641 } 612 }
642 613
643 return false; 614 return false;
644 } 615 }
645 616
646
647 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, 617 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
648 Token::Kind op_kind) { 618 Token::Kind op_kind) {
649 const ICData& ic_data = *call->ic_data(); 619 const ICData& ic_data = *call->ic_data();
650 ASSERT(ic_data.NumArgsTested() == 2); 620 ASSERT(ic_data.NumArgsTested() == 2);
651 621
652 ASSERT(call->type_args_len() == 0); 622 ASSERT(call->type_args_len() == 0);
653 ASSERT(call->ArgumentCount() == 2); 623 ASSERT(call->ArgumentCount() == 2);
654 Definition* const left = call->ArgumentAt(0); 624 Definition* const left = call->ArgumentAt(0);
655 Definition* const right = call->ArgumentAt(1); 625 Definition* const right = call->ArgumentAt(1);
656 626
(...skipping 16 matching lines...) Expand all
673 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { 643 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
674 // Use double comparison. 644 // Use double comparison.
675 if (SmiFitsInDouble()) { 645 if (SmiFitsInDouble()) {
676 cid = kDoubleCid; 646 cid = kDoubleCid;
677 } else { 647 } else {
678 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 648 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
679 // We cannot use double comparison on two smis. Need polymorphic 649 // We cannot use double comparison on two smis. Need polymorphic
680 // call. 650 // call.
681 return false; 651 return false;
682 } else { 652 } else {
683 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left), 653 InsertBefore(
684 new (Z) Value(right), 654 call,
685 call->deopt_id()), 655 new (Z) CheckEitherNonSmiInstr(
686 call->env(), FlowGraph::kEffect); 656 new (Z) Value(left), new (Z) Value(right), call->deopt_id()),
657 call->env(), FlowGraph::kEffect);
687 cid = kDoubleCid; 658 cid = kDoubleCid;
688 } 659 }
689 } 660 }
690 } else { 661 } else {
691 // Check if ICDData contains checks with Smi/Null combinations. In that case 662 // Check if ICDData contains checks with Smi/Null combinations. In that case
692 // we can still emit the optimized Smi equality operation but need to add 663 // we can still emit the optimized Smi equality operation but need to add
693 // checks for null or Smi. 664 // checks for null or Smi.
694 GrowableArray<intptr_t> smi_or_null(2); 665 GrowableArray<intptr_t> smi_or_null(2);
695 smi_or_null.Add(kSmiCid); 666 smi_or_null.Add(kSmiCid);
696 smi_or_null.Add(kNullCid); 667 smi_or_null.Add(kNullCid);
(...skipping 22 matching lines...) Expand all
719 } 690 }
720 } 691 }
721 ASSERT(cid != kIllegalCid); 692 ASSERT(cid != kIllegalCid);
722 EqualityCompareInstr* comp = new (Z) 693 EqualityCompareInstr* comp = new (Z)
723 EqualityCompareInstr(call->token_pos(), op_kind, new (Z) Value(left), 694 EqualityCompareInstr(call->token_pos(), op_kind, new (Z) Value(left),
724 new (Z) Value(right), cid, call->deopt_id()); 695 new (Z) Value(right), cid, call->deopt_id());
725 ReplaceCall(call, comp); 696 ReplaceCall(call, comp);
726 return true; 697 return true;
727 } 698 }
728 699
729
730 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, 700 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
731 Token::Kind op_kind) { 701 Token::Kind op_kind) {
732 const ICData& ic_data = *call->ic_data(); 702 const ICData& ic_data = *call->ic_data();
733 ASSERT(ic_data.NumArgsTested() == 2); 703 ASSERT(ic_data.NumArgsTested() == 2);
734 704
735 ASSERT(call->type_args_len() == 0); 705 ASSERT(call->type_args_len() == 0);
736 ASSERT(call->ArgumentCount() == 2); 706 ASSERT(call->ArgumentCount() == 2);
737 Definition* left = call->ArgumentAt(0); 707 Definition* left = call->ArgumentAt(0);
738 Definition* right = call->ArgumentAt(1); 708 Definition* right = call->ArgumentAt(1);
739 709
(...skipping 14 matching lines...) Expand all
754 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { 724 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
755 // Use double comparison. 725 // Use double comparison.
756 if (SmiFitsInDouble()) { 726 if (SmiFitsInDouble()) {
757 cid = kDoubleCid; 727 cid = kDoubleCid;
758 } else { 728 } else {
759 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 729 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
760 // We cannot use double comparison on two smis. Need polymorphic 730 // We cannot use double comparison on two smis. Need polymorphic
761 // call. 731 // call.
762 return false; 732 return false;
763 } else { 733 } else {
764 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left), 734 InsertBefore(
765 new (Z) Value(right), 735 call,
766 call->deopt_id()), 736 new (Z) CheckEitherNonSmiInstr(
767 call->env(), FlowGraph::kEffect); 737 new (Z) Value(left), new (Z) Value(right), call->deopt_id()),
738 call->env(), FlowGraph::kEffect);
768 cid = kDoubleCid; 739 cid = kDoubleCid;
769 } 740 }
770 } 741 }
771 } else { 742 } else {
772 return false; 743 return false;
773 } 744 }
774 ASSERT(cid != kIllegalCid); 745 ASSERT(cid != kIllegalCid);
775 RelationalOpInstr* comp = 746 RelationalOpInstr* comp =
776 new (Z) RelationalOpInstr(call->token_pos(), op_kind, new (Z) Value(left), 747 new (Z) RelationalOpInstr(call->token_pos(), op_kind, new (Z) Value(left),
777 new (Z) Value(right), cid, call->deopt_id()); 748 new (Z) Value(right), cid, call->deopt_id());
778 ReplaceCall(call, comp); 749 ReplaceCall(call, comp);
779 return true; 750 return true;
780 } 751 }
781 752
782
783 bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, 753 bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
784 Token::Kind op_kind) { 754 Token::Kind op_kind) {
785 intptr_t operands_type = kIllegalCid; 755 intptr_t operands_type = kIllegalCid;
786 ASSERT(call->HasICData()); 756 ASSERT(call->HasICData());
787 const ICData& ic_data = *call->ic_data(); 757 const ICData& ic_data = *call->ic_data();
788 switch (op_kind) { 758 switch (op_kind) {
789 case Token::kADD: 759 case Token::kADD:
790 case Token::kSUB: 760 case Token::kSUB:
791 case Token::kMUL: 761 case Token::kMUL:
792 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 762 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
887 Definition* left = call->ArgumentAt(0); 857 Definition* left = call->ArgumentAt(0);
888 Definition* right = call->ArgumentAt(1); 858 Definition* right = call->ArgumentAt(1);
889 if (operands_type == kDoubleCid) { 859 if (operands_type == kDoubleCid) {
890 if (!CanUnboxDouble()) { 860 if (!CanUnboxDouble()) {
891 return false; 861 return false;
892 } 862 }
893 // Check that either left or right are not a smi. Result of a 863 // Check that either left or right are not a smi. Result of a
894 // binary operation with two smis is a smi not a double, except '/' which 864 // binary operation with two smis is a smi not a double, except '/' which
895 // returns a double for two smis. 865 // returns a double for two smis.
896 if (op_kind != Token::kDIV) { 866 if (op_kind != Token::kDIV) {
897 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left), 867 InsertBefore(
898 new (Z) Value(right), 868 call,
899 call->deopt_id()), 869 new (Z) CheckEitherNonSmiInstr(
900 call->env(), FlowGraph::kEffect); 870 new (Z) Value(left), new (Z) Value(right), call->deopt_id()),
871 call->env(), FlowGraph::kEffect);
901 } 872 }
902 873
903 BinaryDoubleOpInstr* double_bin_op = new (Z) 874 BinaryDoubleOpInstr* double_bin_op = new (Z)
904 BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right), 875 BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right),
905 call->deopt_id(), call->token_pos()); 876 call->deopt_id(), call->token_pos());
906 ReplaceCall(call, double_bin_op); 877 ReplaceCall(call, double_bin_op);
907 } else if (operands_type == kMintCid) { 878 } else if (operands_type == kMintCid) {
908 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; 879 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false;
909 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { 880 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
910 ShiftMintOpInstr* shift_op = new (Z) ShiftMintOpInstr( 881 ShiftMintOpInstr* shift_op = new (Z) ShiftMintOpInstr(
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
961 left = right; 932 left = right;
962 right = temp; 933 right = temp;
963 } 934 }
964 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr( 935 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr(
965 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); 936 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
966 ReplaceCall(call, bin_op); 937 ReplaceCall(call, bin_op);
967 } 938 }
968 return true; 939 return true;
969 } 940 }
970 941
971
972 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, 942 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
973 Token::Kind op_kind) { 943 Token::Kind op_kind) {
974 ASSERT(call->type_args_len() == 0); 944 ASSERT(call->type_args_len() == 0);
975 ASSERT(call->ArgumentCount() == 1); 945 ASSERT(call->ArgumentCount() == 1);
976 Definition* input = call->ArgumentAt(0); 946 Definition* input = call->ArgumentAt(0);
977 Definition* unary_op = NULL; 947 Definition* unary_op = NULL;
978 if (HasOnlyOneSmi(*call->ic_data())) { 948 if (HasOnlyOneSmi(*call->ic_data())) {
979 InsertBefore(call, 949 InsertBefore(call,
980 new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(), 950 new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(),
981 call->token_pos()), 951 call->token_pos()),
(...skipping 11 matching lines...) Expand all
993 unary_op = new (Z) UnaryDoubleOpInstr(Token::kNEGATE, new (Z) Value(input), 963 unary_op = new (Z) UnaryDoubleOpInstr(Token::kNEGATE, new (Z) Value(input),
994 call->deopt_id()); 964 call->deopt_id());
995 } else { 965 } else {
996 return false; 966 return false;
997 } 967 }
998 ASSERT(unary_op != NULL); 968 ASSERT(unary_op != NULL);
999 ReplaceCall(call, unary_op); 969 ReplaceCall(call, unary_op);
1000 return true; 970 return true;
1001 } 971 }
1002 972
1003
1004 // Using field class 973 // Using field class
1005 RawField* AotOptimizer::GetField(intptr_t class_id, const String& field_name) { 974 RawField* AotOptimizer::GetField(intptr_t class_id, const String& field_name) {
1006 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); 975 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
1007 Field& field = Field::Handle(Z); 976 Field& field = Field::Handle(Z);
1008 while (!cls.IsNull()) { 977 while (!cls.IsNull()) {
1009 field = cls.LookupInstanceField(field_name); 978 field = cls.LookupInstanceField(field_name);
1010 if (!field.IsNull()) { 979 if (!field.IsNull()) {
1011 return field.raw(); 980 return field.raw();
1012 } 981 }
1013 cls = cls.SuperClass(); 982 cls = cls.SuperClass();
1014 } 983 }
1015 return Field::null(); 984 return Field::null();
1016 } 985 }
1017 986
1018
1019 bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { 987 bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
1020 ASSERT(call->HasICData()); 988 ASSERT(call->HasICData());
1021 const ICData& ic_data = *call->ic_data(); 989 const ICData& ic_data = *call->ic_data();
1022 ASSERT(ic_data.HasOneTarget()); 990 ASSERT(ic_data.HasOneTarget());
1023 GrowableArray<intptr_t> class_ids; 991 GrowableArray<intptr_t> class_ids;
1024 ic_data.GetClassIdsAt(0, &class_ids); 992 ic_data.GetClassIdsAt(0, &class_ids);
1025 ASSERT(class_ids.length() == 1); 993 ASSERT(class_ids.length() == 1);
1026 // Inline implicit instance getter. 994 // Inline implicit instance getter.
1027 const String& field_name = 995 const String& field_name =
1028 String::Handle(Z, Field::NameFromGetter(call->function_name())); 996 String::Handle(Z, Field::NameFromGetter(call->function_name()));
(...skipping 16 matching lines...) Expand all
1045 1013
1046 if (load->result_cid() != kDynamicCid) { 1014 if (load->result_cid() != kDynamicCid) {
1047 // Reset value types if guarded_cid was used. 1015 // Reset value types if guarded_cid was used.
1048 for (Value::Iterator it(load->input_use_list()); !it.Done(); it.Advance()) { 1016 for (Value::Iterator it(load->input_use_list()); !it.Done(); it.Advance()) {
1049 it.Current()->SetReachingType(NULL); 1017 it.Current()->SetReachingType(NULL);
1050 } 1018 }
1051 } 1019 }
1052 return true; 1020 return true;
1053 } 1021 }
1054 1022
1055
1056 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, 1023 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
1057 Token::Kind op_kind) { 1024 Token::Kind op_kind) {
1058 if (!ShouldInlineSimd()) { 1025 if (!ShouldInlineSimd()) {
1059 return false; 1026 return false;
1060 } 1027 }
1061 ASSERT(call->type_args_len() == 0); 1028 ASSERT(call->type_args_len() == 0);
1062 ASSERT(call->ArgumentCount() == 2); 1029 ASSERT(call->ArgumentCount() == 2);
1063 Definition* const left = call->ArgumentAt(0); 1030 Definition* const left = call->ArgumentAt(0);
1064 Definition* const right = call->ArgumentAt(1); 1031 Definition* const right = call->ArgumentAt(1);
1065 // Type check left and right. 1032 // Type check left and right.
1066 AddChecksForArgNr(call, left, /* arg_number = */ 0); 1033 AddChecksForArgNr(call, left, /* arg_number = */ 0);
1067 AddChecksForArgNr(call, right, /* arg_number = */ 1); 1034 AddChecksForArgNr(call, right, /* arg_number = */ 1);
1068 // Replace call. 1035 // Replace call.
1069 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr( 1036 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr(
1070 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); 1037 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1071 ReplaceCall(call, float32x4_bin_op); 1038 ReplaceCall(call, float32x4_bin_op);
1072 1039
1073 return true; 1040 return true;
1074 } 1041 }
1075 1042
1076
1077 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, 1043 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
1078 Token::Kind op_kind) { 1044 Token::Kind op_kind) {
1079 if (!ShouldInlineSimd()) { 1045 if (!ShouldInlineSimd()) {
1080 return false; 1046 return false;
1081 } 1047 }
1082 ASSERT(call->type_args_len() == 0); 1048 ASSERT(call->type_args_len() == 0);
1083 ASSERT(call->ArgumentCount() == 2); 1049 ASSERT(call->ArgumentCount() == 2);
1084 Definition* const left = call->ArgumentAt(0); 1050 Definition* const left = call->ArgumentAt(0);
1085 Definition* const right = call->ArgumentAt(1); 1051 Definition* const right = call->ArgumentAt(1);
1086 // Type check left and right. 1052 // Type check left and right.
1087 AddChecksForArgNr(call, left, /* arg_number = */ 0); 1053 AddChecksForArgNr(call, left, /* arg_number = */ 0);
1088 AddChecksForArgNr(call, right, /* arg_number = */ 1); 1054 AddChecksForArgNr(call, right, /* arg_number = */ 1);
1089 // Replace call. 1055 // Replace call.
1090 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr( 1056 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr(
1091 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); 1057 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1092 ReplaceCall(call, int32x4_bin_op); 1058 ReplaceCall(call, int32x4_bin_op);
1093 return true; 1059 return true;
1094 } 1060 }
1095 1061
1096
1097 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, 1062 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
1098 Token::Kind op_kind) { 1063 Token::Kind op_kind) {
1099 if (!ShouldInlineSimd()) { 1064 if (!ShouldInlineSimd()) {
1100 return false; 1065 return false;
1101 } 1066 }
1102 ASSERT(call->type_args_len() == 0); 1067 ASSERT(call->type_args_len() == 0);
1103 ASSERT(call->ArgumentCount() == 2); 1068 ASSERT(call->ArgumentCount() == 2);
1104 Definition* const left = call->ArgumentAt(0); 1069 Definition* const left = call->ArgumentAt(0);
1105 Definition* const right = call->ArgumentAt(1); 1070 Definition* const right = call->ArgumentAt(1);
1106 // Type check left and right. 1071 // Type check left and right.
1107 AddChecksForArgNr(call, left, /* arg_number = */ 0); 1072 AddChecksForArgNr(call, left, /* arg_number = */ 0);
1108 AddChecksForArgNr(call, right, /* arg_number = */ 1); 1073 AddChecksForArgNr(call, right, /* arg_number = */ 1);
1109 // Replace call. 1074 // Replace call.
1110 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr( 1075 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr(
1111 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); 1076 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1112 ReplaceCall(call, float64x2_bin_op); 1077 ReplaceCall(call, float64x2_bin_op);
1113 return true; 1078 return true;
1114 } 1079 }
1115 1080
1116
1117 // Only unique implicit instance getters can be currently handled. 1081 // Only unique implicit instance getters can be currently handled.
1118 bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { 1082 bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
1119 ASSERT(call->HasICData()); 1083 ASSERT(call->HasICData());
1120 const ICData& ic_data = *call->ic_data(); 1084 const ICData& ic_data = *call->ic_data();
1121 if (ic_data.NumberOfUsedChecks() == 0) { 1085 if (ic_data.NumberOfUsedChecks() == 0) {
1122 // No type feedback collected. 1086 // No type feedback collected.
1123 return false; 1087 return false;
1124 } 1088 }
1125 1089
1126 if (!ic_data.HasOneTarget()) { 1090 if (!ic_data.HasOneTarget()) {
1127 // Polymorphic sites are inlined like normal methods by conventional 1091 // Polymorphic sites are inlined like normal methods by conventional
1128 // inlining in FlowGraphInliner. 1092 // inlining in FlowGraphInliner.
1129 return false; 1093 return false;
1130 } 1094 }
1131 1095
1132 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); 1096 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0));
1133 if (target.kind() != RawFunction::kImplicitGetter) { 1097 if (target.kind() != RawFunction::kImplicitGetter) {
1134 // Non-implicit getters are inlined like normal methods by conventional 1098 // Non-implicit getters are inlined like normal methods by conventional
1135 // inlining in FlowGraphInliner. 1099 // inlining in FlowGraphInliner.
1136 return false; 1100 return false;
1137 } 1101 }
1138 return InlineImplicitInstanceGetter(call); 1102 return InlineImplicitInstanceGetter(call);
1139 } 1103 }
1140 1104
1141
1142 void AotOptimizer::ReplaceWithMathCFunction( 1105 void AotOptimizer::ReplaceWithMathCFunction(
1143 InstanceCallInstr* call, 1106 InstanceCallInstr* call,
1144 MethodRecognizer::Kind recognized_kind) { 1107 MethodRecognizer::Kind recognized_kind) {
1145 ASSERT(call->type_args_len() == 0); 1108 ASSERT(call->type_args_len() == 0);
1146 AddReceiverCheck(call); 1109 AddReceiverCheck(call);
1147 ZoneGrowableArray<Value*>* args = 1110 ZoneGrowableArray<Value*>* args =
1148 new (Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); 1111 new (Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
1149 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { 1112 for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
1150 args->Add(new (Z) Value(call->ArgumentAt(i))); 1113 args->Add(new (Z) Value(call->ArgumentAt(i)));
1151 } 1114 }
1152 InvokeMathCFunctionInstr* invoke = new (Z) InvokeMathCFunctionInstr( 1115 InvokeMathCFunctionInstr* invoke = new (Z) InvokeMathCFunctionInstr(
1153 args, call->deopt_id(), recognized_kind, call->token_pos()); 1116 args, call->deopt_id(), recognized_kind, call->token_pos());
1154 ReplaceCall(call, invoke); 1117 ReplaceCall(call, invoke);
1155 } 1118 }
1156 1119
1157
1158 // Inline only simple, frequently called core library methods. 1120 // Inline only simple, frequently called core library methods.
1159 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { 1121 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
1160 ASSERT(call->HasICData()); 1122 ASSERT(call->HasICData());
1161 const ICData& ic_data = *call->ic_data(); 1123 const ICData& ic_data = *call->ic_data();
1162 if (ic_data.NumberOfUsedChecks() != 1) { 1124 if (ic_data.NumberOfUsedChecks() != 1) {
1163 // No type feedback collected or multiple receivers/targets found. 1125 // No type feedback collected or multiple receivers/targets found.
1164 return false; 1126 return false;
1165 } 1127 }
1166 1128
1167 Function& target = Function::Handle(Z); 1129 Function& target = Function::Handle(Z);
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1228 return true; 1190 return true;
1229 default: 1191 default:
1230 break; 1192 break;
1231 } 1193 }
1232 } 1194 }
1233 1195
1234 return FlowGraphInliner::TryReplaceInstanceCallWithInline( 1196 return FlowGraphInliner::TryReplaceInstanceCallWithInline(
1235 flow_graph_, current_iterator(), call); 1197 flow_graph_, current_iterator(), call);
1236 } 1198 }
1237 1199
1238
1239 // If type tests specified by 'ic_data' do not depend on type arguments, 1200 // If type tests specified by 'ic_data' do not depend on type arguments,
1240 // return mapping cid->result in 'results' (i : cid; i + 1: result). 1201 // return mapping cid->result in 'results' (i : cid; i + 1: result).
1241 // If all tests yield the same result, return it otherwise return Bool::null. 1202 // If all tests yield the same result, return it otherwise return Bool::null.
1242 // If no mapping is possible, 'results' has less than 1203 // If no mapping is possible, 'results' has less than
1243 // (ic_data.NumberOfChecks() * 2) entries 1204 // (ic_data.NumberOfChecks() * 2) entries
1244 // An instance-of test returning all same results can be converted to a class 1205 // An instance-of test returning all same results can be converted to a class
1245 // check. 1206 // check.
1246 RawBool* AotOptimizer::InstanceOfAsBool( 1207 RawBool* AotOptimizer::InstanceOfAsBool(
1247 const ICData& ic_data, 1208 const ICData& ic_data,
1248 const AbstractType& type, 1209 const AbstractType& type,
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1296 prev = Bool::Get(is_subtype).raw(); 1257 prev = Bool::Get(is_subtype).raw();
1297 } else { 1258 } else {
1298 if (is_subtype != prev.value()) { 1259 if (is_subtype != prev.value()) {
1299 results_differ = true; 1260 results_differ = true;
1300 } 1261 }
1301 } 1262 }
1302 } 1263 }
1303 return results_differ ? Bool::null() : prev.raw(); 1264 return results_differ ? Bool::null() : prev.raw();
1304 } 1265 }
1305 1266
1306
1307 // Returns true if checking against this type is a direct class id comparison. 1267 // Returns true if checking against this type is a direct class id comparison.
1308 bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { 1268 bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
1309 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); 1269 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
1310 // Requires CHA. 1270 // Requires CHA.
1311 if (!type.IsInstantiated()) return false; 1271 if (!type.IsInstantiated()) return false;
1312 // Function types have different type checking rules. 1272 // Function types have different type checking rules.
1313 if (type.IsFunctionType()) return false; 1273 if (type.IsFunctionType()) return false;
1314 const Class& type_class = Class::Handle(type.type_class()); 1274 const Class& type_class = Class::Handle(type.type_class());
1315 // Could be an interface check? 1275 // Could be an interface check?
1316 if (CHA::IsImplemented(type_class)) return false; 1276 if (CHA::IsImplemented(type_class)) return false;
(...skipping 24 matching lines...) Expand all
1341 const intptr_t from_index = num_type_args - num_type_params; 1301 const intptr_t from_index = num_type_args - num_type_params;
1342 const TypeArguments& type_arguments = 1302 const TypeArguments& type_arguments =
1343 TypeArguments::Handle(type.arguments()); 1303 TypeArguments::Handle(type.arguments());
1344 const bool is_raw_type = type_arguments.IsNull() || 1304 const bool is_raw_type = type_arguments.IsNull() ||
1345 type_arguments.IsRaw(from_index, num_type_params); 1305 type_arguments.IsRaw(from_index, num_type_params);
1346 return is_raw_type; 1306 return is_raw_type;
1347 } 1307 }
1348 return true; 1308 return true;
1349 } 1309 }
1350 1310
1351
1352 // TODO(srdjan): Use ICData to check if always true or false. 1311 // TODO(srdjan): Use ICData to check if always true or false.
1353 void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { 1312 void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
1354 ASSERT(Token::IsTypeTestOperator(call->token_kind())); 1313 ASSERT(Token::IsTypeTestOperator(call->token_kind()));
1355 Definition* left = call->ArgumentAt(0); 1314 Definition* left = call->ArgumentAt(0);
1356 Definition* instantiator_type_args = NULL; 1315 Definition* instantiator_type_args = NULL;
1357 Definition* function_type_args = NULL; 1316 Definition* function_type_args = NULL;
1358 AbstractType& type = AbstractType::ZoneHandle(Z); 1317 AbstractType& type = AbstractType::ZoneHandle(Z);
1359 ASSERT(call->type_args_len() == 0); 1318 ASSERT(call->type_args_len() == 0);
1360 if (call->ArgumentCount() == 2) { 1319 if (call->ArgumentCount() == 2) {
1361 instantiator_type_args = flow_graph()->constant_null(); 1320 instantiator_type_args = flow_graph()->constant_null();
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1459 } 1418 }
1460 } 1419 }
1461 1420
1462 InstanceOfInstr* instance_of = new (Z) InstanceOfInstr( 1421 InstanceOfInstr* instance_of = new (Z) InstanceOfInstr(
1463 call->token_pos(), new (Z) Value(left), 1422 call->token_pos(), new (Z) Value(left),
1464 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), 1423 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args),
1465 type, call->deopt_id()); 1424 type, call->deopt_id());
1466 ReplaceCall(call, instance_of); 1425 ReplaceCall(call, instance_of);
1467 } 1426 }
1468 1427
1469
1470 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). 1428 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
1471 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { 1429 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
1472 ASSERT(Token::IsTypeCastOperator(call->token_kind())); 1430 ASSERT(Token::IsTypeCastOperator(call->token_kind()));
1473 ASSERT(call->type_args_len() == 0); 1431 ASSERT(call->type_args_len() == 0);
1474 Definition* left = call->ArgumentAt(0); 1432 Definition* left = call->ArgumentAt(0);
1475 Definition* instantiator_type_args = call->ArgumentAt(1); 1433 Definition* instantiator_type_args = call->ArgumentAt(1);
1476 Definition* function_type_args = call->ArgumentAt(2); 1434 Definition* function_type_args = call->ArgumentAt(2);
1477 const AbstractType& type = 1435 const AbstractType& type =
1478 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); 1436 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value());
1479 ASSERT(!type.IsMalformedOrMalbounded()); 1437 ASSERT(!type.IsMalformedOrMalbounded());
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1622 return; 1580 return;
1623 } 1581 }
1624 } 1582 }
1625 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr( 1583 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr(
1626 call->token_pos(), new (Z) Value(left), 1584 call->token_pos(), new (Z) Value(left),
1627 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), 1585 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args),
1628 type, Symbols::InTypeCast(), call->deopt_id()); 1586 type, Symbols::InTypeCast(), call->deopt_id());
1629 ReplaceCall(call, assert_as); 1587 ReplaceCall(call, assert_as);
1630 } 1588 }
1631 1589
1632
1633 bool AotOptimizer::IsAllowedForInlining(intptr_t call_deopt_id) { 1590 bool AotOptimizer::IsAllowedForInlining(intptr_t call_deopt_id) {
1634 if (!use_speculative_inlining_) return false; 1591 if (!use_speculative_inlining_) return false;
1635 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { 1592 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) {
1636 if ((*inlining_black_list_)[i] == call_deopt_id) return false; 1593 if ((*inlining_black_list_)[i] == call_deopt_id) return false;
1637 } 1594 }
1638 return true; 1595 return true;
1639 } 1596 }
1640 1597
1641
1642 static bool HasLikelySmiOperand(InstanceCallInstr* instr) { 1598 static bool HasLikelySmiOperand(InstanceCallInstr* instr) {
1643 ASSERT(instr->type_args_len() == 0); 1599 ASSERT(instr->type_args_len() == 0);
1644 // Phis with at least one known smi are // guessed to be likely smi as well. 1600 // Phis with at least one known smi are // guessed to be likely smi as well.
1645 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { 1601 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) {
1646 PhiInstr* phi = instr->ArgumentAt(i)->AsPhi(); 1602 PhiInstr* phi = instr->ArgumentAt(i)->AsPhi();
1647 if (phi != NULL) { 1603 if (phi != NULL) {
1648 for (intptr_t j = 0; j < phi->InputCount(); ++j) { 1604 for (intptr_t j = 0; j < phi->InputCount(); ++j) {
1649 if (phi->InputAt(j)->Type()->ToCid() == kSmiCid) return true; 1605 if (phi->InputAt(j)->Type()->ToCid() == kSmiCid) return true;
1650 } 1606 }
1651 } 1607 }
1652 } 1608 }
1653 // If all of the inputs are known smis or the result of CheckedSmiOp, 1609 // If all of the inputs are known smis or the result of CheckedSmiOp,
1654 // we guess the operand to be likely smi. 1610 // we guess the operand to be likely smi.
1655 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { 1611 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) {
1656 if (!instr->ArgumentAt(i)->IsCheckedSmiOp()) return false; 1612 if (!instr->ArgumentAt(i)->IsCheckedSmiOp()) return false;
1657 } 1613 }
1658 return true; 1614 return true;
1659 } 1615 }
1660 1616
1661
1662 bool AotOptimizer::TryInlineFieldAccess(InstanceCallInstr* call) { 1617 bool AotOptimizer::TryInlineFieldAccess(InstanceCallInstr* call) {
1663 const Token::Kind op_kind = call->token_kind(); 1618 const Token::Kind op_kind = call->token_kind();
1664 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(call)) { 1619 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(call)) {
1665 return true; 1620 return true;
1666 } 1621 }
1667 1622
1668 const ICData& unary_checks = 1623 const ICData& unary_checks =
1669 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); 1624 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks());
1670 if (!unary_checks.NumberOfChecksIs(0) && (op_kind == Token::kSET) && 1625 if (!unary_checks.NumberOfChecksIs(0) && (op_kind == Token::kSET) &&
1671 TryInlineInstanceSetter(call, unary_checks)) { 1626 TryInlineInstanceSetter(call, unary_checks)) {
1672 return true; 1627 return true;
1673 } 1628 }
1674 1629
1675 return false; 1630 return false;
1676 } 1631 }
1677 1632
1678
1679 // Tries to optimize instance call by replacing it with a faster instruction 1633 // Tries to optimize instance call by replacing it with a faster instruction
1680 // (e.g, binary op, field load, ..). 1634 // (e.g, binary op, field load, ..).
1681 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { 1635 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
1682 ASSERT(FLAG_precompiled_mode); 1636 ASSERT(FLAG_precompiled_mode);
1683 // TODO(srdjan): Investigate other attempts, as they are not allowed to 1637 // TODO(srdjan): Investigate other attempts, as they are not allowed to
1684 // deoptimize. 1638 // deoptimize.
1685 1639
1686 // Type test is special as it always gets converted into inlined code. 1640 // Type test is special as it always gets converted into inlined code.
1687 const Token::Kind op_kind = instr->token_kind(); 1641 const Token::Kind op_kind = instr->token_kind();
1688 if (Token::IsTypeTestOperator(op_kind)) { 1642 if (Token::IsTypeTestOperator(op_kind)) {
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
1942 // deoptimization is allowed. 1896 // deoptimization is allowed.
1943 CallTargets* targets = CallTargets::Create(Z, *instr->ic_data()); 1897 CallTargets* targets = CallTargets::Create(Z, *instr->ic_data());
1944 PolymorphicInstanceCallInstr* call = 1898 PolymorphicInstanceCallInstr* call =
1945 new (Z) PolymorphicInstanceCallInstr(instr, *targets, 1899 new (Z) PolymorphicInstanceCallInstr(instr, *targets,
1946 /* complete = */ false); 1900 /* complete = */ false);
1947 instr->ReplaceWith(call, current_iterator()); 1901 instr->ReplaceWith(call, current_iterator());
1948 return; 1902 return;
1949 } 1903 }
1950 } 1904 }
1951 1905
1952
1953 void AotOptimizer::VisitPolymorphicInstanceCall( 1906 void AotOptimizer::VisitPolymorphicInstanceCall(
1954 PolymorphicInstanceCallInstr* call) { 1907 PolymorphicInstanceCallInstr* call) {
1955 const intptr_t receiver_cid = 1908 const intptr_t receiver_cid =
1956 call->PushArgumentAt(0)->value()->Type()->ToCid(); 1909 call->PushArgumentAt(0)->value()->Type()->ToCid();
1957 if (receiver_cid != kDynamicCid) { 1910 if (receiver_cid != kDynamicCid) {
1958 const Class& receiver_class = 1911 const Class& receiver_class =
1959 Class::Handle(Z, isolate()->class_table()->At(receiver_cid)); 1912 Class::Handle(Z, isolate()->class_table()->At(receiver_cid));
1960 const Function& function = Function::ZoneHandle( 1913 const Function& function = Function::ZoneHandle(
1961 Z, call->instance_call()->ResolveForReceiverClass(receiver_class)); 1914 Z, call->instance_call()->ResolveForReceiverClass(receiver_class));
1962 if (!function.IsNull()) { 1915 if (!function.IsNull()) {
1963 // Only one target. Replace by static call. 1916 // Only one target. Replace by static call.
1964 StaticCallInstr* new_call = StaticCallInstr::FromCall(Z, call, function); 1917 StaticCallInstr* new_call = StaticCallInstr::FromCall(Z, call, function);
1965 call->ReplaceWith(new_call, current_iterator()); 1918 call->ReplaceWith(new_call, current_iterator());
1966 } 1919 }
1967 } 1920 }
1968 } 1921 }
1969 1922
1970
1971 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { 1923 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
1972 if (!IsAllowedForInlining(call->deopt_id())) { 1924 if (!IsAllowedForInlining(call->deopt_id())) {
1973 // Inlining disabled after a speculative inlining attempt. 1925 // Inlining disabled after a speculative inlining attempt.
1974 return; 1926 return;
1975 } 1927 }
1976 MethodRecognizer::Kind recognized_kind = 1928 MethodRecognizer::Kind recognized_kind =
1977 MethodRecognizer::RecognizeKind(call->function()); 1929 MethodRecognizer::RecognizeKind(call->function());
1978 switch (recognized_kind) { 1930 switch (recognized_kind) {
1979 case MethodRecognizer::kObjectConstructor: 1931 case MethodRecognizer::kObjectConstructor:
1980 case MethodRecognizer::kObjectArrayAllocate: 1932 case MethodRecognizer::kObjectArrayAllocate:
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
2046 } 1998 }
2047 } 1999 }
2048 } 2000 }
2049 break; 2001 break;
2050 } 2002 }
2051 default: 2003 default:
2052 break; 2004 break;
2053 } 2005 }
2054 } 2006 }
2055 2007
2056
2057 void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { 2008 void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
2058 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. 2009 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
2059 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) 2010 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
2060 if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedMint); 2011 if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedMint);
2061 #endif 2012 #endif
2062 } 2013 }
2063 2014
2064
2065 bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, 2015 bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
2066 const ICData& unary_ic_data) { 2016 const ICData& unary_ic_data) {
2067 ASSERT((unary_ic_data.NumberOfChecks() > 0) && 2017 ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
2068 (unary_ic_data.NumArgsTested() == 1)); 2018 (unary_ic_data.NumArgsTested() == 1));
2069 if (I->type_checks()) { 2019 if (I->type_checks()) {
2070 // Checked mode setters are inlined like normal methods by conventional 2020 // Checked mode setters are inlined like normal methods by conventional
2071 // inlining. 2021 // inlining.
2072 return false; 2022 return false;
2073 } 2023 }
2074 2024
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2109 // No unboxed stores in precompiled code. 2059 // No unboxed stores in precompiled code.
2110 ASSERT(!store->IsUnboxedStore()); 2060 ASSERT(!store->IsUnboxedStore());
2111 2061
2112 // Discard the environment from the original instruction because the store 2062 // Discard the environment from the original instruction because the store
2113 // can't deoptimize. 2063 // can't deoptimize.
2114 instr->RemoveEnvironment(); 2064 instr->RemoveEnvironment();
2115 ReplaceCall(instr, store); 2065 ReplaceCall(instr, store);
2116 return true; 2066 return true;
2117 } 2067 }
2118 2068
2119
2120 void AotOptimizer::ReplaceArrayBoundChecks() { 2069 void AotOptimizer::ReplaceArrayBoundChecks() {
2121 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 2070 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
2122 !block_it.Done(); block_it.Advance()) { 2071 !block_it.Done(); block_it.Advance()) {
2123 ForwardInstructionIterator it(block_it.Current()); 2072 ForwardInstructionIterator it(block_it.Current());
2124 current_iterator_ = &it; 2073 current_iterator_ = &it;
2125 for (; !it.Done(); it.Advance()) { 2074 for (; !it.Done(); it.Advance()) {
2126 CheckArrayBoundInstr* check = it.Current()->AsCheckArrayBound(); 2075 CheckArrayBoundInstr* check = it.Current()->AsCheckArrayBound();
2127 if (check != NULL) { 2076 if (check != NULL) {
2128 GenericCheckBoundInstr* new_check = new (Z) GenericCheckBoundInstr( 2077 GenericCheckBoundInstr* new_check = new (Z) GenericCheckBoundInstr(
2129 new (Z) Value(check->length()->definition()), 2078 new (Z) Value(check->length()->definition()),
2130 new (Z) Value(check->index()->definition()), check->deopt_id()); 2079 new (Z) Value(check->index()->definition()), check->deopt_id());
2131 flow_graph_->InsertBefore(check, new_check, check->env(), 2080 flow_graph_->InsertBefore(check, new_check, check->env(),
2132 FlowGraph::kEffect); 2081 FlowGraph::kEffect);
2133 current_iterator()->RemoveCurrentFromGraph(); 2082 current_iterator()->RemoveCurrentFromGraph();
2134 } 2083 }
2135 } 2084 }
2136 } 2085 }
2137 } 2086 }
2138 2087
2139 #endif // DART_PRECOMPILER 2088 #endif // DART_PRECOMPILER
2140 2089
2141 } // namespace dart 2090 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/aot_optimizer.h ('k') | runtime/vm/assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698