OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/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 Loading... |
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_ = ⁢ | 132 current_iterator_ = ⁢ |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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_ = ⁢ | 2073 current_iterator_ = ⁢ |
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 |
OLD | NEW |