OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/flow_graph_optimizer.h" | 5 #include "vm/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" |
11 #include "vm/cpu.h" | 11 #include "vm/cpu.h" |
12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
13 #include "vm/exceptions.h" | 13 #include "vm/exceptions.h" |
14 #include "vm/flow_graph_builder.h" | 14 #include "vm/flow_graph_builder.h" |
15 #include "vm/flow_graph_compiler.h" | 15 #include "vm/flow_graph_compiler.h" |
16 #include "vm/flow_graph_inliner.h" | 16 #include "vm/flow_graph_inliner.h" |
17 #include "vm/flow_graph_range_analysis.h" | 17 #include "vm/flow_graph_range_analysis.h" |
18 #include "vm/hash_map.h" | 18 #include "vm/hash_map.h" |
19 #include "vm/il_printer.h" | 19 #include "vm/il_printer.h" |
20 #include "vm/intermediate_language.h" | 20 #include "vm/intermediate_language.h" |
| 21 #include "vm/object.h" |
21 #include "vm/object_store.h" | 22 #include "vm/object_store.h" |
22 #include "vm/parser.h" | 23 #include "vm/parser.h" |
23 #include "vm/precompiler.h" | 24 #include "vm/precompiler.h" |
24 #include "vm/resolver.h" | 25 #include "vm/resolver.h" |
25 #include "vm/scopes.h" | 26 #include "vm/scopes.h" |
26 #include "vm/stack_frame.h" | 27 #include "vm/stack_frame.h" |
27 #include "vm/symbols.h" | 28 #include "vm/symbols.h" |
28 | 29 |
29 namespace dart { | 30 namespace dart { |
30 | 31 |
31 DEFINE_FLAG(int, getter_setter_ratio, 13, | |
32 "Ratio of getter/setter usage used for double field unboxing heuristics"); | |
33 DEFINE_FLAG(bool, guess_icdata_cid, true, | |
34 "Artificially create type feedback for arithmetic etc. operations" | |
35 " by guessing the other unknown argument cid"); | |
36 DEFINE_FLAG(int, max_polymorphic_checks, 4, | |
37 "Maximum number of polymorphic check, otherwise it is megamorphic."); | |
38 DEFINE_FLAG(int, max_equality_polymorphic_checks, 32, | |
39 "Maximum number of polymorphic checks in equality operator," | |
40 " otherwise use megamorphic dispatch."); | |
41 DEFINE_FLAG(bool, merge_sin_cos, false, "Merge sin/cos into sincos"); | |
42 DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details."); | |
43 DEFINE_FLAG(bool, truncating_left_shift, true, | |
44 "Optimize left shift to truncate if possible"); | |
45 DEFINE_FLAG(bool, use_cha_deopt, true, | |
46 "Use class hierarchy analysis even if it can cause deoptimization."); | |
47 | |
48 DECLARE_FLAG(bool, precompilation); | 32 DECLARE_FLAG(bool, precompilation); |
49 DECLARE_FLAG(bool, polymorphic_with_deopt); | |
50 DECLARE_FLAG(bool, trace_cha); | |
51 DECLARE_FLAG(bool, trace_field_guards); | |
52 | 33 |
53 // Quick access to the current isolate and zone. | 34 // Quick access to the current isolate and zone. |
54 #define I (isolate()) | 35 #define I (isolate()) |
55 #define Z (zone()) | 36 #define Z (zone()) |
56 | 37 |
57 static bool ShouldInlineSimd() { | 38 static bool ShouldInlineSimd() { |
58 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 39 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
59 } | 40 } |
60 | 41 |
61 | 42 |
62 static bool CanUnboxDouble() { | 43 static bool CanUnboxDouble() { |
63 return FlowGraphCompiler::SupportsUnboxedDoubles(); | 44 return FlowGraphCompiler::SupportsUnboxedDoubles(); |
64 } | 45 } |
65 | 46 |
66 | 47 |
67 static bool CanConvertUnboxedMintToDouble() { | 48 static bool CanConvertUnboxedMintToDouble() { |
68 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); | 49 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); |
69 } | 50 } |
70 | 51 |
71 | 52 |
72 // Optimize instance calls using ICData. | 53 // Optimize instance calls using ICData. |
73 void FlowGraphOptimizer::ApplyICData() { | 54 void AotOptimizer::ApplyICData() { |
74 VisitBlocks(); | 55 VisitBlocks(); |
75 } | 56 } |
76 | 57 |
77 | 58 |
78 void FlowGraphOptimizer::PopulateWithICData() { | 59 void AotOptimizer::PopulateWithICData() { |
79 ASSERT(current_iterator_ == NULL); | 60 ASSERT(current_iterator_ == NULL); |
80 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 61 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
81 !block_it.Done(); | 62 !block_it.Done(); |
82 block_it.Advance()) { | 63 block_it.Advance()) { |
83 ForwardInstructionIterator it(block_it.Current()); | 64 ForwardInstructionIterator it(block_it.Current()); |
84 for (; !it.Done(); it.Advance()) { | 65 for (; !it.Done(); it.Advance()) { |
85 Instruction* instr = it.Current(); | 66 Instruction* instr = it.Current(); |
86 if (instr->IsInstanceCall()) { | 67 if (instr->IsInstanceCall()) { |
87 InstanceCallInstr* call = instr->AsInstanceCall(); | 68 InstanceCallInstr* call = instr->AsInstanceCall(); |
88 if (!call->HasICData()) { | 69 if (!call->HasICData()) { |
(...skipping 13 matching lines...) Expand all Loading... |
102 } | 83 } |
103 } | 84 } |
104 | 85 |
105 | 86 |
106 // Optimize instance calls using cid. This is called after optimizer | 87 // Optimize instance calls using cid. This is called after optimizer |
107 // converted instance calls to instructions. Any remaining | 88 // converted instance calls to instructions. Any remaining |
108 // instance calls are either megamorphic calls, cannot be optimized or | 89 // instance calls are either megamorphic calls, cannot be optimized or |
109 // have no runtime type feedback collected. | 90 // have no runtime type feedback collected. |
110 // Attempts to convert an instance call (IC call) using propagated class-ids, | 91 // Attempts to convert an instance call (IC call) using propagated class-ids, |
111 // e.g., receiver class id, guarded-cid, or by guessing cid-s. | 92 // e.g., receiver class id, guarded-cid, or by guessing cid-s. |
112 void FlowGraphOptimizer::ApplyClassIds() { | 93 void AotOptimizer::ApplyClassIds() { |
113 ASSERT(current_iterator_ == NULL); | 94 ASSERT(current_iterator_ == NULL); |
114 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 95 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
115 !block_it.Done(); | 96 !block_it.Done(); |
116 block_it.Advance()) { | 97 block_it.Advance()) { |
117 ForwardInstructionIterator it(block_it.Current()); | 98 ForwardInstructionIterator it(block_it.Current()); |
118 current_iterator_ = ⁢ | 99 current_iterator_ = ⁢ |
119 for (; !it.Done(); it.Advance()) { | 100 for (; !it.Done(); it.Advance()) { |
120 Instruction* instr = it.Current(); | 101 Instruction* instr = it.Current(); |
121 if (instr->IsInstanceCall()) { | 102 if (instr->IsInstanceCall()) { |
122 InstanceCallInstr* call = instr->AsInstanceCall(); | 103 InstanceCallInstr* call = instr->AsInstanceCall(); |
(...skipping 10 matching lines...) Expand all Loading... |
133 } | 114 } |
134 } | 115 } |
135 | 116 |
136 | 117 |
137 // TODO(srdjan): Test/support other number types as well. | 118 // TODO(srdjan): Test/support other number types as well. |
138 static bool IsNumberCid(intptr_t cid) { | 119 static bool IsNumberCid(intptr_t cid) { |
139 return (cid == kSmiCid) || (cid == kDoubleCid); | 120 return (cid == kSmiCid) || (cid == kDoubleCid); |
140 } | 121 } |
141 | 122 |
142 | 123 |
143 bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) { | 124 static void GetUniqueDynamicTarget(Isolate* isolate, |
| 125 const String& fname, |
| 126 Object* function) { |
| 127 UniqueFunctionsSet functions_set( |
| 128 isolate->object_store()->unique_dynamic_targets()); |
| 129 ASSERT(fname.IsSymbol()); |
| 130 *function = functions_set.GetOrNull(fname); |
| 131 ASSERT(functions_set.Release().raw() == |
| 132 isolate->object_store()->unique_dynamic_targets()); |
| 133 } |
| 134 |
| 135 |
| 136 bool AotOptimizer::TryCreateICData(InstanceCallInstr* call) { |
144 ASSERT(call->HasICData()); | 137 ASSERT(call->HasICData()); |
145 if (call->ic_data()->NumberOfUsedChecks() > 0) { | 138 if (call->ic_data()->NumberOfUsedChecks() > 0) { |
146 // This occurs when an instance call has too many checks, will be converted | 139 // This occurs when an instance call has too many checks, will be converted |
147 // to megamorphic call. | 140 // to megamorphic call. |
148 return false; | 141 return false; |
149 } | 142 } |
150 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); | 143 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); |
151 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); | 144 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); |
152 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { | 145 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { |
153 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); | 146 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 return false; | 182 return false; |
190 } | 183 } |
191 const Array& args_desc_array = Array::Handle(Z, | 184 const Array& args_desc_array = Array::Handle(Z, |
192 ArgumentsDescriptor::New(call->ArgumentCount(), | 185 ArgumentsDescriptor::New(call->ArgumentCount(), |
193 call->argument_names())); | 186 call->argument_names())); |
194 ArgumentsDescriptor args_desc(args_desc_array); | 187 ArgumentsDescriptor args_desc(args_desc_array); |
195 const Function& function = Function::Handle(Z, | 188 const Function& function = Function::Handle(Z, |
196 Resolver::ResolveDynamicForReceiverClass( | 189 Resolver::ResolveDynamicForReceiverClass( |
197 receiver_class, | 190 receiver_class, |
198 call->function_name(), | 191 call->function_name(), |
199 args_desc, | 192 args_desc)); |
200 false /* allow add */)); | |
201 if (function.IsNull()) { | 193 if (function.IsNull()) { |
202 return false; | 194 return false; |
203 } | 195 } |
204 | 196 |
205 // Create new ICData, do not modify the one attached to the instruction | 197 // Create new ICData, do not modify the one attached to the instruction |
206 // since it is attached to the assembly instruction itself. | 198 // since it is attached to the assembly instruction itself. |
207 // TODO(srdjan): Prevent modification of ICData object that is | 199 // TODO(srdjan): Prevent modification of ICData object that is |
208 // referenced in assembly code. | 200 // referenced in assembly code. |
209 const ICData& ic_data = ICData::ZoneHandle(Z, | 201 const ICData& ic_data = ICData::ZoneHandle(Z, |
210 ICData::NewFrom(*call->ic_data(), class_ids.length())); | 202 ICData::NewFrom(*call->ic_data(), class_ids.length())); |
211 if (class_ids.length() > 1) { | 203 if (class_ids.length() > 1) { |
212 ic_data.AddCheck(class_ids, function); | 204 ic_data.AddCheck(class_ids, function); |
213 } else { | 205 } else { |
214 ASSERT(class_ids.length() == 1); | 206 ASSERT(class_ids.length() == 1); |
215 ic_data.AddReceiverCheck(class_ids[0], function); | 207 ic_data.AddReceiverCheck(class_ids[0], function); |
216 } | 208 } |
217 call->set_ic_data(&ic_data); | 209 call->set_ic_data(&ic_data); |
218 return true; | 210 return true; |
219 } | 211 } |
220 | 212 |
221 #ifdef DART_PRECOMPILER | 213 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { |
222 if (FLAG_precompilation && | |
223 (isolate()->object_store()->unique_dynamic_targets() != Array::null())) { | |
224 // Check if the target is unique. | 214 // Check if the target is unique. |
225 Function& target_function = Function::Handle(Z); | 215 Function& target_function = Function::Handle(Z); |
226 Precompiler::GetUniqueDynamicTarget( | 216 GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function); |
227 isolate(), call->function_name(), &target_function); | |
228 // Calls with named arguments must be resolved/checked at runtime. | 217 // Calls with named arguments must be resolved/checked at runtime. |
229 String& error_message = String::Handle(Z); | 218 String& error_message = String::Handle(Z); |
230 if (!target_function.IsNull() && | 219 if (!target_function.IsNull() && |
231 !target_function.HasOptionalNamedParameters() && | 220 !target_function.HasOptionalNamedParameters() && |
232 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, | 221 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, |
233 &error_message)) { | 222 &error_message)) { |
234 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); | 223 const intptr_t cid = Class::Handle(Z, target_function.Owner()).id(); |
235 const ICData& ic_data = ICData::ZoneHandle(Z, | 224 const ICData& ic_data = ICData::ZoneHandle(Z, |
236 ICData::NewFrom(*call->ic_data(), 1)); | 225 ICData::NewFrom(*call->ic_data(), 1)); |
237 ic_data.AddReceiverCheck(cid, target_function); | 226 ic_data.AddReceiverCheck(cid, target_function); |
238 call->set_ic_data(&ic_data); | 227 call->set_ic_data(&ic_data); |
239 return true; | 228 return true; |
240 } | 229 } |
241 } | 230 } |
242 #endif | |
243 | 231 |
244 // Check if getter or setter in function's class and class is currently leaf. | 232 // Check if getter or setter in function's class and class is currently leaf. |
245 if (FLAG_guess_icdata_cid && | 233 if (FLAG_guess_icdata_cid && |
246 ((call->token_kind() == Token::kGET) || | 234 ((call->token_kind() == Token::kGET) || |
247 (call->token_kind() == Token::kSET))) { | 235 (call->token_kind() == Token::kSET))) { |
248 const Class& owner_class = Class::Handle(Z, function().Owner()); | 236 const Class& owner_class = Class::Handle(Z, function().Owner()); |
249 if (!owner_class.is_abstract() && | 237 if (!owner_class.is_abstract() && |
250 !CHA::HasSubclasses(owner_class) && | 238 !CHA::HasSubclasses(owner_class) && |
251 !CHA::IsImplemented(owner_class)) { | 239 !CHA::IsImplemented(owner_class)) { |
252 const Array& args_desc_array = Array::Handle(Z, | 240 const Array& args_desc_array = Array::Handle(Z, |
253 ArgumentsDescriptor::New(call->ArgumentCount(), | 241 ArgumentsDescriptor::New(call->ArgumentCount(), |
254 call->argument_names())); | 242 call->argument_names())); |
255 ArgumentsDescriptor args_desc(args_desc_array); | 243 ArgumentsDescriptor args_desc(args_desc_array); |
256 const Function& function = Function::Handle(Z, | 244 const Function& function = Function::Handle(Z, |
257 Resolver::ResolveDynamicForReceiverClass(owner_class, | 245 Resolver::ResolveDynamicForReceiverClass(owner_class, |
258 call->function_name(), | 246 call->function_name(), |
259 args_desc, | 247 args_desc)); |
260 false /* allow_add */)); | |
261 if (!function.IsNull()) { | 248 if (!function.IsNull()) { |
262 const ICData& ic_data = ICData::ZoneHandle(Z, | 249 const ICData& ic_data = ICData::ZoneHandle(Z, |
263 ICData::NewFrom(*call->ic_data(), class_ids.length())); | 250 ICData::NewFrom(*call->ic_data(), class_ids.length())); |
264 ic_data.AddReceiverCheck(owner_class.id(), function); | 251 ic_data.AddReceiverCheck(owner_class.id(), function); |
265 call->set_ic_data(&ic_data); | 252 call->set_ic_data(&ic_data); |
266 return true; | 253 return true; |
267 } | 254 } |
268 } | 255 } |
269 } | 256 } |
270 | 257 |
271 return false; | 258 return false; |
272 } | 259 } |
273 | 260 |
274 | 261 |
275 const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data, | 262 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data, |
276 intptr_t cid) { | 263 intptr_t cid) { |
277 ASSERT(ic_data.NumArgsTested() == 1); | 264 ASSERT(ic_data.NumArgsTested() == 1); |
278 | 265 |
279 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { | 266 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { |
280 return ic_data; // Nothing to do | 267 return ic_data; // Nothing to do |
281 } | 268 } |
282 | 269 |
283 const Function& function = | 270 const Function& function = |
284 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid)); | 271 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid)); |
285 // TODO(fschneider): Try looking up the function on the class if it is | 272 // TODO(fschneider): Try looking up the function on the class if it is |
286 // not found in the ICData. | 273 // not found in the ICData. |
287 if (!function.IsNull()) { | 274 if (!function.IsNull()) { |
288 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New( | 275 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New( |
289 Function::Handle(Z, ic_data.Owner()), | 276 Function::Handle(Z, ic_data.Owner()), |
290 String::Handle(Z, ic_data.target_name()), | 277 String::Handle(Z, ic_data.target_name()), |
291 Object::empty_array(), // Dummy argument descriptor. | 278 Object::empty_array(), // Dummy argument descriptor. |
292 ic_data.deopt_id(), | 279 ic_data.deopt_id(), |
293 ic_data.NumArgsTested())); | 280 ic_data.NumArgsTested())); |
294 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); | 281 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); |
295 new_ic_data.AddReceiverCheck(cid, function); | 282 new_ic_data.AddReceiverCheck(cid, function); |
296 return new_ic_data; | 283 return new_ic_data; |
297 } | 284 } |
298 | 285 |
299 return ic_data; | 286 return ic_data; |
300 } | 287 } |
301 | 288 |
302 | 289 |
303 void FlowGraphOptimizer::SpecializePolymorphicInstanceCall( | 290 void AotOptimizer::SpecializePolymorphicInstanceCall( |
304 PolymorphicInstanceCallInstr* call) { | 291 PolymorphicInstanceCallInstr* call) { |
305 if (!FLAG_polymorphic_with_deopt) { | 292 if (!FLAG_polymorphic_with_deopt) { |
306 // Specialization adds receiver checks which can lead to deoptimization. | 293 // Specialization adds receiver checks which can lead to deoptimization. |
307 return; | 294 return; |
308 } | 295 } |
309 if (!call->with_checks()) { | 296 if (!call->with_checks()) { |
310 return; // Already specialized. | 297 return; // Already specialized. |
311 } | 298 } |
312 | 299 |
313 const intptr_t receiver_cid = | 300 const intptr_t receiver_cid = |
(...skipping 28 matching lines...) Expand all Loading... |
342 | 329 |
343 static bool IsPositiveOrZeroSmiConst(Definition* d) { | 330 static bool IsPositiveOrZeroSmiConst(Definition* d) { |
344 ConstantInstr* const_instr = d->AsConstant(); | 331 ConstantInstr* const_instr = d->AsConstant(); |
345 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { | 332 if ((const_instr != NULL) && (const_instr->value().IsSmi())) { |
346 return Smi::Cast(const_instr->value()).Value() >= 0; | 333 return Smi::Cast(const_instr->value()).Value() >= 0; |
347 } | 334 } |
348 return false; | 335 return false; |
349 } | 336 } |
350 | 337 |
351 | 338 |
352 void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp( | 339 void AotOptimizer::OptimizeLeftShiftBitAndSmiOp( |
353 Definition* bit_and_instr, | 340 Definition* bit_and_instr, |
354 Definition* left_instr, | 341 Definition* left_instr, |
355 Definition* right_instr) { | 342 Definition* right_instr) { |
356 ASSERT(bit_and_instr != NULL); | 343 ASSERT(bit_and_instr != NULL); |
357 ASSERT((left_instr != NULL) && (right_instr != NULL)); | 344 ASSERT((left_instr != NULL) && (right_instr != NULL)); |
358 | 345 |
359 // Check for pattern, smi_shift_left must be single-use. | 346 // Check for pattern, smi_shift_left must be single-use. |
360 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); | 347 bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr); |
361 if (!is_positive_or_zero) { | 348 if (!is_positive_or_zero) { |
362 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr); | 349 is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr); |
(...skipping 17 matching lines...) Expand all Loading... |
380 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr( | 367 BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr( |
381 Token::kBIT_AND, | 368 Token::kBIT_AND, |
382 new(Z) Value(left_instr), | 369 new(Z) Value(left_instr), |
383 new(Z) Value(right_instr), | 370 new(Z) Value(right_instr), |
384 Thread::kNoDeoptId); // BIT_AND cannot deoptimize. | 371 Thread::kNoDeoptId); // BIT_AND cannot deoptimize. |
385 bit_and_instr->ReplaceWith(smi_op, current_iterator()); | 372 bit_and_instr->ReplaceWith(smi_op, current_iterator()); |
386 } | 373 } |
387 } | 374 } |
388 | 375 |
389 | 376 |
390 void FlowGraphOptimizer::AppendExtractNthOutputForMerged(Definition* instr, | 377 void AotOptimizer::AppendExtractNthOutputForMerged(Definition* instr, |
391 intptr_t index, | 378 intptr_t index, |
392 Representation rep, | 379 Representation rep, |
393 intptr_t cid) { | 380 intptr_t cid) { |
394 ExtractNthOutputInstr* extract = | 381 ExtractNthOutputInstr* extract = |
395 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid); | 382 new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid); |
396 instr->ReplaceUsesWith(extract); | 383 instr->ReplaceUsesWith(extract); |
397 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue); | 384 flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue); |
398 } | 385 } |
399 | 386 |
400 | 387 |
401 // Dart: | 388 // Dart: |
402 // var x = d % 10; | 389 // var x = d % 10; |
403 // var y = d ~/ 10; | 390 // var y = d ~/ 10; |
404 // var z = x + y; | 391 // var z = x + y; |
405 // | 392 // |
406 // IL: | 393 // IL: |
407 // v4 <- %(v2, v3) | 394 // v4 <- %(v2, v3) |
408 // v5 <- ~/(v2, v3) | 395 // v5 <- ~/(v2, v3) |
409 // v6 <- +(v4, v5) | 396 // v6 <- +(v4, v5) |
410 // | 397 // |
411 // IL optimized: | 398 // IL optimized: |
412 // v4 <- DIVMOD(v2, v3); | 399 // v4 <- DIVMOD(v2, v3); |
413 // v5 <- LoadIndexed(v4, 0); // ~/ result | 400 // v5 <- LoadIndexed(v4, 0); // ~/ result |
414 // v6 <- LoadIndexed(v4, 1); // % result | 401 // v6 <- LoadIndexed(v4, 1); // % result |
415 // v7 <- +(v5, v6) | 402 // v7 <- +(v5, v6) |
416 // Because of the environment it is important that merged instruction replaces | 403 // Because of the environment it is important that merged instruction replaces |
417 // first original instruction encountered. | 404 // first original instruction encountered. |
418 void FlowGraphOptimizer::TryMergeTruncDivMod( | 405 void AotOptimizer::TryMergeTruncDivMod( |
419 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { | 406 GrowableArray<BinarySmiOpInstr*>* merge_candidates) { |
420 if (merge_candidates->length() < 2) { | 407 if (merge_candidates->length() < 2) { |
421 // Need at least a TRUNCDIV and a MOD. | 408 // Need at least a TRUNCDIV and a MOD. |
422 return; | 409 return; |
423 } | 410 } |
424 for (intptr_t i = 0; i < merge_candidates->length(); i++) { | 411 for (intptr_t i = 0; i < merge_candidates->length(); i++) { |
425 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; | 412 BinarySmiOpInstr* curr_instr = (*merge_candidates)[i]; |
426 if (curr_instr == NULL) { | 413 if (curr_instr == NULL) { |
427 // Instruction was merged already. | 414 // Instruction was merged already. |
428 continue; | 415 continue; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 // more candidates are possible. | 456 // more candidates are possible. |
470 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod. | 457 // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod. |
471 break; | 458 break; |
472 } | 459 } |
473 } | 460 } |
474 } | 461 } |
475 } | 462 } |
476 | 463 |
477 | 464 |
478 // Tries to merge MathUnary operations, in this case sinus and cosinus. | 465 // Tries to merge MathUnary operations, in this case sinus and cosinus. |
479 void FlowGraphOptimizer::TryMergeMathUnary( | 466 void AotOptimizer::TryMergeMathUnary( |
480 GrowableArray<MathUnaryInstr*>* merge_candidates) { | 467 GrowableArray<MathUnaryInstr*>* merge_candidates) { |
481 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() || | 468 if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() || |
482 !FLAG_merge_sin_cos) { | 469 !FLAG_merge_sin_cos) { |
483 return; | 470 return; |
484 } | 471 } |
485 if (merge_candidates->length() < 2) { | 472 if (merge_candidates->length() < 2) { |
486 // Need at least a SIN and a COS. | 473 // Need at least a SIN and a COS. |
487 return; | 474 return; |
488 } | 475 } |
489 for (intptr_t i = 0; i < merge_candidates->length(); i++) { | 476 for (intptr_t i = 0; i < merge_candidates->length(); i++) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 break; | 517 break; |
531 } | 518 } |
532 } | 519 } |
533 } | 520 } |
534 } | 521 } |
535 | 522 |
536 | 523 |
537 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the | 524 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the |
538 // shift can be a truncating Smi shift-left and result is always Smi. | 525 // shift can be a truncating Smi shift-left and result is always Smi. |
539 // Merging occurs only per basic-block. | 526 // Merging occurs only per basic-block. |
540 void FlowGraphOptimizer::TryOptimizePatterns() { | 527 void AotOptimizer::TryOptimizePatterns() { |
541 if (!FLAG_truncating_left_shift) return; | 528 if (!FLAG_truncating_left_shift) return; |
542 ASSERT(current_iterator_ == NULL); | 529 ASSERT(current_iterator_ == NULL); |
543 GrowableArray<BinarySmiOpInstr*> div_mod_merge; | 530 GrowableArray<BinarySmiOpInstr*> div_mod_merge; |
544 GrowableArray<MathUnaryInstr*> sin_cos_merge; | 531 GrowableArray<MathUnaryInstr*> sin_cos_merge; |
545 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 532 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
546 !block_it.Done(); | 533 !block_it.Done(); |
547 block_it.Advance()) { | 534 block_it.Advance()) { |
548 // Merging only per basic-block. | 535 // Merging only per basic-block. |
549 div_mod_merge.Clear(); | 536 div_mod_merge.Clear(); |
550 sin_cos_merge.Clear(); | 537 sin_cos_merge.Clear(); |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
716 // Unboxed double operation can't handle case of two smis. | 703 // Unboxed double operation can't handle case of two smis. |
717 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | 704 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
718 return false; | 705 return false; |
719 } | 706 } |
720 | 707 |
721 // Check that it have seen only smis and doubles. | 708 // Check that it have seen only smis and doubles. |
722 return HasTwoDoubleOrSmi(ic_data); | 709 return HasTwoDoubleOrSmi(ic_data); |
723 } | 710 } |
724 | 711 |
725 | 712 |
726 void FlowGraphOptimizer::ReplaceCall(Definition* call, | 713 void AotOptimizer::ReplaceCall(Definition* call, |
727 Definition* replacement) { | 714 Definition* replacement) { |
728 // Remove the original push arguments. | 715 // Remove the original push arguments. |
729 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 716 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
730 PushArgumentInstr* push = call->PushArgumentAt(i); | 717 PushArgumentInstr* push = call->PushArgumentAt(i); |
731 push->ReplaceUsesWith(push->value()->definition()); | 718 push->ReplaceUsesWith(push->value()->definition()); |
732 push->RemoveFromGraph(); | 719 push->RemoveFromGraph(); |
733 } | 720 } |
734 call->ReplaceWith(replacement, current_iterator()); | 721 call->ReplaceWith(replacement, current_iterator()); |
735 } | 722 } |
736 | 723 |
737 | 724 |
738 void FlowGraphOptimizer::AddCheckSmi(Definition* to_check, | 725 void AotOptimizer::AddCheckSmi(Definition* to_check, |
739 intptr_t deopt_id, | 726 intptr_t deopt_id, |
740 Environment* deopt_environment, | 727 Environment* deopt_environment, |
741 Instruction* insert_before) { | 728 Instruction* insert_before) { |
742 if (to_check->Type()->ToCid() != kSmiCid) { | 729 if (to_check->Type()->ToCid() != kSmiCid) { |
743 InsertBefore(insert_before, | 730 InsertBefore(insert_before, |
744 new(Z) CheckSmiInstr(new(Z) Value(to_check), | 731 new(Z) CheckSmiInstr(new(Z) Value(to_check), |
745 deopt_id, | 732 deopt_id, |
746 insert_before->token_pos()), | 733 insert_before->token_pos()), |
747 deopt_environment, | 734 deopt_environment, |
748 FlowGraph::kEffect); | 735 FlowGraph::kEffect); |
749 } | 736 } |
750 } | 737 } |
751 | 738 |
752 | 739 |
753 Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check, | 740 Instruction* AotOptimizer::GetCheckClass(Definition* to_check, |
754 const ICData& unary_checks, | 741 const ICData& unary_checks, |
755 intptr_t deopt_id, | 742 intptr_t deopt_id, |
756 TokenPosition token_pos) { | 743 TokenPosition token_pos) { |
757 if ((unary_checks.NumberOfUsedChecks() == 1) && | 744 if ((unary_checks.NumberOfUsedChecks() == 1) && |
758 unary_checks.HasReceiverClassId(kSmiCid)) { | 745 unary_checks.HasReceiverClassId(kSmiCid)) { |
759 return new(Z) CheckSmiInstr(new(Z) Value(to_check), | 746 return new(Z) CheckSmiInstr(new(Z) Value(to_check), |
760 deopt_id, | 747 deopt_id, |
761 token_pos); | 748 token_pos); |
762 } | 749 } |
763 return new(Z) CheckClassInstr( | 750 return new(Z) CheckClassInstr( |
764 new(Z) Value(to_check), deopt_id, unary_checks, token_pos); | 751 new(Z) Value(to_check), deopt_id, unary_checks, token_pos); |
765 } | 752 } |
766 | 753 |
767 | 754 |
768 void FlowGraphOptimizer::AddCheckClass(Definition* to_check, | 755 void AotOptimizer::AddCheckClass(Definition* to_check, |
769 const ICData& unary_checks, | 756 const ICData& unary_checks, |
770 intptr_t deopt_id, | 757 intptr_t deopt_id, |
771 Environment* deopt_environment, | 758 Environment* deopt_environment, |
772 Instruction* insert_before) { | 759 Instruction* insert_before) { |
773 // Type propagation has not run yet, we cannot eliminate the check. | 760 // Type propagation has not run yet, we cannot eliminate the check. |
774 Instruction* check = GetCheckClass( | 761 Instruction* check = GetCheckClass( |
775 to_check, unary_checks, deopt_id, insert_before->token_pos()); | 762 to_check, unary_checks, deopt_id, insert_before->token_pos()); |
776 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); | 763 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); |
777 } | 764 } |
778 | 765 |
779 | 766 |
780 void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) { | 767 void AotOptimizer::AddReceiverCheck(InstanceCallInstr* call) { |
781 AddCheckClass(call->ArgumentAt(0), | 768 AddCheckClass(call->ArgumentAt(0), |
782 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), | 769 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), |
783 call->deopt_id(), | 770 call->deopt_id(), |
784 call->env(), | 771 call->env(), |
785 call); | 772 call); |
786 } | 773 } |
787 | 774 |
788 | 775 |
789 static bool ArgIsAlways(intptr_t cid, | 776 static bool ArgIsAlways(intptr_t cid, |
790 const ICData& ic_data, | 777 const ICData& ic_data, |
791 intptr_t arg_number) { | 778 intptr_t arg_number) { |
792 ASSERT(ic_data.NumArgsTested() > arg_number); | 779 ASSERT(ic_data.NumArgsTested() > arg_number); |
793 if (ic_data.NumberOfUsedChecks() == 0) { | 780 if (ic_data.NumberOfUsedChecks() == 0) { |
794 return false; | 781 return false; |
795 } | 782 } |
796 const intptr_t num_checks = ic_data.NumberOfChecks(); | 783 const intptr_t num_checks = ic_data.NumberOfChecks(); |
797 for (intptr_t i = 0; i < num_checks; i++) { | 784 for (intptr_t i = 0; i < num_checks; i++) { |
798 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { | 785 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { |
799 return false; | 786 return false; |
800 } | 787 } |
801 } | 788 } |
802 return true; | 789 return true; |
803 } | 790 } |
804 | 791 |
805 | 792 |
806 bool FlowGraphOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { | 793 bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { |
807 // Check for monomorphic IC data. | 794 // Check for monomorphic IC data. |
808 if (!call->HasICData()) return false; | 795 if (!call->HasICData()) return false; |
809 const ICData& ic_data = | 796 const ICData& ic_data = |
810 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); | 797 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); |
811 if (ic_data.NumberOfChecks() != 1) { | 798 if (ic_data.NumberOfChecks() != 1) { |
812 return false; | 799 return false; |
813 } | 800 } |
814 return TryReplaceInstanceCallWithInline(call); | 801 return TryReplaceInstanceCallWithInline(call); |
815 } | 802 } |
816 | 803 |
(...skipping 11 matching lines...) Expand all Loading... |
828 } else { | 815 } else { |
829 return d->IsStringFromCharCode(); | 816 return d->IsStringFromCharCode(); |
830 } | 817 } |
831 } | 818 } |
832 | 819 |
833 | 820 |
834 // Returns true if the string comparison was converted into char-code | 821 // Returns true if the string comparison was converted into char-code |
835 // comparison. Conversion is only possible for strings of length one. | 822 // comparison. Conversion is only possible for strings of length one. |
836 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. | 823 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. |
837 // TODO(srdjan): Expand for two-byte and external strings. | 824 // TODO(srdjan): Expand for two-byte and external strings. |
838 bool FlowGraphOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, | 825 bool AotOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, |
839 Token::Kind op_kind) { | 826 Token::Kind op_kind) { |
840 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); | 827 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); |
841 // Check that left and right are length one strings (either string constants | 828 // Check that left and right are length one strings (either string constants |
842 // or results of string-from-char-code. | 829 // or results of string-from-char-code. |
843 Definition* left = call->ArgumentAt(0); | 830 Definition* left = call->ArgumentAt(0); |
844 Definition* right = call->ArgumentAt(1); | 831 Definition* right = call->ArgumentAt(1); |
845 Value* left_val = NULL; | 832 Value* left_val = NULL; |
846 Definition* to_remove_left = NULL; | 833 Definition* to_remove_left = NULL; |
847 if (IsLengthOneString(right)) { | 834 if (IsLengthOneString(right)) { |
848 // Swap, since we know that both arguments are strings | 835 // Swap, since we know that both arguments are strings |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
915 to_remove_right->RemoveFromGraph(); | 902 to_remove_right->RemoveFromGraph(); |
916 } | 903 } |
917 return true; | 904 return true; |
918 } | 905 } |
919 return false; | 906 return false; |
920 } | 907 } |
921 | 908 |
922 | 909 |
923 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 910 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
924 | 911 |
925 bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 912 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
926 Token::Kind op_kind) { | 913 Token::Kind op_kind) { |
927 const ICData& ic_data = *call->ic_data(); | 914 const ICData& ic_data = *call->ic_data(); |
928 ASSERT(ic_data.NumArgsTested() == 2); | 915 ASSERT(ic_data.NumArgsTested() == 2); |
929 | 916 |
930 ASSERT(call->ArgumentCount() == 2); | 917 ASSERT(call->ArgumentCount() == 2); |
931 Definition* left = call->ArgumentAt(0); | 918 Definition* left = call->ArgumentAt(0); |
932 Definition* right = call->ArgumentAt(1); | 919 Definition* right = call->ArgumentAt(1); |
933 | 920 |
934 intptr_t cid = kIllegalCid; | 921 intptr_t cid = kIllegalCid; |
935 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { | 922 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1024 op_kind, | 1011 op_kind, |
1025 new(Z) Value(left), | 1012 new(Z) Value(left), |
1026 new(Z) Value(right), | 1013 new(Z) Value(right), |
1027 cid, | 1014 cid, |
1028 call->deopt_id()); | 1015 call->deopt_id()); |
1029 ReplaceCall(call, comp); | 1016 ReplaceCall(call, comp); |
1030 return true; | 1017 return true; |
1031 } | 1018 } |
1032 | 1019 |
1033 | 1020 |
1034 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 1021 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
1035 Token::Kind op_kind) { | 1022 Token::Kind op_kind) { |
1036 const ICData& ic_data = *call->ic_data(); | 1023 const ICData& ic_data = *call->ic_data(); |
1037 ASSERT(ic_data.NumArgsTested() == 2); | 1024 ASSERT(ic_data.NumArgsTested() == 2); |
1038 | 1025 |
1039 ASSERT(call->ArgumentCount() == 2); | 1026 ASSERT(call->ArgumentCount() == 2); |
1040 Definition* left = call->ArgumentAt(0); | 1027 Definition* left = call->ArgumentAt(0); |
1041 Definition* right = call->ArgumentAt(1); | 1028 Definition* right = call->ArgumentAt(1); |
1042 | 1029 |
1043 intptr_t cid = kIllegalCid; | 1030 intptr_t cid = kIllegalCid; |
1044 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1031 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1086 op_kind, | 1073 op_kind, |
1087 new(Z) Value(left), | 1074 new(Z) Value(left), |
1088 new(Z) Value(right), | 1075 new(Z) Value(right), |
1089 cid, | 1076 cid, |
1090 call->deopt_id()); | 1077 call->deopt_id()); |
1091 ReplaceCall(call, comp); | 1078 ReplaceCall(call, comp); |
1092 return true; | 1079 return true; |
1093 } | 1080 } |
1094 | 1081 |
1095 | 1082 |
1096 bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 1083 bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
1097 Token::Kind op_kind) { | 1084 Token::Kind op_kind) { |
1098 intptr_t operands_type = kIllegalCid; | 1085 intptr_t operands_type = kIllegalCid; |
1099 ASSERT(call->HasICData()); | 1086 ASSERT(call->HasICData()); |
1100 const ICData& ic_data = *call->ic_data(); | 1087 const ICData& ic_data = *call->ic_data(); |
1101 switch (op_kind) { | 1088 switch (op_kind) { |
1102 case Token::kADD: | 1089 case Token::kADD: |
1103 case Token::kSUB: | 1090 case Token::kSUB: |
1104 case Token::kMUL: | 1091 case Token::kMUL: |
1105 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 1092 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
1106 // Don't generate smi code if the IC data is marked because | 1093 // Don't generate smi code if the IC data is marked because |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1295 op_kind, | 1282 op_kind, |
1296 new(Z) Value(left), | 1283 new(Z) Value(left), |
1297 new(Z) Value(right), | 1284 new(Z) Value(right), |
1298 call->deopt_id()); | 1285 call->deopt_id()); |
1299 ReplaceCall(call, bin_op); | 1286 ReplaceCall(call, bin_op); |
1300 } | 1287 } |
1301 return true; | 1288 return true; |
1302 } | 1289 } |
1303 | 1290 |
1304 | 1291 |
1305 bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, | 1292 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, |
1306 Token::Kind op_kind) { | 1293 Token::Kind op_kind) { |
1307 ASSERT(call->ArgumentCount() == 1); | 1294 ASSERT(call->ArgumentCount() == 1); |
1308 Definition* input = call->ArgumentAt(0); | 1295 Definition* input = call->ArgumentAt(0); |
1309 Definition* unary_op = NULL; | 1296 Definition* unary_op = NULL; |
1310 if (HasOnlyOneSmi(*call->ic_data())) { | 1297 if (HasOnlyOneSmi(*call->ic_data())) { |
1311 InsertBefore(call, | 1298 InsertBefore(call, |
1312 new(Z) CheckSmiInstr(new(Z) Value(input), | 1299 new(Z) CheckSmiInstr(new(Z) Value(input), |
1313 call->deopt_id(), | 1300 call->deopt_id(), |
1314 call->token_pos()), | 1301 call->token_pos()), |
1315 call->env(), | 1302 call->env(), |
(...skipping 14 matching lines...) Expand all Loading... |
1330 } else { | 1317 } else { |
1331 return false; | 1318 return false; |
1332 } | 1319 } |
1333 ASSERT(unary_op != NULL); | 1320 ASSERT(unary_op != NULL); |
1334 ReplaceCall(call, unary_op); | 1321 ReplaceCall(call, unary_op); |
1335 return true; | 1322 return true; |
1336 } | 1323 } |
1337 | 1324 |
1338 | 1325 |
1339 // Using field class | 1326 // Using field class |
1340 RawField* FlowGraphOptimizer::GetField(intptr_t class_id, | 1327 RawField* AotOptimizer::GetField(intptr_t class_id, |
1341 const String& field_name) { | 1328 const String& field_name) { |
1342 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); | 1329 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); |
1343 Field& field = Field::Handle(Z); | 1330 Field& field = Field::Handle(Z); |
1344 while (!cls.IsNull()) { | 1331 while (!cls.IsNull()) { |
1345 field = cls.LookupInstanceField(field_name); | 1332 field = cls.LookupInstanceField(field_name); |
1346 if (!field.IsNull()) { | 1333 if (!field.IsNull()) { |
1347 return field.raw(); | 1334 return field.raw(); |
1348 } | 1335 } |
1349 cls = cls.SuperClass(); | 1336 cls = cls.SuperClass(); |
1350 } | 1337 } |
1351 return Field::null(); | 1338 return Field::null(); |
1352 } | 1339 } |
1353 | 1340 |
1354 | 1341 |
1355 // Use CHA to determine if the call needs a class check: if the callee's | 1342 // Use CHA to determine if the call needs a class check: if the callee's |
1356 // receiver is the same as the caller's receiver and there are no overriden | 1343 // receiver is the same as the caller's receiver and there are no overriden |
1357 // callee functions, then no class check is needed. | 1344 // callee functions, then no class check is needed. |
1358 bool FlowGraphOptimizer::InstanceCallNeedsClassCheck( | 1345 bool AotOptimizer::InstanceCallNeedsClassCheck( |
1359 InstanceCallInstr* call, RawFunction::Kind kind) const { | 1346 InstanceCallInstr* call, RawFunction::Kind kind) const { |
1360 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { | 1347 if (!FLAG_use_cha_deopt && !isolate()->all_classes_finalized()) { |
1361 // Even if class or function are private, lazy class finalization | 1348 // Even if class or function are private, lazy class finalization |
1362 // may later add overriding methods. | 1349 // may later add overriding methods. |
1363 return true; | 1350 return true; |
1364 } | 1351 } |
1365 Definition* callee_receiver = call->ArgumentAt(0); | 1352 Definition* callee_receiver = call->ArgumentAt(0); |
1366 ASSERT(callee_receiver != NULL); | 1353 ASSERT(callee_receiver != NULL); |
1367 const Function& function = flow_graph_->function(); | 1354 const Function& function = flow_graph_->function(); |
1368 if (function.IsDynamicFunction() && | 1355 if (function.IsDynamicFunction() && |
(...skipping 10 matching lines...) Expand all Loading... |
1379 name.ToCString(), cls.ToCString()); | 1366 name.ToCString(), cls.ToCString()); |
1380 } | 1367 } |
1381 thread()->cha()->AddToLeafClasses(cls); | 1368 thread()->cha()->AddToLeafClasses(cls); |
1382 return false; | 1369 return false; |
1383 } | 1370 } |
1384 } | 1371 } |
1385 return true; | 1372 return true; |
1386 } | 1373 } |
1387 | 1374 |
1388 | 1375 |
1389 bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call, | 1376 bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call, |
1390 bool allow_check) { | 1377 bool allow_check) { |
1391 ASSERT(call->HasICData()); | 1378 ASSERT(call->HasICData()); |
1392 const ICData& ic_data = *call->ic_data(); | 1379 const ICData& ic_data = *call->ic_data(); |
1393 ASSERT(ic_data.HasOneTarget()); | 1380 ASSERT(ic_data.HasOneTarget()); |
1394 GrowableArray<intptr_t> class_ids; | 1381 GrowableArray<intptr_t> class_ids; |
1395 ic_data.GetClassIdsAt(0, &class_ids); | 1382 ic_data.GetClassIdsAt(0, &class_ids); |
1396 ASSERT(class_ids.length() == 1); | 1383 ASSERT(class_ids.length() == 1); |
1397 // Inline implicit instance getter. | 1384 // Inline implicit instance getter. |
1398 const String& field_name = | 1385 const String& field_name = |
1399 String::Handle(Z, Field::NameFromGetter(call->function_name())); | 1386 String::Handle(Z, Field::NameFromGetter(call->function_name())); |
1400 const Field& field = | 1387 const Field& field = |
1401 Field::ZoneHandle(Z, GetField(class_ids[0], field_name)); | 1388 Field::ZoneHandle(Z, GetField(class_ids[0], field_name)); |
1402 ASSERT(!field.IsNull()); | 1389 ASSERT(!field.IsNull()); |
1403 | 1390 |
1404 if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) { | 1391 if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) { |
1405 if (!allow_check) { | 1392 if (!allow_check) { |
1406 return false; | 1393 return false; |
1407 } | 1394 } |
1408 AddReceiverCheck(call); | 1395 AddReceiverCheck(call); |
1409 } | 1396 } |
1410 LoadFieldInstr* load = new(Z) LoadFieldInstr( | 1397 LoadFieldInstr* load = new(Z) LoadFieldInstr( |
1411 new(Z) Value(call->ArgumentAt(0)), | 1398 new(Z) Value(call->ArgumentAt(0)), |
1412 &field, | 1399 &field, |
1413 AbstractType::ZoneHandle(Z, field.type()), | 1400 AbstractType::ZoneHandle(Z, field.type()), |
1414 call->token_pos()); | 1401 call->token_pos()); |
1415 load->set_is_immutable(field.is_final()); | 1402 load->set_is_immutable(field.is_final()); |
1416 if (field.guarded_cid() != kIllegalCid) { | 1403 |
1417 if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) { | 1404 // No guarded cid in precompiled mode. |
1418 load->set_result_cid(field.guarded_cid()); | 1405 ASSERT(field.guarded_cid() == kDynamicCid); |
1419 } | |
1420 flow_graph()->parsed_function().AddToGuardedFields(&field); | |
1421 } | |
1422 | 1406 |
1423 // Discard the environment from the original instruction because the load | 1407 // Discard the environment from the original instruction because the load |
1424 // can't deoptimize. | 1408 // can't deoptimize. |
1425 call->RemoveEnvironment(); | 1409 call->RemoveEnvironment(); |
1426 ReplaceCall(call, load); | 1410 ReplaceCall(call, load); |
1427 | 1411 |
1428 if (load->result_cid() != kDynamicCid) { | 1412 if (load->result_cid() != kDynamicCid) { |
1429 // Reset value types if guarded_cid was used. | 1413 // Reset value types if guarded_cid was used. |
1430 for (Value::Iterator it(load->input_use_list()); | 1414 for (Value::Iterator it(load->input_use_list()); |
1431 !it.Done(); | 1415 !it.Done(); |
1432 it.Advance()) { | 1416 it.Advance()) { |
1433 it.Current()->SetReachingType(NULL); | 1417 it.Current()->SetReachingType(NULL); |
1434 } | 1418 } |
1435 } | 1419 } |
1436 return true; | 1420 return true; |
1437 } | 1421 } |
1438 | 1422 |
1439 | 1423 |
1440 bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, | 1424 bool AotOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call, |
1441 MethodRecognizer::Kind getter) { | 1425 MethodRecognizer::Kind getter) { |
1442 if (!ShouldInlineSimd()) { | 1426 if (!ShouldInlineSimd()) { |
1443 return false; | 1427 return false; |
1444 } | 1428 } |
1445 AddCheckClass(call->ArgumentAt(0), | 1429 AddCheckClass(call->ArgumentAt(0), |
1446 ICData::ZoneHandle( | 1430 ICData::ZoneHandle( |
1447 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1431 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
1448 call->deopt_id(), | 1432 call->deopt_id(), |
1449 call->env(), | 1433 call->env(), |
1450 call); | 1434 call); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1505 mask, | 1489 mask, |
1506 call->deopt_id()); | 1490 call->deopt_id()); |
1507 ReplaceCall(call, instr); | 1491 ReplaceCall(call, instr); |
1508 return true; | 1492 return true; |
1509 } | 1493 } |
1510 UNREACHABLE(); | 1494 UNREACHABLE(); |
1511 return false; | 1495 return false; |
1512 } | 1496 } |
1513 | 1497 |
1514 | 1498 |
1515 bool FlowGraphOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call, | 1499 bool AotOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call, |
1516 MethodRecognizer::Kind getter) { | 1500 MethodRecognizer::Kind getter) { |
1517 if (!ShouldInlineSimd()) { | 1501 if (!ShouldInlineSimd()) { |
1518 return false; | 1502 return false; |
1519 } | 1503 } |
1520 AddCheckClass(call->ArgumentAt(0), | 1504 AddCheckClass(call->ArgumentAt(0), |
1521 ICData::ZoneHandle( | 1505 ICData::ZoneHandle( |
1522 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1506 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
1523 call->deopt_id(), | 1507 call->deopt_id(), |
1524 call->env(), | 1508 call->env(), |
1525 call); | 1509 call); |
1526 if ((getter == MethodRecognizer::kFloat64x2GetX) || | 1510 if ((getter == MethodRecognizer::kFloat64x2GetX) || |
1527 (getter == MethodRecognizer::kFloat64x2GetY)) { | 1511 (getter == MethodRecognizer::kFloat64x2GetY)) { |
1528 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr( | 1512 Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr( |
1529 getter, | 1513 getter, |
1530 new(Z) Value(call->ArgumentAt(0)), | 1514 new(Z) Value(call->ArgumentAt(0)), |
1531 0, | 1515 0, |
1532 call->deopt_id()); | 1516 call->deopt_id()); |
1533 ReplaceCall(call, instr); | 1517 ReplaceCall(call, instr); |
1534 return true; | 1518 return true; |
1535 } | 1519 } |
1536 UNREACHABLE(); | 1520 UNREACHABLE(); |
1537 return false; | 1521 return false; |
1538 } | 1522 } |
1539 | 1523 |
1540 | 1524 |
1541 bool FlowGraphOptimizer::InlineInt32x4Getter(InstanceCallInstr* call, | 1525 bool AotOptimizer::InlineInt32x4Getter(InstanceCallInstr* call, |
1542 MethodRecognizer::Kind getter) { | 1526 MethodRecognizer::Kind getter) { |
1543 if (!ShouldInlineSimd()) { | 1527 if (!ShouldInlineSimd()) { |
1544 return false; | 1528 return false; |
1545 } | 1529 } |
1546 AddCheckClass(call->ArgumentAt(0), | 1530 AddCheckClass(call->ArgumentAt(0), |
1547 ICData::ZoneHandle( | 1531 ICData::ZoneHandle( |
1548 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | 1532 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), |
1549 call->deopt_id(), | 1533 call->deopt_id(), |
1550 call->env(), | 1534 call->env(), |
1551 call); | 1535 call); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1606 Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr( | 1590 Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr( |
1607 getter, | 1591 getter, |
1608 new(Z) Value(call->ArgumentAt(0)), | 1592 new(Z) Value(call->ArgumentAt(0)), |
1609 call->deopt_id()); | 1593 call->deopt_id()); |
1610 ReplaceCall(call, instr); | 1594 ReplaceCall(call, instr); |
1611 return true; | 1595 return true; |
1612 } | 1596 } |
1613 } | 1597 } |
1614 | 1598 |
1615 | 1599 |
1616 bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, | 1600 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, |
1617 Token::Kind op_kind) { | 1601 Token::Kind op_kind) { |
1618 if (!ShouldInlineSimd()) { | 1602 if (!ShouldInlineSimd()) { |
1619 return false; | 1603 return false; |
1620 } | 1604 } |
1621 ASSERT(call->ArgumentCount() == 2); | 1605 ASSERT(call->ArgumentCount() == 2); |
1622 Definition* left = call->ArgumentAt(0); | 1606 Definition* left = call->ArgumentAt(0); |
1623 Definition* right = call->ArgumentAt(1); | 1607 Definition* right = call->ArgumentAt(1); |
1624 // Type check left. | 1608 // Type check left. |
1625 AddCheckClass(left, | 1609 AddCheckClass(left, |
1626 ICData::ZoneHandle( | 1610 ICData::ZoneHandle( |
(...skipping 12 matching lines...) Expand all Loading... |
1639 BinaryFloat32x4OpInstr* float32x4_bin_op = | 1623 BinaryFloat32x4OpInstr* float32x4_bin_op = |
1640 new(Z) BinaryFloat32x4OpInstr( | 1624 new(Z) BinaryFloat32x4OpInstr( |
1641 op_kind, new(Z) Value(left), new(Z) Value(right), | 1625 op_kind, new(Z) Value(left), new(Z) Value(right), |
1642 call->deopt_id()); | 1626 call->deopt_id()); |
1643 ReplaceCall(call, float32x4_bin_op); | 1627 ReplaceCall(call, float32x4_bin_op); |
1644 | 1628 |
1645 return true; | 1629 return true; |
1646 } | 1630 } |
1647 | 1631 |
1648 | 1632 |
1649 bool FlowGraphOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, | 1633 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, |
1650 Token::Kind op_kind) { | 1634 Token::Kind op_kind) { |
1651 if (!ShouldInlineSimd()) { | 1635 if (!ShouldInlineSimd()) { |
1652 return false; | 1636 return false; |
1653 } | 1637 } |
1654 ASSERT(call->ArgumentCount() == 2); | 1638 ASSERT(call->ArgumentCount() == 2); |
1655 Definition* left = call->ArgumentAt(0); | 1639 Definition* left = call->ArgumentAt(0); |
1656 Definition* right = call->ArgumentAt(1); | 1640 Definition* right = call->ArgumentAt(1); |
1657 // Type check left. | 1641 // Type check left. |
1658 AddCheckClass(left, | 1642 AddCheckClass(left, |
1659 ICData::ZoneHandle( | 1643 ICData::ZoneHandle( |
(...skipping 11 matching lines...) Expand all Loading... |
1671 // Replace call. | 1655 // Replace call. |
1672 BinaryInt32x4OpInstr* int32x4_bin_op = | 1656 BinaryInt32x4OpInstr* int32x4_bin_op = |
1673 new(Z) BinaryInt32x4OpInstr( | 1657 new(Z) BinaryInt32x4OpInstr( |
1674 op_kind, new(Z) Value(left), new(Z) Value(right), | 1658 op_kind, new(Z) Value(left), new(Z) Value(right), |
1675 call->deopt_id()); | 1659 call->deopt_id()); |
1676 ReplaceCall(call, int32x4_bin_op); | 1660 ReplaceCall(call, int32x4_bin_op); |
1677 return true; | 1661 return true; |
1678 } | 1662 } |
1679 | 1663 |
1680 | 1664 |
1681 bool FlowGraphOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, | 1665 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, |
1682 Token::Kind op_kind) { | 1666 Token::Kind op_kind) { |
1683 if (!ShouldInlineSimd()) { | 1667 if (!ShouldInlineSimd()) { |
1684 return false; | 1668 return false; |
1685 } | 1669 } |
1686 ASSERT(call->ArgumentCount() == 2); | 1670 ASSERT(call->ArgumentCount() == 2); |
1687 Definition* left = call->ArgumentAt(0); | 1671 Definition* left = call->ArgumentAt(0); |
1688 Definition* right = call->ArgumentAt(1); | 1672 Definition* right = call->ArgumentAt(1); |
1689 // Type check left. | 1673 // Type check left. |
1690 AddCheckClass(left, | 1674 AddCheckClass(left, |
1691 ICData::ZoneHandle( | 1675 ICData::ZoneHandle( |
(...skipping 13 matching lines...) Expand all Loading... |
1705 new(Z) BinaryFloat64x2OpInstr( | 1689 new(Z) BinaryFloat64x2OpInstr( |
1706 op_kind, new(Z) Value(left), new(Z) Value(right), | 1690 op_kind, new(Z) Value(left), new(Z) Value(right), |
1707 call->deopt_id()); | 1691 call->deopt_id()); |
1708 ReplaceCall(call, float64x2_bin_op); | 1692 ReplaceCall(call, float64x2_bin_op); |
1709 return true; | 1693 return true; |
1710 } | 1694 } |
1711 | 1695 |
1712 | 1696 |
1713 // Only unique implicit instance getters can be currently handled. | 1697 // Only unique implicit instance getters can be currently handled. |
1714 // Returns false if 'allow_check' is false and a check is needed. | 1698 // Returns false if 'allow_check' is false and a check is needed. |
1715 bool FlowGraphOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call, | 1699 bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call, |
1716 bool allow_check) { | 1700 bool allow_check) { |
1717 ASSERT(call->HasICData()); | 1701 ASSERT(call->HasICData()); |
1718 const ICData& ic_data = *call->ic_data(); | 1702 const ICData& ic_data = *call->ic_data(); |
1719 if (ic_data.NumberOfUsedChecks() == 0) { | 1703 if (ic_data.NumberOfUsedChecks() == 0) { |
1720 // No type feedback collected. | 1704 // No type feedback collected. |
1721 return false; | 1705 return false; |
1722 } | 1706 } |
1723 | 1707 |
1724 if (!ic_data.HasOneTarget()) { | 1708 if (!ic_data.HasOneTarget()) { |
1725 // Polymorphic sites are inlined like normal methods by conventional | 1709 // Polymorphic sites are inlined like normal methods by conventional |
1726 // inlining in FlowGraphInliner. | 1710 // inlining in FlowGraphInliner. |
1727 return false; | 1711 return false; |
1728 } | 1712 } |
1729 | 1713 |
1730 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); | 1714 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); |
1731 if (target.kind() != RawFunction::kImplicitGetter) { | 1715 if (target.kind() != RawFunction::kImplicitGetter) { |
1732 // Non-implicit getters are inlined like normal methods by conventional | 1716 // Non-implicit getters are inlined like normal methods by conventional |
1733 // inlining in FlowGraphInliner. | 1717 // inlining in FlowGraphInliner. |
1734 return false; | 1718 return false; |
1735 } | 1719 } |
1736 return InlineImplicitInstanceGetter(call, allow_check); | 1720 return InlineImplicitInstanceGetter(call, allow_check); |
1737 } | 1721 } |
1738 | 1722 |
1739 | 1723 |
1740 bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline( | 1724 bool AotOptimizer::TryReplaceInstanceCallWithInline( |
1741 InstanceCallInstr* call) { | 1725 InstanceCallInstr* call) { |
1742 Function& target = Function::Handle(Z); | 1726 Function& target = Function::Handle(Z); |
1743 GrowableArray<intptr_t> class_ids; | 1727 GrowableArray<intptr_t> class_ids; |
1744 call->ic_data()->GetCheckAt(0, &class_ids, &target); | 1728 call->ic_data()->GetCheckAt(0, &class_ids, &target); |
1745 const intptr_t receiver_cid = class_ids[0]; | 1729 const intptr_t receiver_cid = class_ids[0]; |
1746 | 1730 |
1747 TargetEntryInstr* entry; | 1731 TargetEntryInstr* entry; |
1748 Definition* last; | 1732 Definition* last; |
1749 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_, | 1733 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_, |
1750 receiver_cid, | 1734 receiver_cid, |
(...skipping 23 matching lines...) Expand all Loading... |
1774 last->LinkTo(call); | 1758 last->LinkTo(call); |
1775 // Remove through the iterator. | 1759 // Remove through the iterator. |
1776 ASSERT(current_iterator()->Current() == call); | 1760 ASSERT(current_iterator()->Current() == call); |
1777 current_iterator()->RemoveCurrentFromGraph(); | 1761 current_iterator()->RemoveCurrentFromGraph(); |
1778 call->set_previous(NULL); | 1762 call->set_previous(NULL); |
1779 call->set_next(NULL); | 1763 call->set_next(NULL); |
1780 return true; | 1764 return true; |
1781 } | 1765 } |
1782 | 1766 |
1783 | 1767 |
1784 void FlowGraphOptimizer::ReplaceWithMathCFunction( | 1768 void AotOptimizer::ReplaceWithMathCFunction( |
1785 InstanceCallInstr* call, | 1769 InstanceCallInstr* call, |
1786 MethodRecognizer::Kind recognized_kind) { | 1770 MethodRecognizer::Kind recognized_kind) { |
1787 AddReceiverCheck(call); | 1771 AddReceiverCheck(call); |
1788 ZoneGrowableArray<Value*>* args = | 1772 ZoneGrowableArray<Value*>* args = |
1789 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 1773 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
1790 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 1774 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
1791 args->Add(new(Z) Value(call->ArgumentAt(i))); | 1775 args->Add(new(Z) Value(call->ArgumentAt(i))); |
1792 } | 1776 } |
1793 InvokeMathCFunctionInstr* invoke = | 1777 InvokeMathCFunctionInstr* invoke = |
1794 new(Z) InvokeMathCFunctionInstr(args, | 1778 new(Z) InvokeMathCFunctionInstr(args, |
(...skipping 20 matching lines...) Expand all Loading... |
1815 case kTypedDataFloat32x4ArrayCid: | 1799 case kTypedDataFloat32x4ArrayCid: |
1816 case kTypedDataInt32x4ArrayCid: | 1800 case kTypedDataInt32x4ArrayCid: |
1817 return true; | 1801 return true; |
1818 default: | 1802 default: |
1819 return false; | 1803 return false; |
1820 } | 1804 } |
1821 } | 1805 } |
1822 | 1806 |
1823 | 1807 |
1824 // Inline only simple, frequently called core library methods. | 1808 // Inline only simple, frequently called core library methods. |
1825 bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | 1809 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { |
1826 ASSERT(call->HasICData()); | 1810 ASSERT(call->HasICData()); |
1827 const ICData& ic_data = *call->ic_data(); | 1811 const ICData& ic_data = *call->ic_data(); |
1828 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) { | 1812 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) { |
1829 // No type feedback collected or multiple targets found. | 1813 // No type feedback collected or multiple targets found. |
1830 return false; | 1814 return false; |
1831 } | 1815 } |
1832 | 1816 |
1833 Function& target = Function::Handle(Z); | 1817 Function& target = Function::Handle(Z); |
1834 GrowableArray<intptr_t> class_ids; | 1818 GrowableArray<intptr_t> class_ids; |
1835 ic_data.GetCheckAt(0, &class_ids, &target); | 1819 ic_data.GetCheckAt(0, &class_ids, &target); |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2048 new(Z) Value(int32_mask), | 2032 new(Z) Value(int32_mask), |
2049 call->deopt_id()); | 2033 call->deopt_id()); |
2050 ReplaceCall(call, bit_and); | 2034 ReplaceCall(call, bit_and); |
2051 return true; | 2035 return true; |
2052 } | 2036 } |
2053 } | 2037 } |
2054 return false; | 2038 return false; |
2055 } | 2039 } |
2056 | 2040 |
2057 | 2041 |
2058 bool FlowGraphOptimizer::TryInlineFloat32x4Constructor( | 2042 bool AotOptimizer::TryInlineFloat32x4Constructor( |
2059 StaticCallInstr* call, | 2043 StaticCallInstr* call, |
2060 MethodRecognizer::Kind recognized_kind) { | 2044 MethodRecognizer::Kind recognized_kind) { |
2061 if (FLAG_precompilation) { | 2045 // Cannot handle unboxed instructions. |
2062 // Cannot handle unboxed instructions. | 2046 ASSERT(FLAG_precompilation); |
2063 return false; | |
2064 } | |
2065 if (!ShouldInlineSimd()) { | |
2066 return false; | |
2067 } | |
2068 if (recognized_kind == MethodRecognizer::kFloat32x4Zero) { | |
2069 Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr(); | |
2070 ReplaceCall(call, zero); | |
2071 return true; | |
2072 } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) { | |
2073 Float32x4SplatInstr* splat = | |
2074 new(Z) Float32x4SplatInstr( | |
2075 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
2076 ReplaceCall(call, splat); | |
2077 return true; | |
2078 } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) { | |
2079 Float32x4ConstructorInstr* con = | |
2080 new(Z) Float32x4ConstructorInstr( | |
2081 new(Z) Value(call->ArgumentAt(1)), | |
2082 new(Z) Value(call->ArgumentAt(2)), | |
2083 new(Z) Value(call->ArgumentAt(3)), | |
2084 new(Z) Value(call->ArgumentAt(4)), | |
2085 call->deopt_id()); | |
2086 ReplaceCall(call, con); | |
2087 return true; | |
2088 } else if (recognized_kind == MethodRecognizer::kFloat32x4FromInt32x4Bits) { | |
2089 Int32x4ToFloat32x4Instr* cast = | |
2090 new(Z) Int32x4ToFloat32x4Instr( | |
2091 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
2092 ReplaceCall(call, cast); | |
2093 return true; | |
2094 } else if (recognized_kind == MethodRecognizer::kFloat32x4FromFloat64x2) { | |
2095 Float64x2ToFloat32x4Instr* cast = | |
2096 new(Z) Float64x2ToFloat32x4Instr( | |
2097 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
2098 ReplaceCall(call, cast); | |
2099 return true; | |
2100 } | |
2101 return false; | 2047 return false; |
2102 } | 2048 } |
2103 | 2049 |
2104 | 2050 |
2105 bool FlowGraphOptimizer::TryInlineFloat64x2Constructor( | 2051 bool AotOptimizer::TryInlineFloat64x2Constructor( |
2106 StaticCallInstr* call, | 2052 StaticCallInstr* call, |
2107 MethodRecognizer::Kind recognized_kind) { | 2053 MethodRecognizer::Kind recognized_kind) { |
2108 if (FLAG_precompilation) { | 2054 // Cannot handle unboxed instructions. |
2109 // Cannot handle unboxed instructions. | 2055 ASSERT(FLAG_precompilation); |
2110 return false; | |
2111 } | |
2112 if (!ShouldInlineSimd()) { | |
2113 return false; | |
2114 } | |
2115 if (recognized_kind == MethodRecognizer::kFloat64x2Zero) { | |
2116 Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr(); | |
2117 ReplaceCall(call, zero); | |
2118 return true; | |
2119 } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) { | |
2120 Float64x2SplatInstr* splat = | |
2121 new(Z) Float64x2SplatInstr( | |
2122 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
2123 ReplaceCall(call, splat); | |
2124 return true; | |
2125 } else if (recognized_kind == MethodRecognizer::kFloat64x2Constructor) { | |
2126 Float64x2ConstructorInstr* con = | |
2127 new(Z) Float64x2ConstructorInstr( | |
2128 new(Z) Value(call->ArgumentAt(1)), | |
2129 new(Z) Value(call->ArgumentAt(2)), | |
2130 call->deopt_id()); | |
2131 ReplaceCall(call, con); | |
2132 return true; | |
2133 } else if (recognized_kind == MethodRecognizer::kFloat64x2FromFloat32x4) { | |
2134 Float32x4ToFloat64x2Instr* cast = | |
2135 new(Z) Float32x4ToFloat64x2Instr( | |
2136 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
2137 ReplaceCall(call, cast); | |
2138 return true; | |
2139 } | |
2140 return false; | 2056 return false; |
2141 } | 2057 } |
2142 | 2058 |
2143 | 2059 |
2144 bool FlowGraphOptimizer::TryInlineInt32x4Constructor( | 2060 bool AotOptimizer::TryInlineInt32x4Constructor( |
2145 StaticCallInstr* call, | 2061 StaticCallInstr* call, |
2146 MethodRecognizer::Kind recognized_kind) { | 2062 MethodRecognizer::Kind recognized_kind) { |
2147 if (FLAG_precompilation) { | 2063 // Cannot handle unboxed instructions. |
2148 // Cannot handle unboxed instructions. | 2064 ASSERT(FLAG_precompilation); |
2149 return false; | |
2150 } | |
2151 if (!ShouldInlineSimd()) { | |
2152 return false; | |
2153 } | |
2154 if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) { | |
2155 Int32x4BoolConstructorInstr* con = | |
2156 new(Z) Int32x4BoolConstructorInstr( | |
2157 new(Z) Value(call->ArgumentAt(1)), | |
2158 new(Z) Value(call->ArgumentAt(2)), | |
2159 new(Z) Value(call->ArgumentAt(3)), | |
2160 new(Z) Value(call->ArgumentAt(4)), | |
2161 call->deopt_id()); | |
2162 ReplaceCall(call, con); | |
2163 return true; | |
2164 } else if (recognized_kind == MethodRecognizer::kInt32x4FromFloat32x4Bits) { | |
2165 Float32x4ToInt32x4Instr* cast = | |
2166 new(Z) Float32x4ToInt32x4Instr( | |
2167 new(Z) Value(call->ArgumentAt(1)), call->deopt_id()); | |
2168 ReplaceCall(call, cast); | |
2169 return true; | |
2170 } else if (recognized_kind == MethodRecognizer::kInt32x4Constructor) { | |
2171 Int32x4ConstructorInstr* con = | |
2172 new(Z) Int32x4ConstructorInstr( | |
2173 new(Z) Value(call->ArgumentAt(1)), | |
2174 new(Z) Value(call->ArgumentAt(2)), | |
2175 new(Z) Value(call->ArgumentAt(3)), | |
2176 new(Z) Value(call->ArgumentAt(4)), | |
2177 call->deopt_id()); | |
2178 ReplaceCall(call, con); | |
2179 return true; | |
2180 } | |
2181 return false; | 2065 return false; |
2182 } | 2066 } |
2183 | 2067 |
2184 | 2068 |
2185 bool FlowGraphOptimizer::TryInlineFloat32x4Method( | 2069 bool AotOptimizer::TryInlineFloat32x4Method( |
2186 InstanceCallInstr* call, | 2070 InstanceCallInstr* call, |
2187 MethodRecognizer::Kind recognized_kind) { | 2071 MethodRecognizer::Kind recognized_kind) { |
2188 if (!ShouldInlineSimd()) { | 2072 // Cannot handle unboxed instructions. |
2189 return false; | 2073 return false; |
2190 } | |
2191 ASSERT(call->HasICData()); | |
2192 switch (recognized_kind) { | |
2193 case MethodRecognizer::kFloat32x4ShuffleX: | |
2194 case MethodRecognizer::kFloat32x4ShuffleY: | |
2195 case MethodRecognizer::kFloat32x4ShuffleZ: | |
2196 case MethodRecognizer::kFloat32x4ShuffleW: | |
2197 case MethodRecognizer::kFloat32x4GetSignMask: | |
2198 ASSERT(call->ic_data()->HasReceiverClassId(kFloat32x4Cid)); | |
2199 ASSERT(call->ic_data()->HasOneTarget()); | |
2200 return InlineFloat32x4Getter(call, recognized_kind); | |
2201 | |
2202 case MethodRecognizer::kFloat32x4Equal: | |
2203 case MethodRecognizer::kFloat32x4GreaterThan: | |
2204 case MethodRecognizer::kFloat32x4GreaterThanOrEqual: | |
2205 case MethodRecognizer::kFloat32x4LessThan: | |
2206 case MethodRecognizer::kFloat32x4LessThanOrEqual: | |
2207 case MethodRecognizer::kFloat32x4NotEqual: { | |
2208 Definition* left = call->ArgumentAt(0); | |
2209 Definition* right = call->ArgumentAt(1); | |
2210 // Type check left. | |
2211 AddCheckClass(left, | |
2212 ICData::ZoneHandle( | |
2213 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2214 call->deopt_id(), | |
2215 call->env(), | |
2216 call); | |
2217 // Replace call. | |
2218 Float32x4ComparisonInstr* cmp = | |
2219 new(Z) Float32x4ComparisonInstr(recognized_kind, | |
2220 new(Z) Value(left), | |
2221 new(Z) Value(right), | |
2222 call->deopt_id()); | |
2223 ReplaceCall(call, cmp); | |
2224 return true; | |
2225 } | |
2226 case MethodRecognizer::kFloat32x4Min: | |
2227 case MethodRecognizer::kFloat32x4Max: { | |
2228 Definition* left = call->ArgumentAt(0); | |
2229 Definition* right = call->ArgumentAt(1); | |
2230 // Type check left. | |
2231 AddCheckClass(left, | |
2232 ICData::ZoneHandle( | |
2233 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2234 call->deopt_id(), | |
2235 call->env(), | |
2236 call); | |
2237 Float32x4MinMaxInstr* minmax = | |
2238 new(Z) Float32x4MinMaxInstr( | |
2239 recognized_kind, | |
2240 new(Z) Value(left), | |
2241 new(Z) Value(right), | |
2242 call->deopt_id()); | |
2243 ReplaceCall(call, minmax); | |
2244 return true; | |
2245 } | |
2246 case MethodRecognizer::kFloat32x4Scale: { | |
2247 Definition* left = call->ArgumentAt(0); | |
2248 Definition* right = call->ArgumentAt(1); | |
2249 // Type check left. | |
2250 AddCheckClass(left, | |
2251 ICData::ZoneHandle( | |
2252 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2253 call->deopt_id(), | |
2254 call->env(), | |
2255 call); | |
2256 // Left and right values are swapped when handed to the instruction, | |
2257 // this is done so that the double value is loaded into the output | |
2258 // register and can be destroyed. | |
2259 Float32x4ScaleInstr* scale = | |
2260 new(Z) Float32x4ScaleInstr(recognized_kind, | |
2261 new(Z) Value(right), | |
2262 new(Z) Value(left), | |
2263 call->deopt_id()); | |
2264 ReplaceCall(call, scale); | |
2265 return true; | |
2266 } | |
2267 case MethodRecognizer::kFloat32x4Sqrt: | |
2268 case MethodRecognizer::kFloat32x4ReciprocalSqrt: | |
2269 case MethodRecognizer::kFloat32x4Reciprocal: { | |
2270 Definition* left = call->ArgumentAt(0); | |
2271 AddCheckClass(left, | |
2272 ICData::ZoneHandle( | |
2273 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2274 call->deopt_id(), | |
2275 call->env(), | |
2276 call); | |
2277 Float32x4SqrtInstr* sqrt = | |
2278 new(Z) Float32x4SqrtInstr(recognized_kind, | |
2279 new(Z) Value(left), | |
2280 call->deopt_id()); | |
2281 ReplaceCall(call, sqrt); | |
2282 return true; | |
2283 } | |
2284 case MethodRecognizer::kFloat32x4WithX: | |
2285 case MethodRecognizer::kFloat32x4WithY: | |
2286 case MethodRecognizer::kFloat32x4WithZ: | |
2287 case MethodRecognizer::kFloat32x4WithW: { | |
2288 Definition* left = call->ArgumentAt(0); | |
2289 Definition* right = call->ArgumentAt(1); | |
2290 // Type check left. | |
2291 AddCheckClass(left, | |
2292 ICData::ZoneHandle( | |
2293 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2294 call->deopt_id(), | |
2295 call->env(), | |
2296 call); | |
2297 Float32x4WithInstr* with = new(Z) Float32x4WithInstr(recognized_kind, | |
2298 new(Z) Value(left), | |
2299 new(Z) Value(right), | |
2300 call->deopt_id()); | |
2301 ReplaceCall(call, with); | |
2302 return true; | |
2303 } | |
2304 case MethodRecognizer::kFloat32x4Absolute: | |
2305 case MethodRecognizer::kFloat32x4Negate: { | |
2306 Definition* left = call->ArgumentAt(0); | |
2307 // Type check left. | |
2308 AddCheckClass(left, | |
2309 ICData::ZoneHandle( | |
2310 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2311 call->deopt_id(), | |
2312 call->env(), | |
2313 call); | |
2314 Float32x4ZeroArgInstr* zeroArg = | |
2315 new(Z) Float32x4ZeroArgInstr( | |
2316 recognized_kind, new(Z) Value(left), call->deopt_id()); | |
2317 ReplaceCall(call, zeroArg); | |
2318 return true; | |
2319 } | |
2320 case MethodRecognizer::kFloat32x4Clamp: { | |
2321 Definition* left = call->ArgumentAt(0); | |
2322 Definition* lower = call->ArgumentAt(1); | |
2323 Definition* upper = call->ArgumentAt(2); | |
2324 // Type check left. | |
2325 AddCheckClass(left, | |
2326 ICData::ZoneHandle( | |
2327 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2328 call->deopt_id(), | |
2329 call->env(), | |
2330 call); | |
2331 Float32x4ClampInstr* clamp = new(Z) Float32x4ClampInstr( | |
2332 new(Z) Value(left), | |
2333 new(Z) Value(lower), | |
2334 new(Z) Value(upper), | |
2335 call->deopt_id()); | |
2336 ReplaceCall(call, clamp); | |
2337 return true; | |
2338 } | |
2339 case MethodRecognizer::kFloat32x4ShuffleMix: | |
2340 case MethodRecognizer::kFloat32x4Shuffle: { | |
2341 return InlineFloat32x4Getter(call, recognized_kind); | |
2342 } | |
2343 default: | |
2344 return false; | |
2345 } | |
2346 } | 2074 } |
2347 | 2075 |
2348 | 2076 |
2349 bool FlowGraphOptimizer::TryInlineFloat64x2Method( | 2077 bool AotOptimizer::TryInlineFloat64x2Method( |
2350 InstanceCallInstr* call, | 2078 InstanceCallInstr* call, |
2351 MethodRecognizer::Kind recognized_kind) { | 2079 MethodRecognizer::Kind recognized_kind) { |
2352 if (!ShouldInlineSimd()) { | 2080 // Cannot handle unboxed instructions. |
2353 return false; | 2081 return false; |
2354 } | |
2355 ASSERT(call->HasICData()); | |
2356 switch (recognized_kind) { | |
2357 case MethodRecognizer::kFloat64x2GetX: | |
2358 case MethodRecognizer::kFloat64x2GetY: | |
2359 ASSERT(call->ic_data()->HasReceiverClassId(kFloat64x2Cid)); | |
2360 ASSERT(call->ic_data()->HasOneTarget()); | |
2361 return InlineFloat64x2Getter(call, recognized_kind); | |
2362 case MethodRecognizer::kFloat64x2Negate: | |
2363 case MethodRecognizer::kFloat64x2Abs: | |
2364 case MethodRecognizer::kFloat64x2Sqrt: | |
2365 case MethodRecognizer::kFloat64x2GetSignMask: { | |
2366 Definition* left = call->ArgumentAt(0); | |
2367 // Type check left. | |
2368 AddCheckClass(left, | |
2369 ICData::ZoneHandle( | |
2370 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2371 call->deopt_id(), | |
2372 call->env(), | |
2373 call); | |
2374 Float64x2ZeroArgInstr* zeroArg = | |
2375 new(Z) Float64x2ZeroArgInstr( | |
2376 recognized_kind, new(Z) Value(left), call->deopt_id()); | |
2377 ReplaceCall(call, zeroArg); | |
2378 return true; | |
2379 } | |
2380 case MethodRecognizer::kFloat64x2Scale: | |
2381 case MethodRecognizer::kFloat64x2WithX: | |
2382 case MethodRecognizer::kFloat64x2WithY: | |
2383 case MethodRecognizer::kFloat64x2Min: | |
2384 case MethodRecognizer::kFloat64x2Max: { | |
2385 Definition* left = call->ArgumentAt(0); | |
2386 Definition* right = call->ArgumentAt(1); | |
2387 // Type check left. | |
2388 AddCheckClass(left, | |
2389 ICData::ZoneHandle( | |
2390 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2391 call->deopt_id(), | |
2392 call->env(), | |
2393 call); | |
2394 Float64x2OneArgInstr* zeroArg = | |
2395 new(Z) Float64x2OneArgInstr(recognized_kind, | |
2396 new(Z) Value(left), | |
2397 new(Z) Value(right), | |
2398 call->deopt_id()); | |
2399 ReplaceCall(call, zeroArg); | |
2400 return true; | |
2401 } | |
2402 default: | |
2403 return false; | |
2404 } | |
2405 } | 2082 } |
2406 | 2083 |
2407 | 2084 |
2408 bool FlowGraphOptimizer::TryInlineInt32x4Method( | 2085 bool AotOptimizer::TryInlineInt32x4Method( |
2409 InstanceCallInstr* call, | 2086 InstanceCallInstr* call, |
2410 MethodRecognizer::Kind recognized_kind) { | 2087 MethodRecognizer::Kind recognized_kind) { |
2411 if (!ShouldInlineSimd()) { | 2088 // Cannot handle unboxed instructions. |
2412 return false; | 2089 return false; |
2413 } | |
2414 ASSERT(call->HasICData()); | |
2415 switch (recognized_kind) { | |
2416 case MethodRecognizer::kInt32x4ShuffleMix: | |
2417 case MethodRecognizer::kInt32x4Shuffle: | |
2418 case MethodRecognizer::kInt32x4GetFlagX: | |
2419 case MethodRecognizer::kInt32x4GetFlagY: | |
2420 case MethodRecognizer::kInt32x4GetFlagZ: | |
2421 case MethodRecognizer::kInt32x4GetFlagW: | |
2422 case MethodRecognizer::kInt32x4GetSignMask: | |
2423 ASSERT(call->ic_data()->HasReceiverClassId(kInt32x4Cid)); | |
2424 ASSERT(call->ic_data()->HasOneTarget()); | |
2425 return InlineInt32x4Getter(call, recognized_kind); | |
2426 | |
2427 case MethodRecognizer::kInt32x4Select: { | |
2428 Definition* mask = call->ArgumentAt(0); | |
2429 Definition* trueValue = call->ArgumentAt(1); | |
2430 Definition* falseValue = call->ArgumentAt(2); | |
2431 // Type check left. | |
2432 AddCheckClass(mask, | |
2433 ICData::ZoneHandle( | |
2434 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2435 call->deopt_id(), | |
2436 call->env(), | |
2437 call); | |
2438 Int32x4SelectInstr* select = new(Z) Int32x4SelectInstr( | |
2439 new(Z) Value(mask), | |
2440 new(Z) Value(trueValue), | |
2441 new(Z) Value(falseValue), | |
2442 call->deopt_id()); | |
2443 ReplaceCall(call, select); | |
2444 return true; | |
2445 } | |
2446 case MethodRecognizer::kInt32x4WithFlagX: | |
2447 case MethodRecognizer::kInt32x4WithFlagY: | |
2448 case MethodRecognizer::kInt32x4WithFlagZ: | |
2449 case MethodRecognizer::kInt32x4WithFlagW: { | |
2450 Definition* left = call->ArgumentAt(0); | |
2451 Definition* flag = call->ArgumentAt(1); | |
2452 // Type check left. | |
2453 AddCheckClass(left, | |
2454 ICData::ZoneHandle( | |
2455 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), | |
2456 call->deopt_id(), | |
2457 call->env(), | |
2458 call); | |
2459 Int32x4SetFlagInstr* setFlag = new(Z) Int32x4SetFlagInstr( | |
2460 recognized_kind, | |
2461 new(Z) Value(left), | |
2462 new(Z) Value(flag), | |
2463 call->deopt_id()); | |
2464 ReplaceCall(call, setFlag); | |
2465 return true; | |
2466 } | |
2467 default: | |
2468 return false; | |
2469 } | |
2470 } | 2090 } |
2471 | 2091 |
2472 | 2092 |
2473 // If type tests specified by 'ic_data' do not depend on type arguments, | 2093 // If type tests specified by 'ic_data' do not depend on type arguments, |
2474 // return mapping cid->result in 'results' (i : cid; i + 1: result). | 2094 // return mapping cid->result in 'results' (i : cid; i + 1: result). |
2475 // If all tests yield the same result, return it otherwise return Bool::null. | 2095 // If all tests yield the same result, return it otherwise return Bool::null. |
2476 // If no mapping is possible, 'results' is empty. | 2096 // If no mapping is possible, 'results' is empty. |
2477 // An instance-of test returning all same results can be converted to a class | 2097 // An instance-of test returning all same results can be converted to a class |
2478 // check. | 2098 // check. |
2479 RawBool* FlowGraphOptimizer::InstanceOfAsBool( | 2099 RawBool* AotOptimizer::InstanceOfAsBool( |
2480 const ICData& ic_data, | 2100 const ICData& ic_data, |
2481 const AbstractType& type, | 2101 const AbstractType& type, |
2482 ZoneGrowableArray<intptr_t>* results) const { | 2102 ZoneGrowableArray<intptr_t>* results) const { |
2483 ASSERT(results->is_empty()); | 2103 ASSERT(results->is_empty()); |
2484 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. | 2104 ASSERT(ic_data.NumArgsTested() == 1); // Unary checks only. |
2485 if (type.IsFunctionType() || type.IsDartFunctionType() || | 2105 if (type.IsFunctionType() || type.IsDartFunctionType() || |
2486 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) { | 2106 !type.IsInstantiated() || type.IsMalformedOrMalbounded()) { |
2487 return Bool::null(); | 2107 return Bool::null(); |
2488 } | 2108 } |
2489 const Class& type_class = Class::Handle(Z, type.type_class()); | 2109 const Class& type_class = Class::Handle(Z, type.type_class()); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2528 if (is_subtype != prev.value()) { | 2148 if (is_subtype != prev.value()) { |
2529 results_differ = true; | 2149 results_differ = true; |
2530 } | 2150 } |
2531 } | 2151 } |
2532 } | 2152 } |
2533 return results_differ ? Bool::null() : prev.raw(); | 2153 return results_differ ? Bool::null() : prev.raw(); |
2534 } | 2154 } |
2535 | 2155 |
2536 | 2156 |
2537 // Returns true if checking against this type is a direct class id comparison. | 2157 // Returns true if checking against this type is a direct class id comparison. |
2538 bool FlowGraphOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { | 2158 bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { |
2539 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 2159 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
2540 // Requires CHA. | 2160 // Requires CHA. |
2541 if (!type.IsInstantiated()) return false; | 2161 if (!type.IsInstantiated()) return false; |
2542 // Function types have different type checking rules. | 2162 // Function types have different type checking rules. |
2543 if (type.IsFunctionType()) return false; | 2163 if (type.IsFunctionType()) return false; |
2544 const Class& type_class = Class::Handle(type.type_class()); | 2164 const Class& type_class = Class::Handle(type.type_class()); |
2545 // Could be an interface check? | 2165 // Could be an interface check? |
2546 if (CHA::IsImplemented(type_class)) return false; | 2166 if (CHA::IsImplemented(type_class)) return false; |
2547 // Check if there are subclasses. | 2167 // Check if there are subclasses. |
2548 if (CHA::HasSubclasses(type_class)) { | 2168 if (CHA::HasSubclasses(type_class)) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2632 TryAddTest(results, kBigintCid, true); | 2252 TryAddTest(results, kBigintCid, true); |
2633 // Cannot deoptimize since all tests returning true have been added. | 2253 // Cannot deoptimize since all tests returning true have been added. |
2634 return false; | 2254 return false; |
2635 } | 2255 } |
2636 | 2256 |
2637 return true; // May deoptimize since we have not identified all 'true' tests. | 2257 return true; // May deoptimize since we have not identified all 'true' tests. |
2638 } | 2258 } |
2639 | 2259 |
2640 | 2260 |
2641 // TODO(srdjan): Use ICData to check if always true or false. | 2261 // TODO(srdjan): Use ICData to check if always true or false. |
2642 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 2262 void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
2643 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 2263 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
2644 Definition* left = call->ArgumentAt(0); | 2264 Definition* left = call->ArgumentAt(0); |
2645 Definition* type_args = NULL; | 2265 Definition* type_args = NULL; |
2646 AbstractType& type = AbstractType::ZoneHandle(Z); | 2266 AbstractType& type = AbstractType::ZoneHandle(Z); |
2647 bool negate = false; | 2267 bool negate = false; |
2648 if (call->ArgumentCount() == 2) { | 2268 if (call->ArgumentCount() == 2) { |
2649 type_args = flow_graph()->constant_null(); | 2269 type_args = flow_graph()->constant_null(); |
2650 if (call->function_name().raw() == | 2270 if (call->function_name().raw() == |
2651 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) { | 2271 Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) { |
2652 type = Type::Number(); | 2272 type = Type::Number(); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2740 new(Z) Value(left), | 2360 new(Z) Value(left), |
2741 new(Z) Value(type_args), | 2361 new(Z) Value(type_args), |
2742 type, | 2362 type, |
2743 negate, | 2363 negate, |
2744 call->deopt_id()); | 2364 call->deopt_id()); |
2745 ReplaceCall(call, instance_of); | 2365 ReplaceCall(call, instance_of); |
2746 } | 2366 } |
2747 | 2367 |
2748 | 2368 |
2749 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). | 2369 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). |
2750 void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { | 2370 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
2751 ASSERT(Token::IsTypeCastOperator(call->token_kind())); | 2371 ASSERT(Token::IsTypeCastOperator(call->token_kind())); |
2752 Definition* left = call->ArgumentAt(0); | 2372 Definition* left = call->ArgumentAt(0); |
2753 Definition* type_args = call->ArgumentAt(1); | 2373 Definition* type_args = call->ArgumentAt(1); |
2754 const AbstractType& type = | 2374 const AbstractType& type = |
2755 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); | 2375 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); |
2756 ASSERT(!type.IsMalformedOrMalbounded()); | 2376 ASSERT(!type.IsMalformedOrMalbounded()); |
2757 const ICData& unary_checks = | 2377 const ICData& unary_checks = |
2758 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); | 2378 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); |
2759 if ((unary_checks.NumberOfChecks() > 0) && | 2379 if ((unary_checks.NumberOfChecks() > 0) && |
2760 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { | 2380 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { |
(...skipping 22 matching lines...) Expand all Loading... |
2783 new(Z) AssertAssignableInstr(call->token_pos(), | 2403 new(Z) AssertAssignableInstr(call->token_pos(), |
2784 new(Z) Value(left), | 2404 new(Z) Value(left), |
2785 new(Z) Value(type_args), | 2405 new(Z) Value(type_args), |
2786 type, | 2406 type, |
2787 dst_name, | 2407 dst_name, |
2788 call->deopt_id()); | 2408 call->deopt_id()); |
2789 ReplaceCall(call, assert_as); | 2409 ReplaceCall(call, assert_as); |
2790 } | 2410 } |
2791 | 2411 |
2792 | 2412 |
2793 bool FlowGraphOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) { | 2413 bool AotOptimizer::IsBlackListedForInlining(intptr_t call_deopt_id) { |
2794 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { | 2414 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { |
2795 if ((*inlining_black_list_)[i] == call_deopt_id) return true; | 2415 if ((*inlining_black_list_)[i] == call_deopt_id) return true; |
2796 } | 2416 } |
2797 return false; | 2417 return false; |
2798 } | 2418 } |
2799 | 2419 |
2800 // Special optimizations when running in --noopt mode. | 2420 // Special optimizations when running in --noopt mode. |
2801 void FlowGraphOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { | 2421 void AotOptimizer::InstanceCallNoopt(InstanceCallInstr* instr) { |
2802 // TODO(srdjan): Investigate other attempts, as they are not allowed to | 2422 // TODO(srdjan): Investigate other attempts, as they are not allowed to |
2803 // deoptimize. | 2423 // deoptimize. |
2804 | 2424 |
2805 // Type test is special as it always gets converted into inlined code. | 2425 // Type test is special as it always gets converted into inlined code. |
2806 const Token::Kind op_kind = instr->token_kind(); | 2426 const Token::Kind op_kind = instr->token_kind(); |
2807 if (Token::IsTypeTestOperator(op_kind)) { | 2427 if (Token::IsTypeTestOperator(op_kind)) { |
2808 ReplaceWithInstanceOf(instr); | 2428 ReplaceWithInstanceOf(instr); |
2809 return; | 2429 return; |
2810 } | 2430 } |
2811 if (Token::IsTypeCastOperator(op_kind)) { | 2431 if (Token::IsTypeCastOperator(op_kind)) { |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2930 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, | 2550 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, |
2931 /* with_checks = */ false); | 2551 /* with_checks = */ false); |
2932 instr->ReplaceWith(call, current_iterator()); | 2552 instr->ReplaceWith(call, current_iterator()); |
2933 return; | 2553 return; |
2934 } | 2554 } |
2935 } | 2555 } |
2936 | 2556 |
2937 | 2557 |
2938 // Tries to optimize instance call by replacing it with a faster instruction | 2558 // Tries to optimize instance call by replacing it with a faster instruction |
2939 // (e.g, binary op, field load, ..). | 2559 // (e.g, binary op, field load, ..). |
2940 void FlowGraphOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 2560 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
2941 if (FLAG_precompilation) { | 2561 ASSERT(FLAG_precompilation); |
2942 InstanceCallNoopt(instr); | 2562 InstanceCallNoopt(instr); |
2943 return; | |
2944 } | |
2945 | |
2946 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { | |
2947 return; | |
2948 } | |
2949 const Token::Kind op_kind = instr->token_kind(); | |
2950 | |
2951 // Type test is special as it always gets converted into inlined code. | |
2952 if (Token::IsTypeTestOperator(op_kind)) { | |
2953 ReplaceWithInstanceOf(instr); | |
2954 return; | |
2955 } | |
2956 | |
2957 if (Token::IsTypeCastOperator(op_kind)) { | |
2958 ReplaceWithTypeCast(instr); | |
2959 return; | |
2960 } | |
2961 | |
2962 const ICData& unary_checks = | |
2963 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | |
2964 | |
2965 const intptr_t max_checks = (op_kind == Token::kEQ) | |
2966 ? FLAG_max_equality_polymorphic_checks | |
2967 : FLAG_max_polymorphic_checks; | |
2968 if ((unary_checks.NumberOfChecks() > max_checks) && | |
2969 InstanceCallNeedsClassCheck(instr, RawFunction::kRegularFunction)) { | |
2970 // Too many checks, it will be megamorphic which needs unary checks. | |
2971 instr->set_ic_data(&unary_checks); | |
2972 return; | |
2973 } | |
2974 | |
2975 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { | |
2976 return; | |
2977 } | |
2978 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { | |
2979 return; | |
2980 } | |
2981 | |
2982 if (op_kind == Token::kEQ && TryReplaceWithEqualityOp(instr, op_kind)) { | |
2983 return; | |
2984 } | |
2985 | |
2986 if (Token::IsRelationalOperator(op_kind) && | |
2987 TryReplaceWithRelationalOp(instr, op_kind)) { | |
2988 return; | |
2989 } | |
2990 | |
2991 if (Token::IsBinaryOperator(op_kind) && | |
2992 TryReplaceWithBinaryOp(instr, op_kind)) { | |
2993 return; | |
2994 } | |
2995 if (Token::IsUnaryOperator(op_kind) && | |
2996 TryReplaceWithUnaryOp(instr, op_kind)) { | |
2997 return; | |
2998 } | |
2999 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) { | |
3000 return; | |
3001 } | |
3002 if ((op_kind == Token::kSET) && | |
3003 TryInlineInstanceSetter(instr, unary_checks)) { | |
3004 return; | |
3005 } | |
3006 if (TryInlineInstanceMethod(instr)) { | |
3007 return; | |
3008 } | |
3009 | |
3010 bool has_one_target = unary_checks.HasOneTarget(); | |
3011 | |
3012 if (has_one_target) { | |
3013 // Check if the single target is a polymorphic target, if it is, | |
3014 // we don't have one target. | |
3015 const Function& target = | |
3016 Function::Handle(Z, unary_checks.GetTargetAt(0)); | |
3017 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target); | |
3018 has_one_target = !polymorphic_target; | |
3019 } | |
3020 | |
3021 if (has_one_target) { | |
3022 RawFunction::Kind function_kind = | |
3023 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind(); | |
3024 if (!InstanceCallNeedsClassCheck(instr, function_kind)) { | |
3025 PolymorphicInstanceCallInstr* call = | |
3026 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | |
3027 /* call_with_checks = */ false); | |
3028 instr->ReplaceWith(call, current_iterator()); | |
3029 return; | |
3030 } | |
3031 } | |
3032 | |
3033 if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) { | |
3034 bool call_with_checks; | |
3035 if (has_one_target && FLAG_polymorphic_with_deopt) { | |
3036 // Type propagation has not run yet, we cannot eliminate the check. | |
3037 AddReceiverCheck(instr); | |
3038 // Call can still deoptimize, do not detach environment from instr. | |
3039 call_with_checks = false; | |
3040 } else { | |
3041 call_with_checks = true; | |
3042 } | |
3043 PolymorphicInstanceCallInstr* call = | |
3044 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, | |
3045 call_with_checks); | |
3046 instr->ReplaceWith(call, current_iterator()); | |
3047 } | |
3048 } | 2563 } |
3049 | 2564 |
3050 | 2565 |
3051 void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) { | 2566 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { |
3052 if (!CanUnboxDouble()) { | 2567 if (!CanUnboxDouble()) { |
3053 return; | 2568 return; |
3054 } | 2569 } |
3055 MethodRecognizer::Kind recognized_kind = | 2570 MethodRecognizer::Kind recognized_kind = |
3056 MethodRecognizer::RecognizeKind(call->function()); | 2571 MethodRecognizer::RecognizeKind(call->function()); |
3057 MathUnaryInstr::MathUnaryKind unary_kind; | 2572 MathUnaryInstr::MathUnaryKind unary_kind; |
3058 switch (recognized_kind) { | 2573 switch (recognized_kind) { |
3059 case MethodRecognizer::kMathSqrt: | 2574 case MethodRecognizer::kMathSqrt: |
3060 unary_kind = MathUnaryInstr::kSqrt; | 2575 unary_kind = MathUnaryInstr::kSqrt; |
3061 break; | 2576 break; |
3062 case MethodRecognizer::kMathSin: | 2577 case MethodRecognizer::kMathSin: |
3063 unary_kind = MathUnaryInstr::kSin; | 2578 unary_kind = MathUnaryInstr::kSin; |
3064 break; | 2579 break; |
3065 case MethodRecognizer::kMathCos: | 2580 case MethodRecognizer::kMathCos: |
3066 unary_kind = MathUnaryInstr::kCos; | 2581 unary_kind = MathUnaryInstr::kCos; |
3067 break; | 2582 break; |
3068 default: | 2583 default: |
3069 unary_kind = MathUnaryInstr::kIllegal; | 2584 unary_kind = MathUnaryInstr::kIllegal; |
3070 break; | 2585 break; |
3071 } | 2586 } |
3072 if (unary_kind != MathUnaryInstr::kIllegal) { | 2587 if (unary_kind != MathUnaryInstr::kIllegal) { |
3073 if (FLAG_precompilation) { | 2588 ASSERT(FLAG_precompilation); |
3074 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. | 2589 // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well. |
3075 return; | |
3076 } | |
3077 MathUnaryInstr* math_unary = | |
3078 new(Z) MathUnaryInstr(unary_kind, | |
3079 new(Z) Value(call->ArgumentAt(0)), | |
3080 call->deopt_id()); | |
3081 ReplaceCall(call, math_unary); | |
3082 return; | 2590 return; |
3083 } | 2591 } |
| 2592 |
3084 switch (recognized_kind) { | 2593 switch (recognized_kind) { |
3085 case MethodRecognizer::kFloat32x4Zero: | 2594 case MethodRecognizer::kFloat32x4Zero: |
3086 case MethodRecognizer::kFloat32x4Splat: | 2595 case MethodRecognizer::kFloat32x4Splat: |
3087 case MethodRecognizer::kFloat32x4Constructor: | 2596 case MethodRecognizer::kFloat32x4Constructor: |
3088 case MethodRecognizer::kFloat32x4FromFloat64x2: | 2597 case MethodRecognizer::kFloat32x4FromFloat64x2: |
3089 TryInlineFloat32x4Constructor(call, recognized_kind); | 2598 TryInlineFloat32x4Constructor(call, recognized_kind); |
3090 break; | 2599 break; |
3091 case MethodRecognizer::kFloat64x2Constructor: | 2600 case MethodRecognizer::kFloat64x2Constructor: |
3092 case MethodRecognizer::kFloat64x2Zero: | 2601 case MethodRecognizer::kFloat64x2Zero: |
3093 case MethodRecognizer::kFloat64x2Splat: | 2602 case MethodRecognizer::kFloat64x2Splat: |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3149 } | 2658 } |
3150 } | 2659 } |
3151 break; | 2660 break; |
3152 } | 2661 } |
3153 case MethodRecognizer::kMathDoublePow: | 2662 case MethodRecognizer::kMathDoublePow: |
3154 case MethodRecognizer::kMathTan: | 2663 case MethodRecognizer::kMathTan: |
3155 case MethodRecognizer::kMathAsin: | 2664 case MethodRecognizer::kMathAsin: |
3156 case MethodRecognizer::kMathAcos: | 2665 case MethodRecognizer::kMathAcos: |
3157 case MethodRecognizer::kMathAtan: | 2666 case MethodRecognizer::kMathAtan: |
3158 case MethodRecognizer::kMathAtan2: { | 2667 case MethodRecognizer::kMathAtan2: { |
3159 if (FLAG_precompilation) { | 2668 ASSERT(FLAG_precompilation); |
3160 // No UnboxDouble instructons allowed. | 2669 // No UnboxDouble instructions allowed. |
3161 return; | 2670 return; |
3162 } | |
3163 // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble | |
3164 // instructions contain type checks and conversions to double. | |
3165 ZoneGrowableArray<Value*>* args = | |
3166 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | |
3167 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | |
3168 args->Add(new(Z) Value(call->ArgumentAt(i))); | |
3169 } | |
3170 InvokeMathCFunctionInstr* invoke = | |
3171 new(Z) InvokeMathCFunctionInstr(args, | |
3172 call->deopt_id(), | |
3173 recognized_kind, | |
3174 call->token_pos()); | |
3175 ReplaceCall(call, invoke); | |
3176 break; | |
3177 } | 2671 } |
3178 case MethodRecognizer::kDoubleFromInteger: { | 2672 case MethodRecognizer::kDoubleFromInteger: { |
3179 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { | 2673 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { |
3180 const ICData& ic_data = *call->ic_data(); | 2674 const ICData& ic_data = *call->ic_data(); |
3181 if (CanUnboxDouble()) { | 2675 if (CanUnboxDouble()) { |
3182 if (ArgIsAlways(kSmiCid, ic_data, 1)) { | 2676 if (ArgIsAlways(kSmiCid, ic_data, 1)) { |
3183 Definition* arg = call->ArgumentAt(1); | 2677 Definition* arg = call->ArgumentAt(1); |
3184 AddCheckSmi(arg, call->deopt_id(), call->env(), call); | 2678 AddCheckSmi(arg, call->deopt_id(), call->env(), call); |
3185 ReplaceCall(call, | 2679 ReplaceCall(call, |
3186 new(Z) SmiToDoubleInstr(new(Z) Value(arg), | 2680 new(Z) SmiToDoubleInstr(new(Z) Value(arg), |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3222 default: | 2716 default: |
3223 break; | 2717 break; |
3224 } | 2718 } |
3225 } | 2719 } |
3226 } | 2720 } |
3227 } | 2721 } |
3228 } | 2722 } |
3229 } | 2723 } |
3230 | 2724 |
3231 | 2725 |
3232 void FlowGraphOptimizer::VisitStoreInstanceField( | 2726 void AotOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { |
3233 StoreInstanceFieldInstr* instr) { | |
3234 if (instr->IsUnboxedStore()) { | |
3235 ASSERT(instr->is_potential_unboxed_initialization_); | |
3236 // Determine if this field should be unboxed based on the usage of getter | |
3237 // and setter functions: The heuristic requires that the setter has a | |
3238 // usage count of at least 1/kGetterSetterRatio of the getter usage count. | |
3239 // This is to avoid unboxing fields where the setter is never or rarely | |
3240 // executed. | |
3241 const Field& field = Field::ZoneHandle(Z, instr->field().raw()); | |
3242 const String& field_name = String::Handle(Z, field.name()); | |
3243 const Class& owner = Class::Handle(Z, field.owner()); | |
3244 const Function& getter = | |
3245 Function::Handle(Z, owner.LookupGetterFunction(field_name)); | |
3246 const Function& setter = | |
3247 Function::Handle(Z, owner.LookupSetterFunction(field_name)); | |
3248 bool unboxed_field = false; | |
3249 if (!getter.IsNull() && !setter.IsNull()) { | |
3250 if (field.is_double_initialized()) { | |
3251 unboxed_field = true; | |
3252 } else if ((setter.usage_counter() > 0) && | |
3253 ((FLAG_getter_setter_ratio * setter.usage_counter()) >= | |
3254 getter.usage_counter())) { | |
3255 unboxed_field = true; | |
3256 } | |
3257 } | |
3258 if (!unboxed_field) { | |
3259 // TODO(srdjan): Instead of aborting pass this field to the mutator thread | |
3260 // so that it can: | |
3261 // - set it to unboxed | |
3262 // - deoptimize dependent code. | |
3263 if (Compiler::IsBackgroundCompilation()) { | |
3264 isolate()->AddDeoptimizingBoxedField(field); | |
3265 Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId); | |
3266 UNREACHABLE(); | |
3267 } | |
3268 if (FLAG_trace_optimization || FLAG_trace_field_guards) { | |
3269 THR_Print("Disabling unboxing of %s\n", field.ToCString()); | |
3270 if (!setter.IsNull()) { | |
3271 OS::Print(" setter usage count: %" Pd "\n", setter.usage_counter()); | |
3272 } | |
3273 if (!getter.IsNull()) { | |
3274 OS::Print(" getter usage count: %" Pd "\n", getter.usage_counter()); | |
3275 } | |
3276 } | |
3277 field.set_is_unboxing_candidate(false); | |
3278 field.DeoptimizeDependentCode(); | |
3279 } else { | |
3280 flow_graph()->parsed_function().AddToGuardedFields(&field); | |
3281 } | |
3282 } | |
3283 } | |
3284 | |
3285 | |
3286 void FlowGraphOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { | |
3287 // Replace generic allocation with a sequence of inlined allocation and | 2727 // Replace generic allocation with a sequence of inlined allocation and |
3288 // explicit initalizing stores. | 2728 // explicit initalizing stores. |
3289 AllocateUninitializedContextInstr* replacement = | 2729 AllocateUninitializedContextInstr* replacement = |
3290 new AllocateUninitializedContextInstr(instr->token_pos(), | 2730 new AllocateUninitializedContextInstr(instr->token_pos(), |
3291 instr->num_context_variables()); | 2731 instr->num_context_variables()); |
3292 instr->ReplaceWith(replacement, current_iterator()); | 2732 instr->ReplaceWith(replacement, current_iterator()); |
3293 | 2733 |
3294 StoreInstanceFieldInstr* store = | 2734 StoreInstanceFieldInstr* store = |
3295 new(Z) StoreInstanceFieldInstr(Context::parent_offset(), | 2735 new(Z) StoreInstanceFieldInstr(Context::parent_offset(), |
3296 new Value(replacement), | 2736 new Value(replacement), |
(...skipping 14 matching lines...) Expand all Loading... |
3311 instr->token_pos()); | 2751 instr->token_pos()); |
3312 // Storing into uninitialized memory; remember to prevent dead store | 2752 // Storing into uninitialized memory; remember to prevent dead store |
3313 // elimination and ensure proper GC barrier. | 2753 // elimination and ensure proper GC barrier. |
3314 store->set_is_object_reference_initialization(true); | 2754 store->set_is_object_reference_initialization(true); |
3315 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); | 2755 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); |
3316 cursor = store; | 2756 cursor = store; |
3317 } | 2757 } |
3318 } | 2758 } |
3319 | 2759 |
3320 | 2760 |
3321 void FlowGraphOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { | 2761 void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { |
3322 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. | 2762 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. |
3323 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) | 2763 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) |
3324 if (!instr->can_pack_into_smi()) | 2764 if (!instr->can_pack_into_smi()) |
3325 instr->set_representation(kUnboxedMint); | 2765 instr->set_representation(kUnboxedMint); |
3326 #endif | 2766 #endif |
3327 } | 2767 } |
3328 | 2768 |
3329 | 2769 |
3330 bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, | 2770 bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, |
3331 const ICData& unary_ic_data, | 2771 const ICData& unary_ic_data, |
3332 bool allow_checks) { | 2772 bool allow_checks) { |
3333 ASSERT((unary_ic_data.NumberOfChecks() > 0) && | 2773 ASSERT((unary_ic_data.NumberOfChecks() > 0) && |
3334 (unary_ic_data.NumArgsTested() == 1)); | 2774 (unary_ic_data.NumArgsTested() == 1)); |
3335 if (I->flags().type_checks()) { | 2775 if (I->flags().type_checks()) { |
3336 // Checked mode setters are inlined like normal methods by conventional | 2776 // Checked mode setters are inlined like normal methods by conventional |
3337 // inlining. | 2777 // inlining. |
3338 return false; | 2778 return false; |
3339 } | 2779 } |
3340 | 2780 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3395 } | 2835 } |
3396 | 2836 |
3397 // Field guard was detached. | 2837 // Field guard was detached. |
3398 StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr( | 2838 StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr( |
3399 field, | 2839 field, |
3400 new(Z) Value(instr->ArgumentAt(0)), | 2840 new(Z) Value(instr->ArgumentAt(0)), |
3401 new(Z) Value(instr->ArgumentAt(1)), | 2841 new(Z) Value(instr->ArgumentAt(1)), |
3402 kEmitStoreBarrier, | 2842 kEmitStoreBarrier, |
3403 instr->token_pos()); | 2843 instr->token_pos()); |
3404 | 2844 |
3405 if (store->IsUnboxedStore()) { | 2845 // No unboxed stores in precompiled code. |
3406 flow_graph()->parsed_function().AddToGuardedFields(&field); | 2846 ASSERT(!store->IsUnboxedStore()); |
3407 } | |
3408 | 2847 |
3409 // Discard the environment from the original instruction because the store | 2848 // Discard the environment from the original instruction because the store |
3410 // can't deoptimize. | 2849 // can't deoptimize. |
3411 instr->RemoveEnvironment(); | 2850 instr->RemoveEnvironment(); |
3412 ReplaceCall(instr, store); | 2851 ReplaceCall(instr, store); |
3413 return true; | 2852 return true; |
3414 } | 2853 } |
3415 | 2854 |
3416 | 2855 |
3417 } // namespace dart | 2856 } // namespace dart |
OLD | NEW |