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

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

Issue 2481873005: clang-format runtime/vm (Closed)
Patch Set: Merge Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/aot_optimizer.h ('k') | runtime/vm/assembler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/aot_optimizer.h" 5 #include "vm/aot_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/branch_optimizer.h" 8 #include "vm/branch_optimizer.h"
9 #include "vm/cha.h" 9 #include "vm/cha.h"
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
(...skipping 11 matching lines...) Expand all
22 #include "vm/object_store.h" 22 #include "vm/object_store.h"
23 #include "vm/parser.h" 23 #include "vm/parser.h"
24 #include "vm/precompiler.h" 24 #include "vm/precompiler.h"
25 #include "vm/resolver.h" 25 #include "vm/resolver.h"
26 #include "vm/scopes.h" 26 #include "vm/scopes.h"
27 #include "vm/stack_frame.h" 27 #include "vm/stack_frame.h"
28 #include "vm/symbols.h" 28 #include "vm/symbols.h"
29 29
30 namespace dart { 30 namespace dart {
31 31
32 DEFINE_FLAG(int, max_exhaustive_polymorphic_checks, 5, 32 DEFINE_FLAG(int,
33 max_exhaustive_polymorphic_checks,
34 5,
33 "If a call receiver is known to be of at most this many classes, " 35 "If a call receiver is known to be of at most this many classes, "
34 "generate exhaustive class tests instead of a megamorphic call"); 36 "generate exhaustive class tests instead of a megamorphic call");
35 37
36 // Quick access to the current isolate and zone. 38 // Quick access to the current isolate and zone.
37 #define I (isolate()) 39 #define I (isolate())
38 #define Z (zone()) 40 #define Z (zone())
39 41
40 #ifdef DART_PRECOMPILER 42 #ifdef DART_PRECOMPILER
41 43
42 static bool ShouldInlineSimd() { 44 static bool ShouldInlineSimd() {
(...skipping 18 matching lines...) Expand all
61 // Returns Function::null() if there is no unique dynamic target for 63 // Returns Function::null() if there is no unique dynamic target for
62 // given 'fname'. 'fname' must be a symbol. 64 // given 'fname'. 'fname' must be a symbol.
63 static void GetUniqueDynamicTarget(Isolate* isolate, 65 static void GetUniqueDynamicTarget(Isolate* isolate,
64 const String& fname, 66 const String& fname,
65 Object* function) { 67 Object* function) {
66 UniqueFunctionsSet functions_set( 68 UniqueFunctionsSet functions_set(
67 isolate->object_store()->unique_dynamic_targets()); 69 isolate->object_store()->unique_dynamic_targets());
68 ASSERT(fname.IsSymbol()); 70 ASSERT(fname.IsSymbol());
69 *function = functions_set.GetOrNull(fname); 71 *function = functions_set.GetOrNull(fname);
70 ASSERT(functions_set.Release().raw() == 72 ASSERT(functions_set.Release().raw() ==
71 isolate->object_store()->unique_dynamic_targets()); 73 isolate->object_store()->unique_dynamic_targets());
72 } 74 }
73 75
74 76
75 AotOptimizer::AotOptimizer(Precompiler* precompiler, 77 AotOptimizer::AotOptimizer(Precompiler* precompiler,
76 FlowGraph* flow_graph, 78 FlowGraph* flow_graph,
77 bool use_speculative_inlining, 79 bool use_speculative_inlining,
78 GrowableArray<intptr_t>* inlining_black_list) 80 GrowableArray<intptr_t>* inlining_black_list)
79 : FlowGraphVisitor(flow_graph->reverse_postorder()), 81 : FlowGraphVisitor(flow_graph->reverse_postorder()),
80 precompiler_(precompiler), 82 precompiler_(precompiler),
81 flow_graph_(flow_graph), 83 flow_graph_(flow_graph),
82 use_speculative_inlining_(use_speculative_inlining), 84 use_speculative_inlining_(use_speculative_inlining),
83 inlining_black_list_(inlining_black_list), 85 inlining_black_list_(inlining_black_list),
84 has_unique_no_such_method_(false) { 86 has_unique_no_such_method_(false) {
85 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); 87 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL));
86 Function& target_function = Function::Handle(); 88 Function& target_function = Function::Handle();
87 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { 89 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) {
88 GetUniqueDynamicTarget( 90 GetUniqueDynamicTarget(isolate(), Symbols::NoSuchMethod(),
89 isolate(), Symbols::NoSuchMethod(), &target_function); 91 &target_function);
90 has_unique_no_such_method_ = !target_function.IsNull(); 92 has_unique_no_such_method_ = !target_function.IsNull();
91 } 93 }
92 } 94 }
93 95
94 96
95 // Optimize instance calls using ICData. 97 // Optimize instance calls using ICData.
96 void AotOptimizer::ApplyICData() { 98 void AotOptimizer::ApplyICData() {
97 VisitBlocks(); 99 VisitBlocks();
98 } 100 }
99 101
100 102
101 void AotOptimizer::PopulateWithICData() { 103 void AotOptimizer::PopulateWithICData() {
102 ASSERT(current_iterator_ == NULL); 104 ASSERT(current_iterator_ == NULL);
103 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 105 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
104 !block_it.Done(); 106 !block_it.Done(); block_it.Advance()) {
105 block_it.Advance()) {
106 ForwardInstructionIterator it(block_it.Current()); 107 ForwardInstructionIterator it(block_it.Current());
107 for (; !it.Done(); it.Advance()) { 108 for (; !it.Done(); it.Advance()) {
108 Instruction* instr = it.Current(); 109 Instruction* instr = it.Current();
109 if (instr->IsInstanceCall()) { 110 if (instr->IsInstanceCall()) {
110 InstanceCallInstr* call = instr->AsInstanceCall(); 111 InstanceCallInstr* call = instr->AsInstanceCall();
111 if (!call->HasICData()) { 112 if (!call->HasICData()) {
112 const Array& arguments_descriptor = 113 const Array& arguments_descriptor = Array::Handle(
113 Array::Handle(zone(), 114 zone(), ArgumentsDescriptor::New(call->ArgumentCount(),
114 ArgumentsDescriptor::New(call->ArgumentCount(), 115 call->argument_names()));
115 call->argument_names())); 116 const ICData& ic_data = ICData::ZoneHandle(
116 const ICData& ic_data = ICData::ZoneHandle(zone(), ICData::New( 117 zone(), ICData::New(function(), call->function_name(),
117 function(), call->function_name(), 118 arguments_descriptor, call->deopt_id(),
118 arguments_descriptor, call->deopt_id(), 119 call->checked_argument_count(), false));
119 call->checked_argument_count(), false));
120 call->set_ic_data(&ic_data); 120 call->set_ic_data(&ic_data);
121 } 121 }
122 } 122 }
123 } 123 }
124 current_iterator_ = NULL; 124 current_iterator_ = NULL;
125 } 125 }
126 } 126 }
127 127
128 128
129 bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) { 129 bool AotOptimizer::RecognizeRuntimeTypeGetter(InstanceCallInstr* call) {
130 if ((precompiler_ == NULL) || !precompiler_->get_runtime_type_is_unique()) { 130 if ((precompiler_ == NULL) || !precompiler_->get_runtime_type_is_unique()) {
131 return false; 131 return false;
132 } 132 }
133 133
134 if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) { 134 if (call->function_name().raw() != Symbols::GetRuntimeType().raw()) {
135 return false; 135 return false;
136 } 136 }
137 137
138 // There is only a single function Object.get:runtimeType that can be invoked 138 // There is only a single function Object.get:runtimeType that can be invoked
139 // by this call. Convert dynamic invocation to a static one. 139 // by this call. Convert dynamic invocation to a static one.
140 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); 140 const Class& cls = Class::Handle(Z, I->object_store()->object_class());
141 const Array& args_desc_array = Array::Handle(Z, 141 const Array& args_desc_array = Array::Handle(
142 ArgumentsDescriptor::New(call->ArgumentCount(), 142 Z,
143 call->argument_names())); 143 ArgumentsDescriptor::New(call->ArgumentCount(), call->argument_names()));
144 ArgumentsDescriptor args_desc(args_desc_array); 144 ArgumentsDescriptor args_desc(args_desc_array);
145 const Function& function = Function::Handle(Z, 145 const Function& function =
146 Resolver::ResolveDynamicForReceiverClass( 146 Function::Handle(Z, Resolver::ResolveDynamicForReceiverClass(
147 cls, 147 cls, call->function_name(), args_desc));
148 call->function_name(),
149 args_desc));
150 ASSERT(!function.IsNull()); 148 ASSERT(!function.IsNull());
151 149
152 ZoneGrowableArray<PushArgumentInstr*>* args = 150 ZoneGrowableArray<PushArgumentInstr*>* args =
153 new (Z) ZoneGrowableArray<PushArgumentInstr*>( 151 new (Z) ZoneGrowableArray<PushArgumentInstr*>(call->ArgumentCount());
154 call->ArgumentCount());
155 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { 152 for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
156 args->Add(call->PushArgumentAt(i)); 153 args->Add(call->PushArgumentAt(i));
157 } 154 }
158 StaticCallInstr* static_call = new (Z) StaticCallInstr( 155 StaticCallInstr* static_call = new (Z) StaticCallInstr(
159 call->token_pos(), 156 call->token_pos(), Function::ZoneHandle(Z, function.raw()),
160 Function::ZoneHandle(Z, function.raw()), 157 call->argument_names(), args, call->deopt_id());
161 call->argument_names(),
162 args,
163 call->deopt_id());
164 static_call->set_result_cid(kTypeCid); 158 static_call->set_result_cid(kTypeCid);
165 call->ReplaceWith(static_call, current_iterator()); 159 call->ReplaceWith(static_call, current_iterator());
166 return true; 160 return true;
167 } 161 }
168 162
169 163
170 // Optimize instance calls using cid. This is called after optimizer 164 // Optimize instance calls using cid. This is called after optimizer
171 // converted instance calls to instructions. Any remaining 165 // converted instance calls to instructions. Any remaining
172 // instance calls are either megamorphic calls, cannot be optimized or 166 // instance calls are either megamorphic calls, cannot be optimized or
173 // have no runtime type feedback collected. 167 // have no runtime type feedback collected.
174 // Attempts to convert an instance call (IC call) using propagated class-ids, 168 // Attempts to convert an instance call (IC call) using propagated class-ids,
175 // e.g., receiver class id, guarded-cid, or by guessing cid-s. 169 // e.g., receiver class id, guarded-cid, or by guessing cid-s.
176 void AotOptimizer::ApplyClassIds() { 170 void AotOptimizer::ApplyClassIds() {
177 ASSERT(current_iterator_ == NULL); 171 ASSERT(current_iterator_ == NULL);
178 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 172 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
179 !block_it.Done(); 173 !block_it.Done(); block_it.Advance()) {
180 block_it.Advance()) {
181 ForwardInstructionIterator it(block_it.Current()); 174 ForwardInstructionIterator it(block_it.Current());
182 current_iterator_ = &it; 175 current_iterator_ = &it;
183 for (; !it.Done(); it.Advance()) { 176 for (; !it.Done(); it.Advance()) {
184 Instruction* instr = it.Current(); 177 Instruction* instr = it.Current();
185 if (instr->IsInstanceCall()) { 178 if (instr->IsInstanceCall()) {
186 InstanceCallInstr* call = instr->AsInstanceCall(); 179 InstanceCallInstr* call = instr->AsInstanceCall();
187 if (call->HasICData()) { 180 if (call->HasICData()) {
188 if (TryCreateICData(call)) { 181 if (TryCreateICData(call)) {
189 VisitInstanceCall(call); 182 VisitInstanceCall(call);
190 } 183 }
(...skipping 19 matching lines...) Expand all
210 return false; 203 return false;
211 } 204 }
212 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); 205 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested());
213 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); 206 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount());
214 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { 207 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) {
215 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); 208 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid());
216 } 209 }
217 210
218 const Token::Kind op_kind = call->token_kind(); 211 const Token::Kind op_kind = call->token_kind();
219 if (Token::IsRelationalOperator(op_kind) || 212 if (Token::IsRelationalOperator(op_kind) ||
220 Token::IsEqualityOperator(op_kind) || 213 Token::IsEqualityOperator(op_kind) || Token::IsBinaryOperator(op_kind)) {
221 Token::IsBinaryOperator(op_kind)) {
222 // Guess cid: if one of the inputs is a number assume that the other 214 // Guess cid: if one of the inputs is a number assume that the other
223 // is a number of same type. 215 // is a number of same type.
224 if (FLAG_guess_icdata_cid) { 216 if (FLAG_guess_icdata_cid) {
225 const intptr_t cid_0 = class_ids[0]; 217 const intptr_t cid_0 = class_ids[0];
226 const intptr_t cid_1 = class_ids[1]; 218 const intptr_t cid_1 = class_ids[1];
227 if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) { 219 if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) {
228 class_ids[0] = cid_1; 220 class_ids[0] = cid_1;
229 } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) { 221 } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) {
230 class_ids[1] = cid_0; 222 class_ids[1] = cid_0;
231 } 223 }
232 } 224 }
233 } 225 }
234 226
235 bool all_cids_known = true; 227 bool all_cids_known = true;
236 for (intptr_t i = 0; i < class_ids.length(); i++) { 228 for (intptr_t i = 0; i < class_ids.length(); i++) {
237 if (class_ids[i] == kDynamicCid) { 229 if (class_ids[i] == kDynamicCid) {
238 // Not all cid-s known. 230 // Not all cid-s known.
239 all_cids_known = false; 231 all_cids_known = false;
240 break; 232 break;
241 } 233 }
242 } 234 }
243 235
244 if (all_cids_known) { 236 if (all_cids_known) {
245 const Class& receiver_class = Class::Handle(Z, 237 const Class& receiver_class =
246 isolate()->class_table()->At(class_ids[0])); 238 Class::Handle(Z, isolate()->class_table()->At(class_ids[0]));
247 if (!receiver_class.is_finalized()) { 239 if (!receiver_class.is_finalized()) {
248 // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can 240 // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can
249 // cause class finalization, since callee's receiver class may not be 241 // cause class finalization, since callee's receiver class may not be
250 // finalized yet. 242 // finalized yet.
251 return false; 243 return false;
252 } 244 }
253 const Array& args_desc_array = Array::Handle(Z, 245 const Array& args_desc_array =
254 ArgumentsDescriptor::New(call->ArgumentCount(), 246 Array::Handle(Z, ArgumentsDescriptor::New(call->ArgumentCount(),
255 call->argument_names())); 247 call->argument_names()));
256 ArgumentsDescriptor args_desc(args_desc_array); 248 ArgumentsDescriptor args_desc(args_desc_array);
257 const Function& function = Function::Handle(Z, 249 const Function& function = Function::Handle(
258 Resolver::ResolveDynamicForReceiverClass( 250 Z, Resolver::ResolveDynamicForReceiverClass(
259 receiver_class, 251 receiver_class, call->function_name(), args_desc));
260 call->function_name(),
261 args_desc));
262 if (function.IsNull()) { 252 if (function.IsNull()) {
263 return false; 253 return false;
264 } 254 }
265 255
266 // Create new ICData, do not modify the one attached to the instruction 256 // Create new ICData, do not modify the one attached to the instruction
267 // since it is attached to the assembly instruction itself. 257 // since it is attached to the assembly instruction itself.
268 // TODO(srdjan): Prevent modification of ICData object that is 258 // TODO(srdjan): Prevent modification of ICData object that is
269 // referenced in assembly code. 259 // referenced in assembly code.
270 const ICData& ic_data = ICData::ZoneHandle(Z, 260 const ICData& ic_data = ICData::ZoneHandle(
271 ICData::NewFrom(*call->ic_data(), class_ids.length())); 261 Z, ICData::NewFrom(*call->ic_data(), class_ids.length()));
272 if (class_ids.length() > 1) { 262 if (class_ids.length() > 1) {
273 ic_data.AddCheck(class_ids, function); 263 ic_data.AddCheck(class_ids, function);
274 } else { 264 } else {
275 ASSERT(class_ids.length() == 1); 265 ASSERT(class_ids.length() == 1);
276 ic_data.AddReceiverCheck(class_ids[0], function); 266 ic_data.AddReceiverCheck(class_ids[0], function);
277 } 267 }
278 call->set_ic_data(&ic_data); 268 call->set_ic_data(&ic_data);
279 return true; 269 return true;
280 } 270 }
281 271
282 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) { 272 if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) {
283 // Check if the target is unique. 273 // Check if the target is unique.
284 Function& target_function = Function::Handle(Z); 274 Function& target_function = Function::Handle(Z);
285 GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function); 275 GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function);
286 // Calls with named arguments must be resolved/checked at runtime. 276 // Calls with named arguments must be resolved/checked at runtime.
287 if (!target_function.IsNull() && 277 if (!target_function.IsNull() &&
288 !target_function.HasOptionalNamedParameters() && 278 !target_function.HasOptionalNamedParameters() &&
289 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0, 279 target_function.AreValidArgumentCounts(call->ArgumentCount(), 0,
290 /* error_message = */ NULL)) { 280 /* error_message = */ NULL)) {
291 const Class& cls = Class::Handle(Z, target_function.Owner()); 281 const Class& cls = Class::Handle(Z, target_function.Owner());
292 if (!CHA::IsImplemented(cls) && !CHA::HasSubclasses(cls)) { 282 if (!CHA::IsImplemented(cls) && !CHA::HasSubclasses(cls)) {
293 const ICData& ic_data = ICData::ZoneHandle(Z, 283 const ICData& ic_data =
294 ICData::NewFrom(*call->ic_data(), 1)); 284 ICData::ZoneHandle(Z, ICData::NewFrom(*call->ic_data(), 1));
295 ic_data.AddReceiverCheck(cls.id(), target_function); 285 ic_data.AddReceiverCheck(cls.id(), target_function);
296 call->set_ic_data(&ic_data); 286 call->set_ic_data(&ic_data);
297 if (has_unique_no_such_method_) { 287 if (has_unique_no_such_method_) {
298 call->set_has_unique_selector(true); 288 call->set_has_unique_selector(true);
299 } 289 }
300 return true; 290 return true;
301 } 291 }
302 } 292 }
303 } 293 }
304 294
305 return false; 295 return false;
306 } 296 }
307 297
308 298
309 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data, 299 const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data,
310 intptr_t cid) { 300 intptr_t cid) {
311 ASSERT(ic_data.NumArgsTested() == 1); 301 ASSERT(ic_data.NumArgsTested() == 1);
312 302
313 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { 303 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
314 return ic_data; // Nothing to do 304 return ic_data; // Nothing to do
315 } 305 }
316 306
317 const Function& function = 307 const Function& function =
318 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid)); 308 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid));
319 // TODO(fschneider): Try looking up the function on the class if it is 309 // TODO(fschneider): Try looking up the function on the class if it is
320 // not found in the ICData. 310 // not found in the ICData.
321 if (!function.IsNull()) { 311 if (!function.IsNull()) {
322 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New( 312 const ICData& new_ic_data = ICData::ZoneHandle(
323 Function::Handle(Z, ic_data.Owner()), 313 Z, ICData::New(Function::Handle(Z, ic_data.Owner()),
324 String::Handle(Z, ic_data.target_name()), 314 String::Handle(Z, ic_data.target_name()),
325 Object::empty_array(), // Dummy argument descriptor. 315 Object::empty_array(), // Dummy argument descriptor.
326 ic_data.deopt_id(), 316 ic_data.deopt_id(), ic_data.NumArgsTested(), false));
327 ic_data.NumArgsTested(), false));
328 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); 317 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons());
329 new_ic_data.AddReceiverCheck(cid, function); 318 new_ic_data.AddReceiverCheck(cid, function);
330 return new_ic_data; 319 return new_ic_data;
331 } 320 }
332 321
333 return ic_data; 322 return ic_data;
334 } 323 }
335 324
336 325
337 static bool ClassIdIsOneOf(intptr_t class_id, 326 static bool ClassIdIsOneOf(intptr_t class_id,
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 (class_ids[1] == argument_class_id)) { 376 (class_ids[1] == argument_class_id)) {
388 return true; 377 return true;
389 } 378 }
390 } 379 }
391 } 380 }
392 return false; 381 return false;
393 } 382 }
394 383
395 384
396 static bool HasOnlyOneSmi(const ICData& ic_data) { 385 static bool HasOnlyOneSmi(const ICData& ic_data) {
397 return (ic_data.NumberOfUsedChecks() == 1) 386 return (ic_data.NumberOfUsedChecks() == 1) &&
398 && ic_data.HasReceiverClassId(kSmiCid); 387 ic_data.HasReceiverClassId(kSmiCid);
399 } 388 }
400 389
401 390
402 static bool HasOnlySmiOrMint(const ICData& ic_data) { 391 static bool HasOnlySmiOrMint(const ICData& ic_data) {
403 if (ic_data.NumberOfUsedChecks() == 1) { 392 if (ic_data.NumberOfUsedChecks() == 1) {
404 return ic_data.HasReceiverClassId(kSmiCid) 393 return ic_data.HasReceiverClassId(kSmiCid) ||
405 || ic_data.HasReceiverClassId(kMintCid); 394 ic_data.HasReceiverClassId(kMintCid);
406 } 395 }
407 return (ic_data.NumberOfUsedChecks() == 2) 396 return (ic_data.NumberOfUsedChecks() == 2) &&
408 && ic_data.HasReceiverClassId(kSmiCid) 397 ic_data.HasReceiverClassId(kSmiCid) &&
409 && ic_data.HasReceiverClassId(kMintCid); 398 ic_data.HasReceiverClassId(kMintCid);
410 } 399 }
411 400
412 401
413 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) { 402 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
414 if (ic_data.NumberOfUsedChecks() != 1) { 403 if (ic_data.NumberOfUsedChecks() != 1) {
415 return false; 404 return false;
416 } 405 }
417 GrowableArray<intptr_t> first; 406 GrowableArray<intptr_t> first;
418 GrowableArray<intptr_t> second; 407 GrowableArray<intptr_t> second;
419 ic_data.GetUsedCidsForTwoArgs(&first, &second); 408 ic_data.GetUsedCidsForTwoArgs(&first, &second);
(...skipping 22 matching lines...) Expand all
442 // of Double and Smi for the receiver and argument classes. 431 // of Double and Smi for the receiver and argument classes.
443 static bool HasTwoDoubleOrSmi(const ICData& ic_data) { 432 static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
444 GrowableArray<intptr_t> class_ids(2); 433 GrowableArray<intptr_t> class_ids(2);
445 class_ids.Add(kSmiCid); 434 class_ids.Add(kSmiCid);
446 class_ids.Add(kDoubleCid); 435 class_ids.Add(kDoubleCid);
447 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); 436 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
448 } 437 }
449 438
450 439
451 static bool HasOnlyOneDouble(const ICData& ic_data) { 440 static bool HasOnlyOneDouble(const ICData& ic_data) {
452 return (ic_data.NumberOfUsedChecks() == 1) 441 return (ic_data.NumberOfUsedChecks() == 1) &&
453 && ic_data.HasReceiverClassId(kDoubleCid); 442 ic_data.HasReceiverClassId(kDoubleCid);
454 } 443 }
455 444
456 445
457 static bool ShouldSpecializeForDouble(const ICData& ic_data) { 446 static bool ShouldSpecializeForDouble(const ICData& ic_data) {
458 // Don't specialize for double if we can't unbox them. 447 // Don't specialize for double if we can't unbox them.
459 if (!CanUnboxDouble()) { 448 if (!CanUnboxDouble()) {
460 return false; 449 return false;
461 } 450 }
462 451
463 // Unboxed double operation can't handle case of two smis. 452 // Unboxed double operation can't handle case of two smis.
464 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 453 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
465 return false; 454 return false;
466 } 455 }
467 456
468 // Check that it have seen only smis and doubles. 457 // Check that it have seen only smis and doubles.
469 return HasTwoDoubleOrSmi(ic_data); 458 return HasTwoDoubleOrSmi(ic_data);
470 } 459 }
471 460
472 461
473 void AotOptimizer::ReplaceCall(Definition* call, 462 void AotOptimizer::ReplaceCall(Definition* call, Definition* replacement) {
474 Definition* replacement) {
475 // Remove the original push arguments. 463 // Remove the original push arguments.
476 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 464 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
477 PushArgumentInstr* push = call->PushArgumentAt(i); 465 PushArgumentInstr* push = call->PushArgumentAt(i);
478 push->ReplaceUsesWith(push->value()->definition()); 466 push->ReplaceUsesWith(push->value()->definition());
479 push->RemoveFromGraph(); 467 push->RemoveFromGraph();
480 } 468 }
481 call->ReplaceWith(replacement, current_iterator()); 469 call->ReplaceWith(replacement, current_iterator());
482 } 470 }
483 471
484 472
485 void AotOptimizer::AddCheckSmi(Definition* to_check, 473 void AotOptimizer::AddCheckSmi(Definition* to_check,
486 intptr_t deopt_id, 474 intptr_t deopt_id,
487 Environment* deopt_environment, 475 Environment* deopt_environment,
488 Instruction* insert_before) { 476 Instruction* insert_before) {
489 if (to_check->Type()->ToCid() != kSmiCid) { 477 if (to_check->Type()->ToCid() != kSmiCid) {
490 InsertBefore(insert_before, 478 InsertBefore(insert_before,
491 new(Z) CheckSmiInstr(new(Z) Value(to_check), 479 new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id,
492 deopt_id, 480 insert_before->token_pos()),
493 insert_before->token_pos()), 481 deopt_environment, FlowGraph::kEffect);
494 deopt_environment,
495 FlowGraph::kEffect);
496 } 482 }
497 } 483 }
498 484
499 485
500 Instruction* AotOptimizer::GetCheckClass(Definition* to_check, 486 Instruction* AotOptimizer::GetCheckClass(Definition* to_check,
501 const ICData& unary_checks, 487 const ICData& unary_checks,
502 intptr_t deopt_id, 488 intptr_t deopt_id,
503 TokenPosition token_pos) { 489 TokenPosition token_pos) {
504 if ((unary_checks.NumberOfUsedChecks() == 1) && 490 if ((unary_checks.NumberOfUsedChecks() == 1) &&
505 unary_checks.HasReceiverClassId(kSmiCid)) { 491 unary_checks.HasReceiverClassId(kSmiCid)) {
506 return new(Z) CheckSmiInstr(new(Z) Value(to_check), 492 return new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, token_pos);
507 deopt_id,
508 token_pos);
509 } 493 }
510 return new(Z) CheckClassInstr( 494 return new (Z) CheckClassInstr(new (Z) Value(to_check), deopt_id,
511 new(Z) Value(to_check), deopt_id, unary_checks, token_pos); 495 unary_checks, token_pos);
512 } 496 }
513 497
514 498
515 void AotOptimizer::AddCheckClass(Definition* to_check, 499 void AotOptimizer::AddCheckClass(Definition* to_check,
516 const ICData& unary_checks, 500 const ICData& unary_checks,
517 intptr_t deopt_id, 501 intptr_t deopt_id,
518 Environment* deopt_environment, 502 Environment* deopt_environment,
519 Instruction* insert_before) { 503 Instruction* insert_before) {
520 // Type propagation has not run yet, we cannot eliminate the check. 504 // Type propagation has not run yet, we cannot eliminate the check.
521 Instruction* check = GetCheckClass( 505 Instruction* check = GetCheckClass(to_check, unary_checks, deopt_id,
522 to_check, unary_checks, deopt_id, insert_before->token_pos()); 506 insert_before->token_pos());
523 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); 507 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect);
524 } 508 }
525 509
526 510
527 void AotOptimizer::AddReceiverCheck(InstanceCallInstr* call) { 511 void AotOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
528 AddCheckClass(call->ArgumentAt(0), 512 AddCheckClass(call->ArgumentAt(0),
529 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), 513 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
530 call->deopt_id(), 514 call->deopt_id(), call->env(), call);
531 call->env(),
532 call);
533 } 515 }
534 516
535 517
536 static bool ArgIsAlways(intptr_t cid, 518 static bool ArgIsAlways(intptr_t cid,
537 const ICData& ic_data, 519 const ICData& ic_data,
538 intptr_t arg_number) { 520 intptr_t arg_number) {
539 ASSERT(ic_data.NumArgsTested() > arg_number); 521 ASSERT(ic_data.NumArgsTested() > arg_number);
540 if (ic_data.NumberOfUsedChecks() == 0) { 522 if (ic_data.NumberOfUsedChecks() == 0) {
541 return false; 523 return false;
542 } 524 }
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
600 } 582 }
601 if (IsLengthOneString(left)) { 583 if (IsLengthOneString(left)) {
602 // Optimize if left is a string with length one (either constant or 584 // Optimize if left is a string with length one (either constant or
603 // result of string-from-char-code. 585 // result of string-from-char-code.
604 if (left->IsConstant()) { 586 if (left->IsConstant()) {
605 ConstantInstr* left_const = left->AsConstant(); 587 ConstantInstr* left_const = left->AsConstant();
606 const String& str = String::Cast(left_const->value()); 588 const String& str = String::Cast(left_const->value());
607 ASSERT(str.Length() == 1); 589 ASSERT(str.Length() == 1);
608 ConstantInstr* char_code_left = flow_graph()->GetConstant( 590 ConstantInstr* char_code_left = flow_graph()->GetConstant(
609 Smi::ZoneHandle(Z, Smi::New(static_cast<intptr_t>(str.CharAt(0))))); 591 Smi::ZoneHandle(Z, Smi::New(static_cast<intptr_t>(str.CharAt(0)))));
610 left_val = new(Z) Value(char_code_left); 592 left_val = new (Z) Value(char_code_left);
611 } else if (left->IsOneByteStringFromCharCode()) { 593 } else if (left->IsOneByteStringFromCharCode()) {
612 // Use input of string-from-charcode as left value. 594 // Use input of string-from-charcode as left value.
613 OneByteStringFromCharCodeInstr* instr = 595 OneByteStringFromCharCodeInstr* instr =
614 left->AsOneByteStringFromCharCode(); 596 left->AsOneByteStringFromCharCode();
615 left_val = new(Z) Value(instr->char_code()->definition()); 597 left_val = new (Z) Value(instr->char_code()->definition());
616 to_remove_left = instr; 598 to_remove_left = instr;
617 } else { 599 } else {
618 // IsLengthOneString(left) should have been false. 600 // IsLengthOneString(left) should have been false.
619 UNREACHABLE(); 601 UNREACHABLE();
620 } 602 }
621 603
622 Definition* to_remove_right = NULL; 604 Definition* to_remove_right = NULL;
623 Value* right_val = NULL; 605 Value* right_val = NULL;
624 if (right->IsOneByteStringFromCharCode()) { 606 if (right->IsOneByteStringFromCharCode()) {
625 // Skip string-from-char-code, and use its input as right value. 607 // Skip string-from-char-code, and use its input as right value.
626 OneByteStringFromCharCodeInstr* right_instr = 608 OneByteStringFromCharCodeInstr* right_instr =
627 right->AsOneByteStringFromCharCode(); 609 right->AsOneByteStringFromCharCode();
628 right_val = new(Z) Value(right_instr->char_code()->definition()); 610 right_val = new (Z) Value(right_instr->char_code()->definition());
629 to_remove_right = right_instr; 611 to_remove_right = right_instr;
630 } else { 612 } else {
631 const ICData& unary_checks_1 = 613 const ICData& unary_checks_1 =
632 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); 614 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
633 AddCheckClass(right, 615 AddCheckClass(right, unary_checks_1, call->deopt_id(), call->env(), call);
634 unary_checks_1,
635 call->deopt_id(),
636 call->env(),
637 call);
638 // String-to-char-code instructions returns -1 (illegal charcode) if 616 // String-to-char-code instructions returns -1 (illegal charcode) if
639 // string is not of length one. 617 // string is not of length one.
640 StringToCharCodeInstr* char_code_right = 618 StringToCharCodeInstr* char_code_right = new (Z)
641 new(Z) StringToCharCodeInstr(new(Z) Value(right), kOneByteStringCid); 619 StringToCharCodeInstr(new (Z) Value(right), kOneByteStringCid);
642 InsertBefore(call, char_code_right, call->env(), FlowGraph::kValue); 620 InsertBefore(call, char_code_right, call->env(), FlowGraph::kValue);
643 right_val = new(Z) Value(char_code_right); 621 right_val = new (Z) Value(char_code_right);
644 } 622 }
645 623
646 // Comparing char-codes instead of strings. 624 // Comparing char-codes instead of strings.
647 EqualityCompareInstr* comp = 625 EqualityCompareInstr* comp =
648 new(Z) EqualityCompareInstr(call->token_pos(), 626 new (Z) EqualityCompareInstr(call->token_pos(), op_kind, left_val,
649 op_kind, 627 right_val, kSmiCid, call->deopt_id());
650 left_val,
651 right_val,
652 kSmiCid,
653 call->deopt_id());
654 ReplaceCall(call, comp); 628 ReplaceCall(call, comp);
655 629
656 // Remove dead instructions. 630 // Remove dead instructions.
657 if ((to_remove_left != NULL) && 631 if ((to_remove_left != NULL) &&
658 (to_remove_left->input_use_list() == NULL)) { 632 (to_remove_left->input_use_list() == NULL)) {
659 to_remove_left->ReplaceUsesWith(flow_graph()->constant_null()); 633 to_remove_left->ReplaceUsesWith(flow_graph()->constant_null());
660 to_remove_left->RemoveFromGraph(); 634 to_remove_left->RemoveFromGraph();
661 } 635 }
662 if ((to_remove_right != NULL) && 636 if ((to_remove_right != NULL) &&
663 (to_remove_right->input_use_list() == NULL)) { 637 (to_remove_right->input_use_list() == NULL)) {
664 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null()); 638 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null());
665 to_remove_right->RemoveFromGraph(); 639 to_remove_right->RemoveFromGraph();
666 } 640 }
667 return true; 641 return true;
668 } 642 }
669 return false; 643 return false;
670 } 644 }
671 645
672 646
673 static bool SmiFitsInDouble() { return kSmiBits < 53; } 647 static bool SmiFitsInDouble() {
648 return kSmiBits < 53;
649 }
674 650
675 651
676 static bool IsGetRuntimeType(Definition* defn) { 652 static bool IsGetRuntimeType(Definition* defn) {
677 StaticCallInstr* call = defn->AsStaticCall(); 653 StaticCallInstr* call = defn->AsStaticCall();
678 return (call != NULL) && 654 return (call != NULL) && (call->function().recognized_kind() ==
679 (call->function().recognized_kind() == 655 MethodRecognizer::kObjectRuntimeType);
680 MethodRecognizer::kObjectRuntimeType);
681 } 656 }
682 657
683 658
684 // Recognize a.runtimeType == b.runtimeType and fold it into 659 // Recognize a.runtimeType == b.runtimeType and fold it into
685 // Object._haveSameRuntimeType(a, b). 660 // Object._haveSameRuntimeType(a, b).
686 // Note: this optimization is not speculative. 661 // Note: this optimization is not speculative.
687 bool AotOptimizer::TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call) { 662 bool AotOptimizer::TryReplaceWithHaveSameRuntimeType(InstanceCallInstr* call) {
688 const ICData& ic_data = *call->ic_data(); 663 const ICData& ic_data = *call->ic_data();
689 ASSERT(ic_data.NumArgsTested() == 2); 664 ASSERT(ic_data.NumArgsTested() == 2);
690 665
691 ASSERT(call->ArgumentCount() == 2); 666 ASSERT(call->ArgumentCount() == 2);
692 Definition* left = call->ArgumentAt(0); 667 Definition* left = call->ArgumentAt(0);
693 Definition* right = call->ArgumentAt(1); 668 Definition* right = call->ArgumentAt(1);
694 669
695 if (IsGetRuntimeType(left) && left->input_use_list()->IsSingleUse() && 670 if (IsGetRuntimeType(left) && left->input_use_list()->IsSingleUse() &&
696 IsGetRuntimeType(right) && right->input_use_list()->IsSingleUse()) { 671 IsGetRuntimeType(right) && right->input_use_list()->IsSingleUse()) {
697 const Class& cls = Class::Handle(Z, I->object_store()->object_class()); 672 const Class& cls = Class::Handle(Z, I->object_store()->object_class());
698 const Function& have_same_runtime_type = Function::ZoneHandle(Z, 673 const Function& have_same_runtime_type = Function::ZoneHandle(
674 Z,
699 cls.LookupStaticFunctionAllowPrivate(Symbols::HaveSameRuntimeType())); 675 cls.LookupStaticFunctionAllowPrivate(Symbols::HaveSameRuntimeType()));
700 ASSERT(!have_same_runtime_type.IsNull()); 676 ASSERT(!have_same_runtime_type.IsNull());
701 677
702 ZoneGrowableArray<PushArgumentInstr*>* args = 678 ZoneGrowableArray<PushArgumentInstr*>* args =
703 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); 679 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2);
704 PushArgumentInstr* arg = new (Z) PushArgumentInstr( 680 PushArgumentInstr* arg =
705 new (Z) Value(left->ArgumentAt(0))); 681 new (Z) PushArgumentInstr(new (Z) Value(left->ArgumentAt(0)));
706 InsertBefore(call, arg, NULL, FlowGraph::kEffect); 682 InsertBefore(call, arg, NULL, FlowGraph::kEffect);
707 args->Add(arg); 683 args->Add(arg);
708 arg = new (Z) PushArgumentInstr( 684 arg = new (Z) PushArgumentInstr(new (Z) Value(right->ArgumentAt(0)));
709 new (Z) Value(right->ArgumentAt(0)));
710 InsertBefore(call, arg, NULL, FlowGraph::kEffect); 685 InsertBefore(call, arg, NULL, FlowGraph::kEffect);
711 args->Add(arg); 686 args->Add(arg);
712 StaticCallInstr* static_call = new (Z) StaticCallInstr( 687 StaticCallInstr* static_call =
713 call->token_pos(), 688 new (Z) StaticCallInstr(call->token_pos(), have_same_runtime_type,
714 have_same_runtime_type, 689 Object::null_array(), // argument_names
715 Object::null_array(), // argument_names 690 args, call->deopt_id());
716 args,
717 call->deopt_id());
718 static_call->set_result_cid(kBoolCid); 691 static_call->set_result_cid(kBoolCid);
719 ReplaceCall(call, static_call); 692 ReplaceCall(call, static_call);
720 return true; 693 return true;
721 } 694 }
722 695
723 return false; 696 return false;
724 } 697 }
725 698
726 699
727 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, 700 bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
728 Token::Kind op_kind) { 701 Token::Kind op_kind) {
729 const ICData& ic_data = *call->ic_data(); 702 const ICData& ic_data = *call->ic_data();
730 ASSERT(ic_data.NumArgsTested() == 2); 703 ASSERT(ic_data.NumArgsTested() == 2);
731 704
732 ASSERT(call->ArgumentCount() == 2); 705 ASSERT(call->ArgumentCount() == 2);
733 Definition* left = call->ArgumentAt(0); 706 Definition* left = call->ArgumentAt(0);
734 Definition* right = call->ArgumentAt(1); 707 Definition* right = call->ArgumentAt(1);
735 708
736 intptr_t cid = kIllegalCid; 709 intptr_t cid = kIllegalCid;
737 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { 710 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
738 return TryStringLengthOneEquality(call, op_kind); 711 return TryStringLengthOneEquality(call, op_kind);
739 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { 712 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) {
740 InsertBefore(call, 713 InsertBefore(call,
741 new(Z) CheckSmiInstr(new(Z) Value(left), 714 new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(),
742 call->deopt_id(), 715 call->token_pos()),
743 call->token_pos()), 716 call->env(), FlowGraph::kEffect);
744 call->env(),
745 FlowGraph::kEffect);
746 InsertBefore(call, 717 InsertBefore(call,
747 new(Z) CheckSmiInstr(new(Z) Value(right), 718 new (Z) CheckSmiInstr(new (Z) Value(right), call->deopt_id(),
748 call->deopt_id(), 719 call->token_pos()),
749 call->token_pos()), 720 call->env(), FlowGraph::kEffect);
750 call->env(),
751 FlowGraph::kEffect);
752 cid = kSmiCid; 721 cid = kSmiCid;
753 } else if (HasTwoMintOrSmi(ic_data) && 722 } else if (HasTwoMintOrSmi(ic_data) &&
754 FlowGraphCompiler::SupportsUnboxedMints()) { 723 FlowGraphCompiler::SupportsUnboxedMints()) {
755 cid = kMintCid; 724 cid = kMintCid;
756 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { 725 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
757 // Use double comparison. 726 // Use double comparison.
758 if (SmiFitsInDouble()) { 727 if (SmiFitsInDouble()) {
759 cid = kDoubleCid; 728 cid = kDoubleCid;
760 } else { 729 } else {
761 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 730 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
762 // We cannot use double comparison on two smis. Need polymorphic 731 // We cannot use double comparison on two smis. Need polymorphic
763 // call. 732 // call.
764 return false; 733 return false;
765 } else { 734 } else {
766 InsertBefore(call, 735 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left),
767 new(Z) CheckEitherNonSmiInstr( 736 new (Z) Value(right),
768 new(Z) Value(left), 737 call->deopt_id()),
769 new(Z) Value(right), 738 call->env(), FlowGraph::kEffect);
770 call->deopt_id()),
771 call->env(),
772 FlowGraph::kEffect);
773 cid = kDoubleCid; 739 cid = kDoubleCid;
774 } 740 }
775 } 741 }
776 } else { 742 } else {
777 // Check if ICDData contains checks with Smi/Null combinations. In that case 743 // Check if ICDData contains checks with Smi/Null combinations. In that case
778 // we can still emit the optimized Smi equality operation but need to add 744 // we can still emit the optimized Smi equality operation but need to add
779 // checks for null or Smi. 745 // checks for null or Smi.
780 GrowableArray<intptr_t> smi_or_null(2); 746 GrowableArray<intptr_t> smi_or_null(2);
781 smi_or_null.Add(kSmiCid); 747 smi_or_null.Add(kSmiCid);
782 smi_or_null.Add(kNullCid); 748 smi_or_null.Add(kNullCid);
783 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, 749 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, smi_or_null,
784 smi_or_null,
785 smi_or_null)) { 750 smi_or_null)) {
786 const ICData& unary_checks_0 = 751 const ICData& unary_checks_0 =
787 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 752 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
788 AddCheckClass(left, 753 AddCheckClass(left, unary_checks_0, call->deopt_id(), call->env(), call);
789 unary_checks_0,
790 call->deopt_id(),
791 call->env(),
792 call);
793 754
794 const ICData& unary_checks_1 = 755 const ICData& unary_checks_1 =
795 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); 756 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
796 AddCheckClass(right, 757 AddCheckClass(right, unary_checks_1, call->deopt_id(), call->env(), call);
797 unary_checks_1,
798 call->deopt_id(),
799 call->env(),
800 call);
801 cid = kSmiCid; 758 cid = kSmiCid;
802 } else { 759 } else {
803 // Shortcut for equality with null. 760 // Shortcut for equality with null.
804 // TODO(vegorov): this optimization is not speculative and should 761 // TODO(vegorov): this optimization is not speculative and should
805 // be hoisted out of this function. 762 // be hoisted out of this function.
806 ConstantInstr* right_const = right->AsConstant(); 763 ConstantInstr* right_const = right->AsConstant();
807 ConstantInstr* left_const = left->AsConstant(); 764 ConstantInstr* left_const = left->AsConstant();
808 if ((right_const != NULL && right_const->value().IsNull()) || 765 if ((right_const != NULL && right_const->value().IsNull()) ||
809 (left_const != NULL && left_const->value().IsNull())) { 766 (left_const != NULL && left_const->value().IsNull())) {
810 StrictCompareInstr* comp = 767 StrictCompareInstr* comp = new (Z)
811 new(Z) StrictCompareInstr(call->token_pos(), 768 StrictCompareInstr(call->token_pos(), Token::kEQ_STRICT,
812 Token::kEQ_STRICT, 769 new (Z) Value(left), new (Z) Value(right),
813 new(Z) Value(left), 770 false); // No number check.
814 new(Z) Value(right),
815 false); // No number check.
816 ReplaceCall(call, comp); 771 ReplaceCall(call, comp);
817 return true; 772 return true;
818 } 773 }
819 return false; 774 return false;
820 } 775 }
821 } 776 }
822 ASSERT(cid != kIllegalCid); 777 ASSERT(cid != kIllegalCid);
823 EqualityCompareInstr* comp = new(Z) EqualityCompareInstr(call->token_pos(), 778 EqualityCompareInstr* comp = new (Z)
824 op_kind, 779 EqualityCompareInstr(call->token_pos(), op_kind, new (Z) Value(left),
825 new(Z) Value(left), 780 new (Z) Value(right), cid, call->deopt_id());
826 new(Z) Value(right),
827 cid,
828 call->deopt_id());
829 ReplaceCall(call, comp); 781 ReplaceCall(call, comp);
830 return true; 782 return true;
831 } 783 }
832 784
833 785
834 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, 786 bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
835 Token::Kind op_kind) { 787 Token::Kind op_kind) {
836 const ICData& ic_data = *call->ic_data(); 788 const ICData& ic_data = *call->ic_data();
837 ASSERT(ic_data.NumArgsTested() == 2); 789 ASSERT(ic_data.NumArgsTested() == 2);
838 790
839 ASSERT(call->ArgumentCount() == 2); 791 ASSERT(call->ArgumentCount() == 2);
840 Definition* left = call->ArgumentAt(0); 792 Definition* left = call->ArgumentAt(0);
841 Definition* right = call->ArgumentAt(1); 793 Definition* right = call->ArgumentAt(1);
842 794
843 intptr_t cid = kIllegalCid; 795 intptr_t cid = kIllegalCid;
844 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 796 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
845 InsertBefore(call, 797 InsertBefore(call,
846 new(Z) CheckSmiInstr(new(Z) Value(left), 798 new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(),
847 call->deopt_id(), 799 call->token_pos()),
848 call->token_pos()), 800 call->env(), FlowGraph::kEffect);
849 call->env(),
850 FlowGraph::kEffect);
851 InsertBefore(call, 801 InsertBefore(call,
852 new(Z) CheckSmiInstr(new(Z) Value(right), 802 new (Z) CheckSmiInstr(new (Z) Value(right), call->deopt_id(),
853 call->deopt_id(), 803 call->token_pos()),
854 call->token_pos()), 804 call->env(), FlowGraph::kEffect);
855 call->env(),
856 FlowGraph::kEffect);
857 cid = kSmiCid; 805 cid = kSmiCid;
858 } else if (HasTwoMintOrSmi(ic_data) && 806 } else if (HasTwoMintOrSmi(ic_data) &&
859 FlowGraphCompiler::SupportsUnboxedMints()) { 807 FlowGraphCompiler::SupportsUnboxedMints()) {
860 cid = kMintCid; 808 cid = kMintCid;
861 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { 809 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
862 // Use double comparison. 810 // Use double comparison.
863 if (SmiFitsInDouble()) { 811 if (SmiFitsInDouble()) {
864 cid = kDoubleCid; 812 cid = kDoubleCid;
865 } else { 813 } else {
866 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 814 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
867 // We cannot use double comparison on two smis. Need polymorphic 815 // We cannot use double comparison on two smis. Need polymorphic
868 // call. 816 // call.
869 return false; 817 return false;
870 } else { 818 } else {
871 InsertBefore(call, 819 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left),
872 new(Z) CheckEitherNonSmiInstr( 820 new (Z) Value(right),
873 new(Z) Value(left), 821 call->deopt_id()),
874 new(Z) Value(right), 822 call->env(), FlowGraph::kEffect);
875 call->deopt_id()),
876 call->env(),
877 FlowGraph::kEffect);
878 cid = kDoubleCid; 823 cid = kDoubleCid;
879 } 824 }
880 } 825 }
881 } else { 826 } else {
882 return false; 827 return false;
883 } 828 }
884 ASSERT(cid != kIllegalCid); 829 ASSERT(cid != kIllegalCid);
885 RelationalOpInstr* comp = new(Z) RelationalOpInstr(call->token_pos(), 830 RelationalOpInstr* comp =
886 op_kind, 831 new (Z) RelationalOpInstr(call->token_pos(), op_kind, new (Z) Value(left),
887 new(Z) Value(left), 832 new (Z) Value(right), cid, call->deopt_id());
888 new(Z) Value(right),
889 cid,
890 call->deopt_id());
891 ReplaceCall(call, comp); 833 ReplaceCall(call, comp);
892 return true; 834 return true;
893 } 835 }
894 836
895 837
896 bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, 838 bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
897 Token::Kind op_kind) { 839 Token::Kind op_kind) {
898 intptr_t operands_type = kIllegalCid; 840 intptr_t operands_type = kIllegalCid;
899 ASSERT(call->HasICData()); 841 ASSERT(call->HasICData());
900 const ICData& ic_data = *call->ic_data(); 842 const ICData& ic_data = *call->ic_data();
901 switch (op_kind) { 843 switch (op_kind) {
902 case Token::kADD: 844 case Token::kADD:
903 case Token::kSUB: 845 case Token::kSUB:
904 case Token::kMUL: 846 case Token::kMUL:
905 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 847 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
906 // Don't generate smi code if the IC data is marked because 848 // Don't generate smi code if the IC data is marked because
907 // of an overflow. 849 // of an overflow.
908 operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp) 850 operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
909 ? kMintCid 851 ? kMintCid
910 : kSmiCid; 852 : kSmiCid;
911 } else if (HasTwoMintOrSmi(ic_data) && 853 } else if (HasTwoMintOrSmi(ic_data) &&
912 FlowGraphCompiler::SupportsUnboxedMints()) { 854 FlowGraphCompiler::SupportsUnboxedMints()) {
913 // Don't generate mint code if the IC data is marked because of an 855 // Don't generate mint code if the IC data is marked because of an
914 // overflow. 856 // overflow.
915 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) return false; 857 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) return false;
916 operands_type = kMintCid; 858 operands_type = kMintCid;
917 } else if (ShouldSpecializeForDouble(ic_data)) { 859 } else if (ShouldSpecializeForDouble(ic_data)) {
918 operands_type = kDoubleCid; 860 operands_type = kDoubleCid;
919 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) { 861 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
920 operands_type = kFloat32x4Cid; 862 operands_type = kFloat32x4Cid;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
956 case Token::kSHR: 898 case Token::kSHR:
957 case Token::kSHL: 899 case Token::kSHL:
958 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 900 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
959 // Left shift may overflow from smi into mint or big ints. 901 // Left shift may overflow from smi into mint or big ints.
960 // Don't generate smi code if the IC data is marked because 902 // Don't generate smi code if the IC data is marked because
961 // of an overflow. 903 // of an overflow.
962 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) { 904 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
963 return false; 905 return false;
964 } 906 }
965 operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp) 907 operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
966 ? kMintCid 908 ? kMintCid
967 : kSmiCid; 909 : kSmiCid;
968 } else if (HasTwoMintOrSmi(ic_data) && 910 } else if (HasTwoMintOrSmi(ic_data) &&
969 HasOnlyOneSmi(ICData::Handle(Z, 911 HasOnlyOneSmi(ICData::Handle(
970 ic_data.AsUnaryClassChecksForArgNr(1)))) { 912 Z, ic_data.AsUnaryClassChecksForArgNr(1)))) {
971 // Don't generate mint code if the IC data is marked because of an 913 // Don't generate mint code if the IC data is marked because of an
972 // overflow. 914 // overflow.
973 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) { 915 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
974 return false; 916 return false;
975 } 917 }
976 // Check for smi/mint << smi or smi/mint >> smi. 918 // Check for smi/mint << smi or smi/mint >> smi.
977 operands_type = kMintCid; 919 operands_type = kMintCid;
978 } else { 920 } else {
979 return false; 921 return false;
980 } 922 }
(...skipping 18 matching lines...) Expand all
999 Definition* left = call->ArgumentAt(0); 941 Definition* left = call->ArgumentAt(0);
1000 Definition* right = call->ArgumentAt(1); 942 Definition* right = call->ArgumentAt(1);
1001 if (operands_type == kDoubleCid) { 943 if (operands_type == kDoubleCid) {
1002 if (!CanUnboxDouble()) { 944 if (!CanUnboxDouble()) {
1003 return false; 945 return false;
1004 } 946 }
1005 // Check that either left or right are not a smi. Result of a 947 // Check that either left or right are not a smi. Result of a
1006 // binary operation with two smis is a smi not a double, except '/' which 948 // binary operation with two smis is a smi not a double, except '/' which
1007 // returns a double for two smis. 949 // returns a double for two smis.
1008 if (op_kind != Token::kDIV) { 950 if (op_kind != Token::kDIV) {
1009 InsertBefore(call, 951 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left),
1010 new(Z) CheckEitherNonSmiInstr( 952 new (Z) Value(right),
1011 new(Z) Value(left), 953 call->deopt_id()),
1012 new(Z) Value(right), 954 call->env(), FlowGraph::kEffect);
1013 call->deopt_id()),
1014 call->env(),
1015 FlowGraph::kEffect);
1016 } 955 }
1017 956
1018 BinaryDoubleOpInstr* double_bin_op = 957 BinaryDoubleOpInstr* double_bin_op = new (Z)
1019 new(Z) BinaryDoubleOpInstr(op_kind, 958 BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right),
1020 new(Z) Value(left), 959 call->deopt_id(), call->token_pos());
1021 new(Z) Value(right),
1022 call->deopt_id(), call->token_pos());
1023 ReplaceCall(call, double_bin_op); 960 ReplaceCall(call, double_bin_op);
1024 } else if (operands_type == kMintCid) { 961 } else if (operands_type == kMintCid) {
1025 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; 962 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false;
1026 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { 963 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
1027 ShiftMintOpInstr* shift_op = 964 ShiftMintOpInstr* shift_op = new (Z) ShiftMintOpInstr(
1028 new(Z) ShiftMintOpInstr( 965 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1029 op_kind, new(Z) Value(left), new(Z) Value(right),
1030 call->deopt_id());
1031 ReplaceCall(call, shift_op); 966 ReplaceCall(call, shift_op);
1032 } else { 967 } else {
1033 BinaryMintOpInstr* bin_op = 968 BinaryMintOpInstr* bin_op = new (Z) BinaryMintOpInstr(
1034 new(Z) BinaryMintOpInstr( 969 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1035 op_kind, new(Z) Value(left), new(Z) Value(right),
1036 call->deopt_id());
1037 ReplaceCall(call, bin_op); 970 ReplaceCall(call, bin_op);
1038 } 971 }
1039 } else if (operands_type == kFloat32x4Cid) { 972 } else if (operands_type == kFloat32x4Cid) {
1040 return InlineFloat32x4BinaryOp(call, op_kind); 973 return InlineFloat32x4BinaryOp(call, op_kind);
1041 } else if (operands_type == kInt32x4Cid) { 974 } else if (operands_type == kInt32x4Cid) {
1042 return InlineInt32x4BinaryOp(call, op_kind); 975 return InlineInt32x4BinaryOp(call, op_kind);
1043 } else if (operands_type == kFloat64x2Cid) { 976 } else if (operands_type == kFloat64x2Cid) {
1044 return InlineFloat64x2BinaryOp(call, op_kind); 977 return InlineFloat64x2BinaryOp(call, op_kind);
1045 } else if (op_kind == Token::kMOD) { 978 } else if (op_kind == Token::kMOD) {
1046 ASSERT(operands_type == kSmiCid); 979 ASSERT(operands_type == kSmiCid);
1047 if (right->IsConstant()) { 980 if (right->IsConstant()) {
1048 const Object& obj = right->AsConstant()->value(); 981 const Object& obj = right->AsConstant()->value();
1049 if (obj.IsSmi() && Utils::IsPowerOfTwo(Smi::Cast(obj).Value())) { 982 if (obj.IsSmi() && Utils::IsPowerOfTwo(Smi::Cast(obj).Value())) {
1050 // Insert smi check and attach a copy of the original environment 983 // Insert smi check and attach a copy of the original environment
1051 // because the smi operation can still deoptimize. 984 // because the smi operation can still deoptimize.
1052 InsertBefore(call, 985 InsertBefore(call,
1053 new(Z) CheckSmiInstr(new(Z) Value(left), 986 new (Z) CheckSmiInstr(new (Z) Value(left),
1054 call->deopt_id(), 987 call->deopt_id(), call->token_pos()),
1055 call->token_pos()), 988 call->env(), FlowGraph::kEffect);
1056 call->env(), 989 ConstantInstr* constant = flow_graph()->GetConstant(
1057 FlowGraph::kEffect); 990 Smi::Handle(Z, Smi::New(Smi::Cast(obj).Value() - 1)));
1058 ConstantInstr* constant =
1059 flow_graph()->GetConstant(Smi::Handle(Z,
1060 Smi::New(Smi::Cast(obj).Value() - 1)));
1061 BinarySmiOpInstr* bin_op = 991 BinarySmiOpInstr* bin_op =
1062 new(Z) BinarySmiOpInstr(Token::kBIT_AND, 992 new (Z) BinarySmiOpInstr(Token::kBIT_AND, new (Z) Value(left),
1063 new(Z) Value(left), 993 new (Z) Value(constant), call->deopt_id());
1064 new(Z) Value(constant),
1065 call->deopt_id());
1066 ReplaceCall(call, bin_op); 994 ReplaceCall(call, bin_op);
1067 return true; 995 return true;
1068 } 996 }
1069 } 997 }
1070 // Insert two smi checks and attach a copy of the original 998 // Insert two smi checks and attach a copy of the original
1071 // environment because the smi operation can still deoptimize. 999 // environment because the smi operation can still deoptimize.
1072 AddCheckSmi(left, call->deopt_id(), call->env(), call); 1000 AddCheckSmi(left, call->deopt_id(), call->env(), call);
1073 AddCheckSmi(right, call->deopt_id(), call->env(), call); 1001 AddCheckSmi(right, call->deopt_id(), call->env(), call);
1074 BinarySmiOpInstr* bin_op = 1002 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr(
1075 new(Z) BinarySmiOpInstr(op_kind, 1003 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1076 new(Z) Value(left),
1077 new(Z) Value(right),
1078 call->deopt_id());
1079 ReplaceCall(call, bin_op); 1004 ReplaceCall(call, bin_op);
1080 } else { 1005 } else {
1081 ASSERT(operands_type == kSmiCid); 1006 ASSERT(operands_type == kSmiCid);
1082 // Insert two smi checks and attach a copy of the original 1007 // Insert two smi checks and attach a copy of the original
1083 // environment because the smi operation can still deoptimize. 1008 // environment because the smi operation can still deoptimize.
1084 AddCheckSmi(left, call->deopt_id(), call->env(), call); 1009 AddCheckSmi(left, call->deopt_id(), call->env(), call);
1085 AddCheckSmi(right, call->deopt_id(), call->env(), call); 1010 AddCheckSmi(right, call->deopt_id(), call->env(), call);
1086 if (left->IsConstant() && 1011 if (left->IsConstant() &&
1087 ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) { 1012 ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) {
1088 // Constant should be on the right side. 1013 // Constant should be on the right side.
1089 Definition* temp = left; 1014 Definition* temp = left;
1090 left = right; 1015 left = right;
1091 right = temp; 1016 right = temp;
1092 } 1017 }
1093 BinarySmiOpInstr* bin_op = 1018 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr(
1094 new(Z) BinarySmiOpInstr( 1019 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1095 op_kind,
1096 new(Z) Value(left),
1097 new(Z) Value(right),
1098 call->deopt_id());
1099 ReplaceCall(call, bin_op); 1020 ReplaceCall(call, bin_op);
1100 } 1021 }
1101 return true; 1022 return true;
1102 } 1023 }
1103 1024
1104 1025
1105 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, 1026 bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
1106 Token::Kind op_kind) { 1027 Token::Kind op_kind) {
1107 ASSERT(call->ArgumentCount() == 1); 1028 ASSERT(call->ArgumentCount() == 1);
1108 Definition* input = call->ArgumentAt(0); 1029 Definition* input = call->ArgumentAt(0);
1109 Definition* unary_op = NULL; 1030 Definition* unary_op = NULL;
1110 if (HasOnlyOneSmi(*call->ic_data())) { 1031 if (HasOnlyOneSmi(*call->ic_data())) {
1111 InsertBefore(call, 1032 InsertBefore(call,
1112 new(Z) CheckSmiInstr(new(Z) Value(input), 1033 new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(),
1113 call->deopt_id(), 1034 call->token_pos()),
1114 call->token_pos()), 1035 call->env(), FlowGraph::kEffect);
1115 call->env(), 1036 unary_op = new (Z)
1116 FlowGraph::kEffect); 1037 UnarySmiOpInstr(op_kind, new (Z) Value(input), call->deopt_id());
1117 unary_op = new(Z) UnarySmiOpInstr(
1118 op_kind, new(Z) Value(input), call->deopt_id());
1119 } else if ((op_kind == Token::kBIT_NOT) && 1038 } else if ((op_kind == Token::kBIT_NOT) &&
1120 HasOnlySmiOrMint(*call->ic_data()) && 1039 HasOnlySmiOrMint(*call->ic_data()) &&
1121 FlowGraphCompiler::SupportsUnboxedMints()) { 1040 FlowGraphCompiler::SupportsUnboxedMints()) {
1122 unary_op = new(Z) UnaryMintOpInstr( 1041 unary_op = new (Z)
1123 op_kind, new(Z) Value(input), call->deopt_id()); 1042 UnaryMintOpInstr(op_kind, new (Z) Value(input), call->deopt_id());
1124 } else if (HasOnlyOneDouble(*call->ic_data()) && 1043 } else if (HasOnlyOneDouble(*call->ic_data()) &&
1125 (op_kind == Token::kNEGATE) && 1044 (op_kind == Token::kNEGATE) && CanUnboxDouble()) {
1126 CanUnboxDouble()) {
1127 AddReceiverCheck(call); 1045 AddReceiverCheck(call);
1128 unary_op = new(Z) UnaryDoubleOpInstr( 1046 unary_op = new (Z) UnaryDoubleOpInstr(Token::kNEGATE, new (Z) Value(input),
1129 Token::kNEGATE, new(Z) Value(input), call->deopt_id()); 1047 call->deopt_id());
1130 } else { 1048 } else {
1131 return false; 1049 return false;
1132 } 1050 }
1133 ASSERT(unary_op != NULL); 1051 ASSERT(unary_op != NULL);
1134 ReplaceCall(call, unary_op); 1052 ReplaceCall(call, unary_op);
1135 return true; 1053 return true;
1136 } 1054 }
1137 1055
1138 1056
1139 // Using field class 1057 // Using field class
1140 RawField* AotOptimizer::GetField(intptr_t class_id, 1058 RawField* AotOptimizer::GetField(intptr_t class_id, const String& field_name) {
1141 const String& field_name) {
1142 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); 1059 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
1143 Field& field = Field::Handle(Z); 1060 Field& field = Field::Handle(Z);
1144 while (!cls.IsNull()) { 1061 while (!cls.IsNull()) {
1145 field = cls.LookupInstanceField(field_name); 1062 field = cls.LookupInstanceField(field_name);
1146 if (!field.IsNull()) { 1063 if (!field.IsNull()) {
1147 return field.raw(); 1064 return field.raw();
1148 } 1065 }
1149 cls = cls.SuperClass(); 1066 cls = cls.SuperClass();
1150 } 1067 }
1151 return Field::null(); 1068 return Field::null();
1152 } 1069 }
1153 1070
1154 1071
1155 bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { 1072 bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
1156 ASSERT(call->HasICData()); 1073 ASSERT(call->HasICData());
1157 const ICData& ic_data = *call->ic_data(); 1074 const ICData& ic_data = *call->ic_data();
1158 ASSERT(ic_data.HasOneTarget()); 1075 ASSERT(ic_data.HasOneTarget());
1159 GrowableArray<intptr_t> class_ids; 1076 GrowableArray<intptr_t> class_ids;
1160 ic_data.GetClassIdsAt(0, &class_ids); 1077 ic_data.GetClassIdsAt(0, &class_ids);
1161 ASSERT(class_ids.length() == 1); 1078 ASSERT(class_ids.length() == 1);
1162 // Inline implicit instance getter. 1079 // Inline implicit instance getter.
1163 const String& field_name = 1080 const String& field_name =
1164 String::Handle(Z, Field::NameFromGetter(call->function_name())); 1081 String::Handle(Z, Field::NameFromGetter(call->function_name()));
1165 const Field& field = 1082 const Field& field = Field::ZoneHandle(Z, GetField(class_ids[0], field_name));
1166 Field::ZoneHandle(Z, GetField(class_ids[0], field_name));
1167 ASSERT(!field.IsNull()); 1083 ASSERT(!field.IsNull());
1168 1084
1169 if (flow_graph()->InstanceCallNeedsClassCheck( 1085 if (flow_graph()->InstanceCallNeedsClassCheck(call,
1170 call, RawFunction::kImplicitGetter)) { 1086 RawFunction::kImplicitGetter)) {
1171 return false; 1087 return false;
1172 } 1088 }
1173 LoadFieldInstr* load = new(Z) LoadFieldInstr( 1089 LoadFieldInstr* load = new (Z) LoadFieldInstr(
1174 new(Z) Value(call->ArgumentAt(0)), 1090 new (Z) Value(call->ArgumentAt(0)), &field,
1175 &field, 1091 AbstractType::ZoneHandle(Z, field.type()), call->token_pos());
1176 AbstractType::ZoneHandle(Z, field.type()),
1177 call->token_pos());
1178 load->set_is_immutable(field.is_final()); 1092 load->set_is_immutable(field.is_final());
1179 1093
1180 // Discard the environment from the original instruction because the load 1094 // Discard the environment from the original instruction because the load
1181 // can't deoptimize. 1095 // can't deoptimize.
1182 call->RemoveEnvironment(); 1096 call->RemoveEnvironment();
1183 ReplaceCall(call, load); 1097 ReplaceCall(call, load);
1184 1098
1185 if (load->result_cid() != kDynamicCid) { 1099 if (load->result_cid() != kDynamicCid) {
1186 // Reset value types if guarded_cid was used. 1100 // Reset value types if guarded_cid was used.
1187 for (Value::Iterator it(load->input_use_list()); 1101 for (Value::Iterator it(load->input_use_list()); !it.Done(); it.Advance()) {
1188 !it.Done();
1189 it.Advance()) {
1190 it.Current()->SetReachingType(NULL); 1102 it.Current()->SetReachingType(NULL);
1191 } 1103 }
1192 } 1104 }
1193 return true; 1105 return true;
1194 } 1106 }
1195 1107
1196 1108
1197 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, 1109 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
1198 Token::Kind op_kind) { 1110 Token::Kind op_kind) {
1199 if (!ShouldInlineSimd()) { 1111 if (!ShouldInlineSimd()) {
1200 return false; 1112 return false;
1201 } 1113 }
1202 ASSERT(call->ArgumentCount() == 2); 1114 ASSERT(call->ArgumentCount() == 2);
1203 Definition* left = call->ArgumentAt(0); 1115 Definition* left = call->ArgumentAt(0);
1204 Definition* right = call->ArgumentAt(1); 1116 Definition* right = call->ArgumentAt(1);
1205 // Type check left. 1117 // Type check left.
1206 AddCheckClass(left, 1118 AddCheckClass(left, ICData::ZoneHandle(
1207 ICData::ZoneHandle( 1119 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1208 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1120 call->deopt_id(), call->env(), call);
1209 call->deopt_id(),
1210 call->env(),
1211 call);
1212 // Type check right. 1121 // Type check right.
1213 AddCheckClass(right, 1122 AddCheckClass(right, ICData::ZoneHandle(
1214 ICData::ZoneHandle( 1123 Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)),
1215 Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)), 1124 call->deopt_id(), call->env(), call);
1216 call->deopt_id(),
1217 call->env(),
1218 call);
1219 // Replace call. 1125 // Replace call.
1220 BinaryFloat32x4OpInstr* float32x4_bin_op = 1126 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr(
1221 new(Z) BinaryFloat32x4OpInstr( 1127 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1222 op_kind, new(Z) Value(left), new(Z) Value(right),
1223 call->deopt_id());
1224 ReplaceCall(call, float32x4_bin_op); 1128 ReplaceCall(call, float32x4_bin_op);
1225 1129
1226 return true; 1130 return true;
1227 } 1131 }
1228 1132
1229 1133
1230 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, 1134 bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
1231 Token::Kind op_kind) { 1135 Token::Kind op_kind) {
1232 if (!ShouldInlineSimd()) { 1136 if (!ShouldInlineSimd()) {
1233 return false; 1137 return false;
1234 } 1138 }
1235 ASSERT(call->ArgumentCount() == 2); 1139 ASSERT(call->ArgumentCount() == 2);
1236 Definition* left = call->ArgumentAt(0); 1140 Definition* left = call->ArgumentAt(0);
1237 Definition* right = call->ArgumentAt(1); 1141 Definition* right = call->ArgumentAt(1);
1238 // Type check left. 1142 // Type check left.
1239 AddCheckClass(left, 1143 AddCheckClass(left, ICData::ZoneHandle(
1240 ICData::ZoneHandle( 1144 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1241 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1145 call->deopt_id(), call->env(), call);
1242 call->deopt_id(),
1243 call->env(),
1244 call);
1245 // Type check right. 1146 // Type check right.
1246 AddCheckClass(right, 1147 AddCheckClass(right, ICData::ZoneHandle(
1247 ICData::ZoneHandle(Z, 1148 Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)),
1248 call->ic_data()->AsUnaryClassChecksForArgNr(1)), 1149 call->deopt_id(), call->env(), call);
1249 call->deopt_id(),
1250 call->env(),
1251 call);
1252 // Replace call. 1150 // Replace call.
1253 BinaryInt32x4OpInstr* int32x4_bin_op = 1151 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr(
1254 new(Z) BinaryInt32x4OpInstr( 1152 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1255 op_kind, new(Z) Value(left), new(Z) Value(right),
1256 call->deopt_id());
1257 ReplaceCall(call, int32x4_bin_op); 1153 ReplaceCall(call, int32x4_bin_op);
1258 return true; 1154 return true;
1259 } 1155 }
1260 1156
1261 1157
1262 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, 1158 bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
1263 Token::Kind op_kind) { 1159 Token::Kind op_kind) {
1264 if (!ShouldInlineSimd()) { 1160 if (!ShouldInlineSimd()) {
1265 return false; 1161 return false;
1266 } 1162 }
1267 ASSERT(call->ArgumentCount() == 2); 1163 ASSERT(call->ArgumentCount() == 2);
1268 Definition* left = call->ArgumentAt(0); 1164 Definition* left = call->ArgumentAt(0);
1269 Definition* right = call->ArgumentAt(1); 1165 Definition* right = call->ArgumentAt(1);
1270 // Type check left. 1166 // Type check left.
1271 AddCheckClass(left, 1167 AddCheckClass(
1272 ICData::ZoneHandle( 1168 left, ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1273 call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1169 call->deopt_id(), call->env(), call);
1274 call->deopt_id(),
1275 call->env(),
1276 call);
1277 // Type check right. 1170 // Type check right.
1278 AddCheckClass(right, 1171 AddCheckClass(
1279 ICData::ZoneHandle( 1172 right, ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(1)),
1280 call->ic_data()->AsUnaryClassChecksForArgNr(1)), 1173 call->deopt_id(), call->env(), call);
1281 call->deopt_id(),
1282 call->env(),
1283 call);
1284 // Replace call. 1174 // Replace call.
1285 BinaryFloat64x2OpInstr* float64x2_bin_op = 1175 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr(
1286 new(Z) BinaryFloat64x2OpInstr( 1176 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1287 op_kind, new(Z) Value(left), new(Z) Value(right),
1288 call->deopt_id());
1289 ReplaceCall(call, float64x2_bin_op); 1177 ReplaceCall(call, float64x2_bin_op);
1290 return true; 1178 return true;
1291 } 1179 }
1292 1180
1293 1181
1294 // Only unique implicit instance getters can be currently handled. 1182 // Only unique implicit instance getters can be currently handled.
1295 bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { 1183 bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
1296 ASSERT(call->HasICData()); 1184 ASSERT(call->HasICData());
1297 const ICData& ic_data = *call->ic_data(); 1185 const ICData& ic_data = *call->ic_data();
1298 if (ic_data.NumberOfUsedChecks() == 0) { 1186 if (ic_data.NumberOfUsedChecks() == 0) {
(...skipping 15 matching lines...) Expand all
1314 } 1202 }
1315 return InlineImplicitInstanceGetter(call); 1203 return InlineImplicitInstanceGetter(call);
1316 } 1204 }
1317 1205
1318 1206
1319 void AotOptimizer::ReplaceWithMathCFunction( 1207 void AotOptimizer::ReplaceWithMathCFunction(
1320 InstanceCallInstr* call, 1208 InstanceCallInstr* call,
1321 MethodRecognizer::Kind recognized_kind) { 1209 MethodRecognizer::Kind recognized_kind) {
1322 AddReceiverCheck(call); 1210 AddReceiverCheck(call);
1323 ZoneGrowableArray<Value*>* args = 1211 ZoneGrowableArray<Value*>* args =
1324 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); 1212 new (Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
1325 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { 1213 for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
1326 args->Add(new(Z) Value(call->ArgumentAt(i))); 1214 args->Add(new (Z) Value(call->ArgumentAt(i)));
1327 } 1215 }
1328 InvokeMathCFunctionInstr* invoke = 1216 InvokeMathCFunctionInstr* invoke = new (Z) InvokeMathCFunctionInstr(
1329 new(Z) InvokeMathCFunctionInstr(args, 1217 args, call->deopt_id(), recognized_kind, call->token_pos());
1330 call->deopt_id(),
1331 recognized_kind,
1332 call->token_pos());
1333 ReplaceCall(call, invoke); 1218 ReplaceCall(call, invoke);
1334 } 1219 }
1335 1220
1336 1221
1337 // Inline only simple, frequently called core library methods. 1222 // Inline only simple, frequently called core library methods.
1338 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { 1223 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
1339 ASSERT(call->HasICData()); 1224 ASSERT(call->HasICData());
1340 const ICData& ic_data = *call->ic_data(); 1225 const ICData& ic_data = *call->ic_data();
1341 if (ic_data.NumberOfUsedChecks() != 1) { 1226 if (ic_data.NumberOfUsedChecks() != 1) {
1342 // No type feedback collected or multiple receivers/targets found. 1227 // No type feedback collected or multiple receivers/targets found.
1343 return false; 1228 return false;
1344 } 1229 }
1345 1230
1346 Function& target = Function::Handle(Z); 1231 Function& target = Function::Handle(Z);
1347 GrowableArray<intptr_t> class_ids; 1232 GrowableArray<intptr_t> class_ids;
1348 ic_data.GetCheckAt(0, &class_ids, &target); 1233 ic_data.GetCheckAt(0, &class_ids, &target);
1349 MethodRecognizer::Kind recognized_kind = 1234 MethodRecognizer::Kind recognized_kind =
1350 MethodRecognizer::RecognizeKind(target); 1235 MethodRecognizer::RecognizeKind(target);
1351 1236
1352 if (CanUnboxDouble() && 1237 if (CanUnboxDouble() &&
1353 (recognized_kind == MethodRecognizer::kIntegerToDouble)) { 1238 (recognized_kind == MethodRecognizer::kIntegerToDouble)) {
1354 if (class_ids[0] == kSmiCid) { 1239 if (class_ids[0] == kSmiCid) {
1355 AddReceiverCheck(call); 1240 AddReceiverCheck(call);
1356 ReplaceCall(call, 1241 ReplaceCall(call,
1357 new(Z) SmiToDoubleInstr( 1242 new (Z) SmiToDoubleInstr(new (Z) Value(call->ArgumentAt(0)),
1358 new(Z) Value(call->ArgumentAt(0)), 1243 call->token_pos()));
1359 call->token_pos()));
1360 return true; 1244 return true;
1361 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) { 1245 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) {
1362 AddReceiverCheck(call); 1246 AddReceiverCheck(call);
1363 ReplaceCall(call, 1247 ReplaceCall(call,
1364 new(Z) MintToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), 1248 new (Z) MintToDoubleInstr(new (Z) Value(call->ArgumentAt(0)),
1365 call->deopt_id())); 1249 call->deopt_id()));
1366 return true; 1250 return true;
1367 } 1251 }
1368 } 1252 }
1369 1253
1370 if (class_ids[0] == kDoubleCid) { 1254 if (class_ids[0] == kDoubleCid) {
1371 if (!CanUnboxDouble()) { 1255 if (!CanUnboxDouble()) {
1372 return false; 1256 return false;
1373 } 1257 }
1374 switch (recognized_kind) { 1258 switch (recognized_kind) {
1375 case MethodRecognizer::kDoubleToInteger: { 1259 case MethodRecognizer::kDoubleToInteger: {
1376 AddReceiverCheck(call); 1260 AddReceiverCheck(call);
1377 ASSERT(call->HasICData()); 1261 ASSERT(call->HasICData());
1378 const ICData& ic_data = *call->ic_data(); 1262 const ICData& ic_data = *call->ic_data();
1379 Definition* input = call->ArgumentAt(0); 1263 Definition* input = call->ArgumentAt(0);
1380 Definition* d2i_instr = NULL; 1264 Definition* d2i_instr = NULL;
1381 if (ic_data.HasDeoptReason(ICData::kDeoptDoubleToSmi)) { 1265 if (ic_data.HasDeoptReason(ICData::kDeoptDoubleToSmi)) {
1382 // Do not repeatedly deoptimize because result didn't fit into Smi. 1266 // Do not repeatedly deoptimize because result didn't fit into Smi.
1383 d2i_instr = new(Z) DoubleToIntegerInstr( 1267 d2i_instr = new (Z) DoubleToIntegerInstr(new (Z) Value(input), call);
1384 new(Z) Value(input), call);
1385 } else { 1268 } else {
1386 // Optimistically assume result fits into Smi. 1269 // Optimistically assume result fits into Smi.
1387 d2i_instr = new(Z) DoubleToSmiInstr( 1270 d2i_instr =
1388 new(Z) Value(input), call->deopt_id()); 1271 new (Z) DoubleToSmiInstr(new (Z) Value(input), call->deopt_id());
1389 } 1272 }
1390 ReplaceCall(call, d2i_instr); 1273 ReplaceCall(call, d2i_instr);
1391 return true; 1274 return true;
1392 } 1275 }
1393 case MethodRecognizer::kDoubleMod: 1276 case MethodRecognizer::kDoubleMod:
1394 case MethodRecognizer::kDoubleRound: 1277 case MethodRecognizer::kDoubleRound:
1395 ReplaceWithMathCFunction(call, recognized_kind); 1278 ReplaceWithMathCFunction(call, recognized_kind);
1396 return true; 1279 return true;
1397 case MethodRecognizer::kDoubleTruncate: 1280 case MethodRecognizer::kDoubleTruncate:
1398 case MethodRecognizer::kDoubleFloor: 1281 case MethodRecognizer::kDoubleFloor:
1399 case MethodRecognizer::kDoubleCeil: 1282 case MethodRecognizer::kDoubleCeil:
1400 if (!TargetCPUFeatures::double_truncate_round_supported()) { 1283 if (!TargetCPUFeatures::double_truncate_round_supported()) {
1401 ReplaceWithMathCFunction(call, recognized_kind); 1284 ReplaceWithMathCFunction(call, recognized_kind);
1402 } else { 1285 } else {
1403 AddReceiverCheck(call); 1286 AddReceiverCheck(call);
1404 DoubleToDoubleInstr* d2d_instr = 1287 DoubleToDoubleInstr* d2d_instr =
1405 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), 1288 new (Z) DoubleToDoubleInstr(new (Z) Value(call->ArgumentAt(0)),
1406 recognized_kind, call->deopt_id()); 1289 recognized_kind, call->deopt_id());
1407 ReplaceCall(call, d2d_instr); 1290 ReplaceCall(call, d2d_instr);
1408 } 1291 }
1409 return true; 1292 return true;
1410 default: 1293 default:
1411 break; 1294 break;
1412 } 1295 }
1413 } 1296 }
1414 1297
1415 return FlowGraphInliner::TryReplaceInstanceCallWithInline( 1298 return FlowGraphInliner::TryReplaceInstanceCallWithInline(
1416 flow_graph_, current_iterator(), call); 1299 flow_graph_, current_iterator(), call);
(...skipping 20 matching lines...) Expand all
1437 const Class& type_class = Class::Handle(Z, type.type_class()); 1320 const Class& type_class = Class::Handle(Z, type.type_class());
1438 const intptr_t num_type_args = type_class.NumTypeArguments(); 1321 const intptr_t num_type_args = type_class.NumTypeArguments();
1439 if (num_type_args > 0) { 1322 if (num_type_args > 0) {
1440 // Only raw types can be directly compared, thus disregarding type 1323 // Only raw types can be directly compared, thus disregarding type
1441 // arguments. 1324 // arguments.
1442 const intptr_t num_type_params = type_class.NumTypeParameters(); 1325 const intptr_t num_type_params = type_class.NumTypeParameters();
1443 const intptr_t from_index = num_type_args - num_type_params; 1326 const intptr_t from_index = num_type_args - num_type_params;
1444 const TypeArguments& type_arguments = 1327 const TypeArguments& type_arguments =
1445 TypeArguments::Handle(Z, type.arguments()); 1328 TypeArguments::Handle(Z, type.arguments());
1446 const bool is_raw_type = type_arguments.IsNull() || 1329 const bool is_raw_type = type_arguments.IsNull() ||
1447 type_arguments.IsRaw(from_index, num_type_params); 1330 type_arguments.IsRaw(from_index, num_type_params);
1448 if (!is_raw_type) { 1331 if (!is_raw_type) {
1449 // Unknown result. 1332 // Unknown result.
1450 return Bool::null(); 1333 return Bool::null();
1451 } 1334 }
1452 } 1335 }
1453 1336
1454 const ClassTable& class_table = *isolate()->class_table(); 1337 const ClassTable& class_table = *isolate()->class_table();
1455 Bool& prev = Bool::Handle(Z); 1338 Bool& prev = Bool::Handle(Z);
1456 Class& cls = Class::Handle(Z); 1339 Class& cls = Class::Handle(Z);
1457 1340
1458 bool results_differ = false; 1341 bool results_differ = false;
1459 for (int i = 0; i < ic_data.NumberOfChecks(); i++) { 1342 for (int i = 0; i < ic_data.NumberOfChecks(); i++) {
1460 cls = class_table.At(ic_data.GetReceiverClassIdAt(i)); 1343 cls = class_table.At(ic_data.GetReceiverClassIdAt(i));
1461 if (cls.NumTypeArguments() > 0) { 1344 if (cls.NumTypeArguments() > 0) {
1462 return Bool::null(); 1345 return Bool::null();
1463 } 1346 }
1464 const bool is_subtype = cls.IsSubtypeOf( 1347 const bool is_subtype =
1465 TypeArguments::Handle(Z), 1348 cls.IsSubtypeOf(TypeArguments::Handle(Z), type_class,
1466 type_class, 1349 TypeArguments::Handle(Z), NULL, NULL, Heap::kOld);
1467 TypeArguments::Handle(Z),
1468 NULL,
1469 NULL,
1470 Heap::kOld);
1471 results->Add(cls.id()); 1350 results->Add(cls.id());
1472 results->Add(is_subtype); 1351 results->Add(is_subtype);
1473 if (prev.IsNull()) { 1352 if (prev.IsNull()) {
1474 prev = Bool::Get(is_subtype).raw(); 1353 prev = Bool::Get(is_subtype).raw();
1475 } else { 1354 } else {
1476 if (is_subtype != prev.value()) { 1355 if (is_subtype != prev.value()) {
1477 results_differ = true; 1356 results_differ = true;
1478 } 1357 }
1479 } 1358 }
1480 } 1359 }
1481 return results_differ ? Bool::null() : prev.raw(); 1360 return results_differ ? Bool::null() : prev.raw();
1482 } 1361 }
1483 1362
1484 1363
1485 // Returns true if checking against this type is a direct class id comparison. 1364 // Returns true if checking against this type is a direct class id comparison.
1486 bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { 1365 bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
1487 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); 1366 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
1488 // Requires CHA. 1367 // Requires CHA.
1489 if (!type.IsInstantiated()) return false; 1368 if (!type.IsInstantiated()) return false;
1490 // Function types have different type checking rules. 1369 // Function types have different type checking rules.
1491 if (type.IsFunctionType()) return false; 1370 if (type.IsFunctionType()) return false;
1492 const Class& type_class = Class::Handle(type.type_class()); 1371 const Class& type_class = Class::Handle(type.type_class());
1493 // Could be an interface check? 1372 // Could be an interface check?
1494 if (CHA::IsImplemented(type_class)) return false; 1373 if (CHA::IsImplemented(type_class)) return false;
1495 // Check if there are subclasses. 1374 // Check if there are subclasses.
1496 if (CHA::HasSubclasses(type_class)) { 1375 if (CHA::HasSubclasses(type_class)) {
1497 return false; 1376 return false;
1498 } 1377 }
1499 1378
1500 // Private classes cannot be subclassed by later loaded libs. 1379 // Private classes cannot be subclassed by later loaded libs.
1501 if (!type_class.IsPrivate()) { 1380 if (!type_class.IsPrivate()) {
1502 if (isolate()->all_classes_finalized()) { 1381 if (isolate()->all_classes_finalized()) {
1503 if (FLAG_trace_cha) { 1382 if (FLAG_trace_cha) {
1504 THR_Print(" **(CHA) Typecheck as class equality since no " 1383 THR_Print(
1384 " **(CHA) Typecheck as class equality since no "
1505 "subclasses: %s\n", 1385 "subclasses: %s\n",
1506 type_class.ToCString()); 1386 type_class.ToCString());
1507 } 1387 }
1508 ASSERT(!FLAG_use_cha_deopt); 1388 ASSERT(!FLAG_use_cha_deopt);
1509 } else { 1389 } else {
1510 return false; 1390 return false;
1511 } 1391 }
1512 } 1392 }
1513 const intptr_t num_type_args = type_class.NumTypeArguments(); 1393 const intptr_t num_type_args = type_class.NumTypeArguments();
1514 if (num_type_args > 0) { 1394 if (num_type_args > 0) {
1515 // Only raw types can be directly compared, thus disregarding type 1395 // Only raw types can be directly compared, thus disregarding type
1516 // arguments. 1396 // arguments.
1517 const intptr_t num_type_params = type_class.NumTypeParameters(); 1397 const intptr_t num_type_params = type_class.NumTypeParameters();
1518 const intptr_t from_index = num_type_args - num_type_params; 1398 const intptr_t from_index = num_type_args - num_type_params;
1519 const TypeArguments& type_arguments = 1399 const TypeArguments& type_arguments =
1520 TypeArguments::Handle(type.arguments()); 1400 TypeArguments::Handle(type.arguments());
1521 const bool is_raw_type = type_arguments.IsNull() || 1401 const bool is_raw_type = type_arguments.IsNull() ||
1522 type_arguments.IsRaw(from_index, num_type_params); 1402 type_arguments.IsRaw(from_index, num_type_params);
1523 return is_raw_type; 1403 return is_raw_type;
1524 } 1404 }
1525 return true; 1405 return true;
1526 } 1406 }
1527 1407
1528 1408
1529 static bool CidTestResultsContains(const ZoneGrowableArray<intptr_t>& results, 1409 static bool CidTestResultsContains(const ZoneGrowableArray<intptr_t>& results,
1530 intptr_t test_cid) { 1410 intptr_t test_cid) {
1531 for (intptr_t i = 0; i < results.length(); i += 2) { 1411 for (intptr_t i = 0; i < results.length(); i += 2) {
1532 if (results[i] == test_cid) return true; 1412 if (results[i] == test_cid) return true;
(...skipping 15 matching lines...) Expand all
1548 // Tries to add cid tests to 'results' so that no deoptimization is 1428 // Tries to add cid tests to 'results' so that no deoptimization is
1549 // necessary. 1429 // necessary.
1550 // TODO(srdjan): Do also for other than 'int' type. 1430 // TODO(srdjan): Do also for other than 'int' type.
1551 static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results, 1431 static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results,
1552 const AbstractType& type) { 1432 const AbstractType& type) {
1553 ASSERT(results->length() >= 2); // At least on entry. 1433 ASSERT(results->length() >= 2); // At least on entry.
1554 const ClassTable& class_table = *Isolate::Current()->class_table(); 1434 const ClassTable& class_table = *Isolate::Current()->class_table();
1555 if ((*results)[0] != kSmiCid) { 1435 if ((*results)[0] != kSmiCid) {
1556 const Class& cls = Class::Handle(class_table.At(kSmiCid)); 1436 const Class& cls = Class::Handle(class_table.At(kSmiCid));
1557 const Class& type_class = Class::Handle(type.type_class()); 1437 const Class& type_class = Class::Handle(type.type_class());
1558 const bool smi_is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(), 1438 const bool smi_is_subtype =
1559 type_class, 1439 cls.IsSubtypeOf(TypeArguments::Handle(), type_class,
1560 TypeArguments::Handle(), 1440 TypeArguments::Handle(), NULL, NULL, Heap::kOld);
1561 NULL,
1562 NULL,
1563 Heap::kOld);
1564 results->Add((*results)[results->length() - 2]); 1441 results->Add((*results)[results->length() - 2]);
1565 results->Add((*results)[results->length() - 2]); 1442 results->Add((*results)[results->length() - 2]);
1566 for (intptr_t i = results->length() - 3; i > 1; --i) { 1443 for (intptr_t i = results->length() - 3; i > 1; --i) {
1567 (*results)[i] = (*results)[i - 2]; 1444 (*results)[i] = (*results)[i - 2];
1568 } 1445 }
1569 (*results)[0] = kSmiCid; 1446 (*results)[0] = kSmiCid;
1570 (*results)[1] = smi_is_subtype; 1447 (*results)[1] = smi_is_subtype;
1571 } 1448 }
1572 1449
1573 ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded()); 1450 ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded());
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1620 type = Type::IntType(); 1497 type = Type::IntType();
1621 } else if (matches_core(call, Symbols::_instanceOfSmi())) { 1498 } else if (matches_core(call, Symbols::_instanceOfSmi())) {
1622 type = Type::SmiType(); 1499 type = Type::SmiType();
1623 } else if (matches_core(call, Symbols::_instanceOfDouble())) { 1500 } else if (matches_core(call, Symbols::_instanceOfDouble())) {
1624 type = Type::Double(); 1501 type = Type::Double();
1625 } else if (matches_core(call, Symbols::_instanceOfString())) { 1502 } else if (matches_core(call, Symbols::_instanceOfString())) {
1626 type = Type::StringType(); 1503 type = Type::StringType();
1627 } else { 1504 } else {
1628 UNIMPLEMENTED(); 1505 UNIMPLEMENTED();
1629 } 1506 }
1630 negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition() 1507 negate =
1631 ->AsConstant()->value()).value(); 1508 Bool::Cast(
1509 call->ArgumentAt(1)->OriginalDefinition()->AsConstant()->value())
1510 .value();
1632 } 1511 }
1633 } else { 1512 } else {
1634 type_args = call->ArgumentAt(1); 1513 type_args = call->ArgumentAt(1);
1635 type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw(); 1514 type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw();
1636 negate = Bool::Cast(call->ArgumentAt(3)->OriginalDefinition() 1515 negate =
1637 ->AsConstant()->value()).value(); 1516 Bool::Cast(
1517 call->ArgumentAt(3)->OriginalDefinition()->AsConstant()->value())
1518 .value();
1638 } 1519 }
1639 1520
1640 if (TypeCheckAsClassEquality(type)) { 1521 if (TypeCheckAsClassEquality(type)) {
1641 LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left)); 1522 LoadClassIdInstr* left_cid = new (Z) LoadClassIdInstr(new (Z) Value(left));
1642 InsertBefore(call, left_cid, NULL, FlowGraph::kValue); 1523 InsertBefore(call, left_cid, NULL, FlowGraph::kValue);
1643 const intptr_t type_cid = Class::Handle(Z, type.type_class()).id(); 1524 const intptr_t type_cid = Class::Handle(Z, type.type_class()).id();
1644 ConstantInstr* cid = 1525 ConstantInstr* cid =
1645 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid))); 1526 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid)));
1646 1527
1647 StrictCompareInstr* check_cid = 1528 StrictCompareInstr* check_cid = new (Z) StrictCompareInstr(
1648 new(Z) StrictCompareInstr( 1529 call->token_pos(), negate ? Token::kNE_STRICT : Token::kEQ_STRICT,
1649 call->token_pos(), 1530 new (Z) Value(left_cid), new (Z) Value(cid),
1650 negate ? Token::kNE_STRICT : Token::kEQ_STRICT, 1531 false); // No number check.
1651 new(Z) Value(left_cid),
1652 new(Z) Value(cid),
1653 false); // No number check.
1654 ReplaceCall(call, check_cid); 1532 ReplaceCall(call, check_cid);
1655 return; 1533 return;
1656 } 1534 }
1657 1535
1658 TypeRangeCache* cache = thread()->type_range_cache(); 1536 TypeRangeCache* cache = thread()->type_range_cache();
1659 intptr_t lower_limit, upper_limit; 1537 intptr_t lower_limit, upper_limit;
1660 if (cache != NULL && 1538 if (cache != NULL &&
1661 cache->InstanceOfHasClassRange(type, &lower_limit, &upper_limit)) { 1539 cache->InstanceOfHasClassRange(type, &lower_limit, &upper_limit)) {
1662 // left.instanceof(type) => 1540 // left.instanceof(type) =>
1663 // _classRangeCheck(left.cid, lower_limit, upper_limit) 1541 // _classRangeCheck(left.cid, lower_limit, upper_limit)
1664 1542
1665 LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left)); 1543 LoadClassIdInstr* left_cid = new (Z) LoadClassIdInstr(new (Z) Value(left));
1666 InsertBefore(call, left_cid, NULL, FlowGraph::kValue); 1544 InsertBefore(call, left_cid, NULL, FlowGraph::kValue);
1667 ConstantInstr* lower_cid = 1545 ConstantInstr* lower_cid =
1668 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(lower_limit))); 1546 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(lower_limit)));
1669 ConstantInstr* upper_cid = 1547 ConstantInstr* upper_cid =
1670 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(upper_limit))); 1548 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(upper_limit)));
1671 1549
1672 ZoneGrowableArray<PushArgumentInstr*>* args = 1550 ZoneGrowableArray<PushArgumentInstr*>* args =
1673 new(Z) ZoneGrowableArray<PushArgumentInstr*>(3); 1551 new (Z) ZoneGrowableArray<PushArgumentInstr*>(3);
1674 PushArgumentInstr* arg = new (Z) PushArgumentInstr(new (Z) Value(left_cid)); 1552 PushArgumentInstr* arg = new (Z) PushArgumentInstr(new (Z) Value(left_cid));
1675 InsertBefore(call, arg, NULL, FlowGraph::kEffect); 1553 InsertBefore(call, arg, NULL, FlowGraph::kEffect);
1676 args->Add(arg); 1554 args->Add(arg);
1677 arg = new (Z) PushArgumentInstr(new (Z) Value(lower_cid)); 1555 arg = new (Z) PushArgumentInstr(new (Z) Value(lower_cid));
1678 InsertBefore(call, arg, NULL, FlowGraph::kEffect); 1556 InsertBefore(call, arg, NULL, FlowGraph::kEffect);
1679 args->Add(arg); 1557 args->Add(arg);
1680 arg = new (Z) PushArgumentInstr(new (Z) Value(upper_cid)); 1558 arg = new (Z) PushArgumentInstr(new (Z) Value(upper_cid));
1681 InsertBefore(call, arg, NULL, FlowGraph::kEffect); 1559 InsertBefore(call, arg, NULL, FlowGraph::kEffect);
1682 args->Add(arg); 1560 args->Add(arg);
1683 1561
1684 const Library& dart_internal = 1562 const Library& dart_internal =
1685 Library::Handle(Z, Library::InternalLibrary()); 1563 Library::Handle(Z, Library::InternalLibrary());
1686 const String& target_name = negate ? Symbols::_classRangeCheckNegative() 1564 const String& target_name = negate ? Symbols::_classRangeCheckNegative()
1687 : Symbols::_classRangeCheck(); 1565 : Symbols::_classRangeCheck();
1688 const Function& target = Function::ZoneHandle(Z, 1566 const Function& target = Function::ZoneHandle(
1689 dart_internal.LookupFunctionAllowPrivate(target_name)); 1567 Z, dart_internal.LookupFunctionAllowPrivate(target_name));
1690 ASSERT(!target.IsNull()); 1568 ASSERT(!target.IsNull());
1691 ASSERT(target.IsRecognized() && target.always_inline()); 1569 ASSERT(target.IsRecognized() && target.always_inline());
1692 1570
1693 StaticCallInstr* new_call = new (Z) StaticCallInstr( 1571 StaticCallInstr* new_call =
1694 call->token_pos(), 1572 new (Z) StaticCallInstr(call->token_pos(), target,
1695 target, 1573 Object::null_array(), // argument_names
1696 Object::null_array(), // argument_names 1574 args, call->deopt_id());
1697 args,
1698 call->deopt_id());
1699 ReplaceCall(call, new_call); 1575 ReplaceCall(call, new_call);
1700 return; 1576 return;
1701 } 1577 }
1702 1578
1703 const ICData& unary_checks = 1579 const ICData& unary_checks =
1704 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 1580 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
1705 if ((unary_checks.NumberOfChecks() > 0) && 1581 if ((unary_checks.NumberOfChecks() > 0) &&
1706 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { 1582 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
1707 ZoneGrowableArray<intptr_t>* results = 1583 ZoneGrowableArray<intptr_t>* results =
1708 new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); 1584 new (Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
1709 InstanceOfAsBool(unary_checks, type, results); 1585 InstanceOfAsBool(unary_checks, type, results);
1710 if (results->length() == unary_checks.NumberOfChecks() * 2) { 1586 if (results->length() == unary_checks.NumberOfChecks() * 2) {
1711 const bool can_deopt = TryExpandTestCidsResult(results, type); 1587 const bool can_deopt = TryExpandTestCidsResult(results, type);
1712 if (can_deopt && !IsAllowedForInlining(call->deopt_id())) { 1588 if (can_deopt && !IsAllowedForInlining(call->deopt_id())) {
1713 // Guard against repeated speculative inlining. 1589 // Guard against repeated speculative inlining.
1714 return; 1590 return;
1715 } 1591 }
1716 TestCidsInstr* test_cids = new(Z) TestCidsInstr( 1592 TestCidsInstr* test_cids = new (Z)
1717 call->token_pos(), 1593 TestCidsInstr(call->token_pos(), negate ? Token::kISNOT : Token::kIS,
1718 negate ? Token::kISNOT : Token::kIS, 1594 new (Z) Value(left), *results,
1719 new(Z) Value(left), 1595 can_deopt ? call->deopt_id() : Thread::kNoDeoptId);
1720 *results,
1721 can_deopt ? call->deopt_id() : Thread::kNoDeoptId);
1722 // Remove type. 1596 // Remove type.
1723 ReplaceCall(call, test_cids); 1597 ReplaceCall(call, test_cids);
1724 return; 1598 return;
1725 } 1599 }
1726 } 1600 }
1727 1601
1728 InstanceOfInstr* instance_of = 1602 InstanceOfInstr* instance_of = new (Z)
1729 new(Z) InstanceOfInstr(call->token_pos(), 1603 InstanceOfInstr(call->token_pos(), new (Z) Value(left),
1730 new(Z) Value(left), 1604 new (Z) Value(type_args), type, negate, call->deopt_id());
1731 new(Z) Value(type_args),
1732 type,
1733 negate,
1734 call->deopt_id());
1735 ReplaceCall(call, instance_of); 1605 ReplaceCall(call, instance_of);
1736 } 1606 }
1737 1607
1738 1608
1739 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). 1609 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
1740 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { 1610 void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
1741 ASSERT(Token::IsTypeCastOperator(call->token_kind())); 1611 ASSERT(Token::IsTypeCastOperator(call->token_kind()));
1742 Definition* left = call->ArgumentAt(0); 1612 Definition* left = call->ArgumentAt(0);
1743 Definition* type_args = call->ArgumentAt(1); 1613 Definition* type_args = call->ArgumentAt(1);
1744 const AbstractType& type = 1614 const AbstractType& type =
1745 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); 1615 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value());
1746 ASSERT(!type.IsMalformedOrMalbounded()); 1616 ASSERT(!type.IsMalformedOrMalbounded());
1747 const ICData& unary_checks = 1617 const ICData& unary_checks =
1748 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 1618 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
1749 if ((unary_checks.NumberOfChecks() > 0) && 1619 if ((unary_checks.NumberOfChecks() > 0) &&
1750 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { 1620 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
1751 ZoneGrowableArray<intptr_t>* results = 1621 ZoneGrowableArray<intptr_t>* results =
1752 new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); 1622 new (Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
1753 const Bool& as_bool = Bool::ZoneHandle(Z, 1623 const Bool& as_bool =
1754 InstanceOfAsBool(unary_checks, type, results)); 1624 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results));
1755 if (as_bool.raw() == Bool::True().raw()) { 1625 if (as_bool.raw() == Bool::True().raw()) {
1756 // Guard against repeated speculative inlining. 1626 // Guard against repeated speculative inlining.
1757 if (!IsAllowedForInlining(call->deopt_id())) { 1627 if (!IsAllowedForInlining(call->deopt_id())) {
1758 return; 1628 return;
1759 } 1629 }
1760 AddReceiverCheck(call); 1630 AddReceiverCheck(call);
1761 // Remove the original push arguments. 1631 // Remove the original push arguments.
1762 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 1632 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
1763 PushArgumentInstr* push = call->PushArgumentAt(i); 1633 PushArgumentInstr* push = call->PushArgumentAt(i);
1764 push->ReplaceUsesWith(push->value()->definition()); 1634 push->ReplaceUsesWith(push->value()->definition());
1765 push->RemoveFromGraph(); 1635 push->RemoveFromGraph();
1766 } 1636 }
1767 // Remove call, replace it with 'left'. 1637 // Remove call, replace it with 'left'.
1768 call->ReplaceUsesWith(left); 1638 call->ReplaceUsesWith(left);
1769 ASSERT(current_iterator()->Current() == call); 1639 ASSERT(current_iterator()->Current() == call);
1770 current_iterator()->RemoveCurrentFromGraph(); 1640 current_iterator()->RemoveCurrentFromGraph();
1771 return; 1641 return;
1772 } 1642 }
1773 } 1643 }
1774 AssertAssignableInstr* assert_as = 1644 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr(
1775 new(Z) AssertAssignableInstr(call->token_pos(), 1645 call->token_pos(), new (Z) Value(left), new (Z) Value(type_args), type,
1776 new(Z) Value(left), 1646 Symbols::InTypeCast(), call->deopt_id());
1777 new(Z) Value(type_args),
1778 type,
1779 Symbols::InTypeCast(),
1780 call->deopt_id());
1781 ReplaceCall(call, assert_as); 1647 ReplaceCall(call, assert_as);
1782 } 1648 }
1783 1649
1784 1650
1785 bool AotOptimizer::IsAllowedForInlining(intptr_t call_deopt_id) { 1651 bool AotOptimizer::IsAllowedForInlining(intptr_t call_deopt_id) {
1786 if (!use_speculative_inlining_) return false; 1652 if (!use_speculative_inlining_) return false;
1787 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) { 1653 for (intptr_t i = 0; i < inlining_black_list_->length(); ++i) {
1788 if ((*inlining_black_list_)[i] == call_deopt_id) return false; 1654 if ((*inlining_black_list_)[i] == call_deopt_id) return false;
1789 } 1655 }
1790 return true; 1656 return true;
(...skipping 20 matching lines...) Expand all
1811 1677
1812 1678
1813 bool AotOptimizer::TryInlineFieldAccess(InstanceCallInstr* call) { 1679 bool AotOptimizer::TryInlineFieldAccess(InstanceCallInstr* call) {
1814 const Token::Kind op_kind = call->token_kind(); 1680 const Token::Kind op_kind = call->token_kind();
1815 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(call)) { 1681 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(call)) {
1816 return true; 1682 return true;
1817 } 1683 }
1818 1684
1819 const ICData& unary_checks = 1685 const ICData& unary_checks =
1820 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); 1686 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks());
1821 if ((unary_checks.NumberOfChecks() > 0) && 1687 if ((unary_checks.NumberOfChecks() > 0) && (op_kind == Token::kSET) &&
1822 (op_kind == Token::kSET) &&
1823 TryInlineInstanceSetter(call, unary_checks)) { 1688 TryInlineInstanceSetter(call, unary_checks)) {
1824 return true; 1689 return true;
1825 } 1690 }
1826 1691
1827 return false; 1692 return false;
1828 } 1693 }
1829 1694
1830 1695
1831 // Tries to optimize instance call by replacing it with a faster instruction 1696 // Tries to optimize instance call by replacing it with a faster instruction
1832 // (e.g, binary op, field load, ..). 1697 // (e.g, binary op, field load, ..).
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1889 if (TryInlineInstanceMethod(instr)) { 1754 if (TryInlineInstanceMethod(instr)) {
1890 return; 1755 return;
1891 } 1756 }
1892 } 1757 }
1893 1758
1894 bool has_one_target = 1759 bool has_one_target =
1895 (unary_checks.NumberOfChecks() > 0) && unary_checks.HasOneTarget(); 1760 (unary_checks.NumberOfChecks() > 0) && unary_checks.HasOneTarget();
1896 if (has_one_target) { 1761 if (has_one_target) {
1897 // Check if the single target is a polymorphic target, if it is, 1762 // Check if the single target is a polymorphic target, if it is,
1898 // we don't have one target. 1763 // we don't have one target.
1899 const Function& target = 1764 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
1900 Function::Handle(Z, unary_checks.GetTargetAt(0));
1901 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target); 1765 const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
1902 has_one_target = !polymorphic_target; 1766 has_one_target = !polymorphic_target;
1903 } 1767 }
1904 1768
1905 if (has_one_target) { 1769 if (has_one_target) {
1906 RawFunction::Kind function_kind = 1770 RawFunction::Kind function_kind =
1907 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind(); 1771 Function::Handle(Z, unary_checks.GetTargetAt(0)).kind();
1908 if (!flow_graph()->InstanceCallNeedsClassCheck( 1772 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) {
1909 instr, function_kind)) {
1910 PolymorphicInstanceCallInstr* call = 1773 PolymorphicInstanceCallInstr* call =
1911 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, 1774 new (Z) PolymorphicInstanceCallInstr(instr, unary_checks,
1912 /* with_checks = */ false, 1775 /* with_checks = */ false,
1913 /* complete = */ true); 1776 /* complete = */ true);
1914 instr->ReplaceWith(call, current_iterator()); 1777 instr->ReplaceWith(call, current_iterator());
1915 return; 1778 return;
1916 } 1779 }
1917 } 1780 }
1918 switch (instr->token_kind()) { 1781 switch (instr->token_kind()) {
1919 case Token::kEQ: 1782 case Token::kEQ:
1920 case Token::kLT: 1783 case Token::kLT:
1921 case Token::kLTE: 1784 case Token::kLTE:
1922 case Token::kGT: 1785 case Token::kGT:
1923 case Token::kGTE: { 1786 case Token::kGTE: {
1924 if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) || 1787 if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) ||
1925 HasLikelySmiOperand(instr)) { 1788 HasLikelySmiOperand(instr)) {
1926 Definition* left = instr->ArgumentAt(0); 1789 Definition* left = instr->ArgumentAt(0);
1927 Definition* right = instr->ArgumentAt(1); 1790 Definition* right = instr->ArgumentAt(1);
1928 CheckedSmiComparisonInstr* smi_op = 1791 CheckedSmiComparisonInstr* smi_op = new (Z)
1929 new(Z) CheckedSmiComparisonInstr(instr->token_kind(), 1792 CheckedSmiComparisonInstr(instr->token_kind(), new (Z) Value(left),
1930 new(Z) Value(left), 1793 new (Z) Value(right), instr);
1931 new(Z) Value(right),
1932 instr);
1933 ReplaceCall(instr, smi_op); 1794 ReplaceCall(instr, smi_op);
1934 return; 1795 return;
1935 } 1796 }
1936 break; 1797 break;
1937 } 1798 }
1938 case Token::kBIT_OR: 1799 case Token::kBIT_OR:
1939 case Token::kBIT_XOR: 1800 case Token::kBIT_XOR:
1940 case Token::kBIT_AND: 1801 case Token::kBIT_AND:
1941 case Token::kADD: 1802 case Token::kADD:
1942 case Token::kSUB: 1803 case Token::kSUB:
1943 case Token::kMUL: { 1804 case Token::kMUL: {
1944 if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) || 1805 if (HasOnlyTwoOf(*instr->ic_data(), kSmiCid) ||
1945 HasLikelySmiOperand(instr)) { 1806 HasLikelySmiOperand(instr)) {
1946 Definition* left = instr->ArgumentAt(0); 1807 Definition* left = instr->ArgumentAt(0);
1947 Definition* right = instr->ArgumentAt(1); 1808 Definition* right = instr->ArgumentAt(1);
1948 CheckedSmiOpInstr* smi_op = 1809 CheckedSmiOpInstr* smi_op =
1949 new(Z) CheckedSmiOpInstr(instr->token_kind(), 1810 new (Z) CheckedSmiOpInstr(instr->token_kind(), new (Z) Value(left),
1950 new(Z) Value(left), 1811 new (Z) Value(right), instr);
1951 new(Z) Value(right),
1952 instr);
1953 1812
1954 ReplaceCall(instr, smi_op); 1813 ReplaceCall(instr, smi_op);
1955 return; 1814 return;
1956 } 1815 }
1957 break; 1816 break;
1958 } 1817 }
1959 default: 1818 default:
1960 break; 1819 break;
1961 } 1820 }
1962 1821
1963 // No IC data checks. Try resolve target using the propagated cid. 1822 // No IC data checks. Try resolve target using the propagated cid.
1964 const intptr_t receiver_cid = 1823 const intptr_t receiver_cid =
1965 instr->PushArgumentAt(0)->value()->Type()->ToCid(); 1824 instr->PushArgumentAt(0)->value()->Type()->ToCid();
1966 if (receiver_cid != kDynamicCid) { 1825 if (receiver_cid != kDynamicCid) {
1967 const Class& receiver_class = Class::Handle(Z, 1826 const Class& receiver_class =
1968 isolate()->class_table()->At(receiver_cid)); 1827 Class::Handle(Z, isolate()->class_table()->At(receiver_cid));
1969 1828
1970 const Array& args_desc_array = Array::Handle(Z, 1829 const Array& args_desc_array =
1971 ArgumentsDescriptor::New(instr->ArgumentCount(), 1830 Array::Handle(Z, ArgumentsDescriptor::New(instr->ArgumentCount(),
1972 instr->argument_names())); 1831 instr->argument_names()));
1973 ArgumentsDescriptor args_desc(args_desc_array); 1832 ArgumentsDescriptor args_desc(args_desc_array);
1974 const Function& function = Function::Handle(Z, 1833 const Function& function = Function::Handle(
1975 Resolver::ResolveDynamicForReceiverClass( 1834 Z, Resolver::ResolveDynamicForReceiverClass(
1976 receiver_class, 1835 receiver_class, instr->function_name(), args_desc));
1977 instr->function_name(),
1978 args_desc));
1979 if (!function.IsNull()) { 1836 if (!function.IsNull()) {
1980 const ICData& ic_data = ICData::Handle( 1837 const ICData& ic_data = ICData::Handle(
1981 ICData::New(flow_graph_->function(), 1838 ICData::New(flow_graph_->function(), instr->function_name(),
1982 instr->function_name(), 1839 args_desc_array, Thread::kNoDeoptId,
1983 args_desc_array, 1840 /* args_tested = */ 1, false));
1984 Thread::kNoDeoptId,
1985 /* args_tested = */ 1,
1986 false));
1987 ic_data.AddReceiverCheck(receiver_class.id(), function); 1841 ic_data.AddReceiverCheck(receiver_class.id(), function);
1988 PolymorphicInstanceCallInstr* call = 1842 PolymorphicInstanceCallInstr* call =
1989 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, 1843 new (Z) PolymorphicInstanceCallInstr(instr, ic_data,
1990 /* with_checks = */ false, 1844 /* with_checks = */ false,
1991 /* complete = */ true); 1845 /* complete = */ true);
1992 instr->ReplaceWith(call, current_iterator()); 1846 instr->ReplaceWith(call, current_iterator());
1993 return; 1847 return;
1994 } 1848 }
1995 } 1849 }
1996 1850
1997 Definition* callee_receiver = instr->ArgumentAt(0); 1851 Definition* callee_receiver = instr->ArgumentAt(0);
1998 const Function& function = flow_graph_->function(); 1852 const Function& function = flow_graph_->function();
1999 if (function.IsDynamicFunction() && 1853 if (function.IsDynamicFunction() &&
2000 flow_graph_->IsReceiver(callee_receiver)) { 1854 flow_graph_->IsReceiver(callee_receiver)) {
2001 // Call receiver is method receiver. 1855 // Call receiver is method receiver.
2002 Class& receiver_class = Class::Handle(Z, function.Owner()); 1856 Class& receiver_class = Class::Handle(Z, function.Owner());
2003 1857
2004 GrowableArray<intptr_t> class_ids(6); 1858 GrowableArray<intptr_t> class_ids(6);
2005 if (thread()->cha()->ConcreteSubclasses(receiver_class, &class_ids)) { 1859 if (thread()->cha()->ConcreteSubclasses(receiver_class, &class_ids)) {
2006 // First check if all subclasses end up calling the same method. 1860 // First check if all subclasses end up calling the same method.
2007 // If this is the case we will replace instance call with a direct 1861 // If this is the case we will replace instance call with a direct
2008 // static call. 1862 // static call.
2009 // Otherwise we will try to create ICData that contains all possible 1863 // Otherwise we will try to create ICData that contains all possible
2010 // targets with appropriate checks. 1864 // targets with appropriate checks.
2011 Function& single_target = Function::Handle(Z); 1865 Function& single_target = Function::Handle(Z);
2012 ICData& ic_data = ICData::Handle(Z); 1866 ICData& ic_data = ICData::Handle(Z);
2013 1867
2014 const Array& args_desc_array = Array::Handle(Z, 1868 const Array& args_desc_array =
2015 ArgumentsDescriptor::New(instr->ArgumentCount(), 1869 Array::Handle(Z, ArgumentsDescriptor::New(instr->ArgumentCount(),
2016 instr->argument_names())); 1870 instr->argument_names()));
2017 ArgumentsDescriptor args_desc(args_desc_array); 1871 ArgumentsDescriptor args_desc(args_desc_array);
2018 1872
2019 Function& target = Function::Handle(Z); 1873 Function& target = Function::Handle(Z);
2020 Class& cls = Class::Handle(Z); 1874 Class& cls = Class::Handle(Z);
2021 for (intptr_t i = 0; i < class_ids.length(); i++) { 1875 for (intptr_t i = 0; i < class_ids.length(); i++) {
2022 const intptr_t cid = class_ids[i]; 1876 const intptr_t cid = class_ids[i];
2023 cls = isolate()->class_table()->At(cid); 1877 cls = isolate()->class_table()->At(cid);
2024 target = Resolver::ResolveDynamicForReceiverClass( 1878 target = Resolver::ResolveDynamicForReceiverClass(
2025 cls, 1879 cls, instr->function_name(), args_desc);
2026 instr->function_name(),
2027 args_desc);
2028 1880
2029 if (target.IsNull()) { 1881 if (target.IsNull()) {
2030 // Can't resolve the target. It might be a noSuchMethod, 1882 // Can't resolve the target. It might be a noSuchMethod,
2031 // call through getter or closurization. 1883 // call through getter or closurization.
2032 single_target = Function::null(); 1884 single_target = Function::null();
2033 ic_data = ICData::null(); 1885 ic_data = ICData::null();
2034 break; 1886 break;
2035 } else if (ic_data.IsNull()) { 1887 } else if (ic_data.IsNull()) {
2036 // First we are trying to compute a single target for all subclasses. 1888 // First we are trying to compute a single target for all subclasses.
2037 if (single_target.IsNull()) { 1889 if (single_target.IsNull()) {
2038 ASSERT(i == 0); 1890 ASSERT(i == 0);
2039 single_target = target.raw(); 1891 single_target = target.raw();
2040 continue; 1892 continue;
2041 } else if (single_target.raw() == target.raw()) { 1893 } else if (single_target.raw() == target.raw()) {
2042 continue; 1894 continue;
2043 } 1895 }
2044 1896
2045 // The call does not resolve to a single target within the hierarchy. 1897 // The call does not resolve to a single target within the hierarchy.
2046 // If we have too many subclasses abort the optimization. 1898 // If we have too many subclasses abort the optimization.
2047 if (class_ids.length() > FLAG_max_exhaustive_polymorphic_checks) { 1899 if (class_ids.length() > FLAG_max_exhaustive_polymorphic_checks) {
2048 single_target = Function::null(); 1900 single_target = Function::null();
2049 break; 1901 break;
2050 } 1902 }
2051 1903
2052 // Create an ICData and map all previously seen classes (< i) to 1904 // Create an ICData and map all previously seen classes (< i) to
2053 // the computed single_target. 1905 // the computed single_target.
2054 ic_data = ICData::New(function, 1906 ic_data = ICData::New(function, instr->function_name(),
2055 instr->function_name(), 1907 args_desc_array, Thread::kNoDeoptId,
2056 args_desc_array,
2057 Thread::kNoDeoptId,
2058 /* args_tested = */ 1, false); 1908 /* args_tested = */ 1, false);
2059 for (intptr_t j = 0; j < i; j++) { 1909 for (intptr_t j = 0; j < i; j++) {
2060 ic_data.AddReceiverCheck(class_ids[j], single_target); 1910 ic_data.AddReceiverCheck(class_ids[j], single_target);
2061 } 1911 }
2062 1912
2063 single_target = Function::null(); 1913 single_target = Function::null();
2064 } 1914 }
2065 1915
2066 ASSERT(ic_data.raw() != ICData::null()); 1916 ASSERT(ic_data.raw() != ICData::null());
2067 ASSERT(single_target.raw() == Function::null()); 1917 ASSERT(single_target.raw() == Function::null());
2068 ic_data.AddReceiverCheck(cid, target); 1918 ic_data.AddReceiverCheck(cid, target);
2069 } 1919 }
2070 1920
2071 if (single_target.raw() != Function::null()) { 1921 if (single_target.raw() != Function::null()) {
2072 // If this is a getter or setter invocation try inlining it right away 1922 // If this is a getter or setter invocation try inlining it right away
2073 // instead of replacing it with a static call. 1923 // instead of replacing it with a static call.
2074 if ((op_kind == Token::kGET) || (op_kind == Token::kSET)) { 1924 if ((op_kind == Token::kGET) || (op_kind == Token::kSET)) {
2075 // Create fake IC data with the resolved target. 1925 // Create fake IC data with the resolved target.
2076 const ICData& ic_data = ICData::Handle( 1926 const ICData& ic_data = ICData::Handle(
2077 ICData::New(flow_graph_->function(), 1927 ICData::New(flow_graph_->function(), instr->function_name(),
2078 instr->function_name(), 1928 args_desc_array, Thread::kNoDeoptId,
2079 args_desc_array, 1929 /* args_tested = */ 1, false));
2080 Thread::kNoDeoptId,
2081 /* args_tested = */ 1,
2082 false));
2083 cls = single_target.Owner(); 1930 cls = single_target.Owner();
2084 ic_data.AddReceiverCheck(cls.id(), single_target); 1931 ic_data.AddReceiverCheck(cls.id(), single_target);
2085 instr->set_ic_data(&ic_data); 1932 instr->set_ic_data(&ic_data);
2086 1933
2087 if (TryInlineFieldAccess(instr)) { 1934 if (TryInlineFieldAccess(instr)) {
2088 return; 1935 return;
2089 } 1936 }
2090 } 1937 }
2091 1938
2092 // We have computed that there is only a single target for this call 1939 // We have computed that there is only a single target for this call
2093 // within the whole hierarchy. Replace InstanceCall with StaticCall. 1940 // within the whole hierarchy. Replace InstanceCall with StaticCall.
2094 ZoneGrowableArray<PushArgumentInstr*>* args = 1941 ZoneGrowableArray<PushArgumentInstr*>* args = new (Z)
2095 new (Z) ZoneGrowableArray<PushArgumentInstr*>( 1942 ZoneGrowableArray<PushArgumentInstr*>(instr->ArgumentCount());
2096 instr->ArgumentCount());
2097 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) { 1943 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) {
2098 args->Add(instr->PushArgumentAt(i)); 1944 args->Add(instr->PushArgumentAt(i));
2099 } 1945 }
2100 StaticCallInstr* call = new (Z) StaticCallInstr( 1946 StaticCallInstr* call = new (Z) StaticCallInstr(
2101 instr->token_pos(), 1947 instr->token_pos(), Function::ZoneHandle(Z, single_target.raw()),
2102 Function::ZoneHandle(Z, single_target.raw()), 1948 instr->argument_names(), args, instr->deopt_id());
2103 instr->argument_names(),
2104 args,
2105 instr->deopt_id());
2106 instr->ReplaceWith(call, current_iterator()); 1949 instr->ReplaceWith(call, current_iterator());
2107 return; 1950 return;
2108 } else if ((ic_data.raw() != ICData::null()) && 1951 } else if ((ic_data.raw() != ICData::null()) &&
2109 (ic_data.NumberOfChecks() > 0)) { 1952 (ic_data.NumberOfChecks() > 0)) {
2110 PolymorphicInstanceCallInstr* call = 1953 PolymorphicInstanceCallInstr* call =
2111 new(Z) PolymorphicInstanceCallInstr(instr, ic_data, 1954 new (Z) PolymorphicInstanceCallInstr(instr, ic_data,
2112 /* with_checks = */ true, 1955 /* with_checks = */ true,
2113 /* complete = */ true); 1956 /* complete = */ true);
2114 instr->ReplaceWith(call, current_iterator()); 1957 instr->ReplaceWith(call, current_iterator());
2115 return; 1958 return;
2116 } 1959 }
2117 } 1960 }
2118 } 1961 }
2119 1962
2120 // More than one target. Generate generic polymorphic call without 1963 // More than one target. Generate generic polymorphic call without
2121 // deoptimization. 1964 // deoptimization.
2122 if (instr->ic_data()->NumberOfUsedChecks() > 0) { 1965 if (instr->ic_data()->NumberOfUsedChecks() > 0) {
2123 ASSERT(!FLAG_polymorphic_with_deopt); 1966 ASSERT(!FLAG_polymorphic_with_deopt);
2124 // OK to use checks with PolymorphicInstanceCallInstr since no 1967 // OK to use checks with PolymorphicInstanceCallInstr since no
2125 // deoptimization is allowed. 1968 // deoptimization is allowed.
2126 PolymorphicInstanceCallInstr* call = 1969 PolymorphicInstanceCallInstr* call =
2127 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, 1970 new (Z) PolymorphicInstanceCallInstr(instr, unary_checks,
2128 /* with_checks = */ true, 1971 /* with_checks = */ true,
2129 /* complete = */ false); 1972 /* complete = */ false);
2130 instr->ReplaceWith(call, current_iterator()); 1973 instr->ReplaceWith(call, current_iterator());
2131 return; 1974 return;
2132 } 1975 }
2133 } 1976 }
2134 1977
2135 1978
2136 void AotOptimizer::VisitPolymorphicInstanceCall( 1979 void AotOptimizer::VisitPolymorphicInstanceCall(
2137 PolymorphicInstanceCallInstr* call) { 1980 PolymorphicInstanceCallInstr* call) {
2138 if (call->with_checks()) { 1981 if (call->with_checks()) {
2139 const intptr_t receiver_cid = 1982 const intptr_t receiver_cid =
2140 call->PushArgumentAt(0)->value()->Type()->ToCid(); 1983 call->PushArgumentAt(0)->value()->Type()->ToCid();
2141 if (receiver_cid != kDynamicCid) { 1984 if (receiver_cid != kDynamicCid) {
2142 const Class& receiver_class = Class::Handle(Z, 1985 const Class& receiver_class =
2143 isolate()->class_table()->At(receiver_cid)); 1986 Class::Handle(Z, isolate()->class_table()->At(receiver_cid));
2144 1987
2145 const Array& args_desc_array = Array::Handle(Z, 1988 const Array& args_desc_array = Array::Handle(
2146 ArgumentsDescriptor::New(call->ArgumentCount(), 1989 Z, ArgumentsDescriptor::New(call->ArgumentCount(),
2147 call->instance_call()->argument_names())); 1990 call->instance_call()->argument_names()));
2148 ArgumentsDescriptor args_desc(args_desc_array); 1991 ArgumentsDescriptor args_desc(args_desc_array);
2149 const Function& function = Function::Handle(Z, 1992 const Function& function = Function::Handle(
2150 Resolver::ResolveDynamicForReceiverClass( 1993 Z, Resolver::ResolveDynamicForReceiverClass(
2151 receiver_class, 1994 receiver_class, call->instance_call()->function_name(),
2152 call->instance_call()->function_name(), 1995 args_desc));
2153 args_desc));
2154 if (!function.IsNull()) { 1996 if (!function.IsNull()) {
2155 call->set_with_checks(false); 1997 call->set_with_checks(false);
2156 } 1998 }
2157 } 1999 }
2158 } 2000 }
2159 } 2001 }
2160 2002
2161 2003
2162 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) { 2004 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
2163 if (!IsAllowedForInlining(call->deopt_id())) { 2005 if (!IsAllowedForInlining(call->deopt_id())) {
(...skipping 24 matching lines...) Expand all
2188 case MethodRecognizer::kMathAcos: 2030 case MethodRecognizer::kMathAcos:
2189 case MethodRecognizer::kMathAtan: 2031 case MethodRecognizer::kMathAtan:
2190 case MethodRecognizer::kMathAtan2: 2032 case MethodRecognizer::kMathAtan2:
2191 FlowGraphInliner::TryReplaceStaticCallWithInline( 2033 FlowGraphInliner::TryReplaceStaticCallWithInline(
2192 flow_graph_, current_iterator(), call); 2034 flow_graph_, current_iterator(), call);
2193 break; 2035 break;
2194 case MethodRecognizer::kMathMin: 2036 case MethodRecognizer::kMathMin:
2195 case MethodRecognizer::kMathMax: { 2037 case MethodRecognizer::kMathMax: {
2196 // We can handle only monomorphic min/max call sites with both arguments 2038 // We can handle only monomorphic min/max call sites with both arguments
2197 // being either doubles or smis. 2039 // being either doubles or smis.
2198 if (CanUnboxDouble() && 2040 if (CanUnboxDouble() && call->HasICData() &&
2199 call->HasICData() &&
2200 (call->ic_data()->NumberOfChecks() == 1)) { 2041 (call->ic_data()->NumberOfChecks() == 1)) {
2201 const ICData& ic_data = *call->ic_data(); 2042 const ICData& ic_data = *call->ic_data();
2202 intptr_t result_cid = kIllegalCid; 2043 intptr_t result_cid = kIllegalCid;
2203 if (ICDataHasReceiverArgumentClassIds(ic_data, 2044 if (ICDataHasReceiverArgumentClassIds(ic_data, kDoubleCid,
2204 kDoubleCid, kDoubleCid)) { 2045 kDoubleCid)) {
2205 result_cid = kDoubleCid; 2046 result_cid = kDoubleCid;
2206 } else if (ICDataHasReceiverArgumentClassIds(ic_data, 2047 } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid,
2207 kSmiCid, kSmiCid)) { 2048 kSmiCid)) {
2208 result_cid = kSmiCid; 2049 result_cid = kSmiCid;
2209 } 2050 }
2210 if (result_cid != kIllegalCid) { 2051 if (result_cid != kIllegalCid) {
2211 MathMinMaxInstr* min_max = new(Z) MathMinMaxInstr( 2052 MathMinMaxInstr* min_max = new (Z) MathMinMaxInstr(
2212 recognized_kind, 2053 recognized_kind, new (Z) Value(call->ArgumentAt(0)),
2213 new(Z) Value(call->ArgumentAt(0)), 2054 new (Z) Value(call->ArgumentAt(1)), call->deopt_id(), result_cid);
2214 new(Z) Value(call->ArgumentAt(1)),
2215 call->deopt_id(),
2216 result_cid);
2217 const ICData& unary_checks = 2055 const ICData& unary_checks =
2218 ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks()); 2056 ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks());
2219 AddCheckClass(min_max->left()->definition(), 2057 AddCheckClass(min_max->left()->definition(), unary_checks,
2220 unary_checks, 2058 call->deopt_id(), call->env(), call);
2221 call->deopt_id(), 2059 AddCheckClass(min_max->right()->definition(), unary_checks,
2222 call->env(), 2060 call->deopt_id(), call->env(), call);
2223 call);
2224 AddCheckClass(min_max->right()->definition(),
2225 unary_checks,
2226 call->deopt_id(),
2227 call->env(),
2228 call);
2229 ReplaceCall(call, min_max); 2061 ReplaceCall(call, min_max);
2230 } 2062 }
2231 } 2063 }
2232 break; 2064 break;
2233 } 2065 }
2234 case MethodRecognizer::kDoubleFromInteger: { 2066 case MethodRecognizer::kDoubleFromInteger: {
2235 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { 2067 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
2236 const ICData& ic_data = *call->ic_data(); 2068 const ICData& ic_data = *call->ic_data();
2237 if (CanUnboxDouble()) { 2069 if (CanUnboxDouble()) {
2238 if (ArgIsAlways(kSmiCid, ic_data, 1)) { 2070 if (ArgIsAlways(kSmiCid, ic_data, 1)) {
2239 Definition* arg = call->ArgumentAt(1); 2071 Definition* arg = call->ArgumentAt(1);
2240 AddCheckSmi(arg, call->deopt_id(), call->env(), call); 2072 AddCheckSmi(arg, call->deopt_id(), call->env(), call);
2241 ReplaceCall(call, 2073 ReplaceCall(call, new (Z) SmiToDoubleInstr(new (Z) Value(arg),
2242 new(Z) SmiToDoubleInstr(new(Z) Value(arg), 2074 call->token_pos()));
2243 call->token_pos()));
2244 } else if (ArgIsAlways(kMintCid, ic_data, 1) && 2075 } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
2245 CanConvertUnboxedMintToDouble()) { 2076 CanConvertUnboxedMintToDouble()) {
2246 Definition* arg = call->ArgumentAt(1); 2077 Definition* arg = call->ArgumentAt(1);
2247 ReplaceCall(call, 2078 ReplaceCall(call, new (Z) MintToDoubleInstr(new (Z) Value(arg),
2248 new(Z) MintToDoubleInstr(new(Z) Value(arg), 2079 call->deopt_id()));
2249 call->deopt_id()));
2250 } 2080 }
2251 } 2081 }
2252 } 2082 }
2253 break; 2083 break;
2254 } 2084 }
2255 default: 2085 default:
2256 break; 2086 break;
2257 } 2087 }
2258 } 2088 }
2259 2089
2260 2090
2261 void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { 2091 void AotOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
2262 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. 2092 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
2263 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) 2093 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
2264 if (!instr->can_pack_into_smi()) 2094 if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedMint);
2265 instr->set_representation(kUnboxedMint);
2266 #endif 2095 #endif
2267 } 2096 }
2268 2097
2269 2098
2270 bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, 2099 bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
2271 const ICData& unary_ic_data) { 2100 const ICData& unary_ic_data) {
2272 ASSERT((unary_ic_data.NumberOfChecks() > 0) && 2101 ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
2273 (unary_ic_data.NumArgsTested() == 1)); 2102 (unary_ic_data.NumArgsTested() == 1));
2274 if (I->type_checks()) { 2103 if (I->type_checks()) {
2275 // Checked mode setters are inlined like normal methods by conventional 2104 // Checked mode setters are inlined like normal methods by conventional
2276 // inlining. 2105 // inlining.
2277 return false; 2106 return false;
2278 } 2107 }
2279 2108
2280 ASSERT(instr->HasICData()); 2109 ASSERT(instr->HasICData());
2281 if (unary_ic_data.NumberOfChecks() == 0) { 2110 if (unary_ic_data.NumberOfChecks() == 0) {
2282 // No type feedback collected. 2111 // No type feedback collected.
2283 return false; 2112 return false;
2284 } 2113 }
2285 if (!unary_ic_data.HasOneTarget()) { 2114 if (!unary_ic_data.HasOneTarget()) {
2286 // Polymorphic sites are inlined like normal method calls by conventional 2115 // Polymorphic sites are inlined like normal method calls by conventional
2287 // inlining. 2116 // inlining.
2288 return false; 2117 return false;
2289 } 2118 }
2290 Function& target = Function::Handle(Z); 2119 Function& target = Function::Handle(Z);
2291 intptr_t class_id; 2120 intptr_t class_id;
2292 unary_ic_data.GetOneClassCheckAt(0, &class_id, &target); 2121 unary_ic_data.GetOneClassCheckAt(0, &class_id, &target);
2293 if (target.kind() != RawFunction::kImplicitSetter) { 2122 if (target.kind() != RawFunction::kImplicitSetter) {
2294 // Non-implicit setter are inlined like normal method calls. 2123 // Non-implicit setter are inlined like normal method calls.
2295 return false; 2124 return false;
2296 } 2125 }
2297 // Inline implicit instance setter. 2126 // Inline implicit instance setter.
2298 const String& field_name = 2127 const String& field_name =
2299 String::Handle(Z, Field::NameFromSetter(instr->function_name())); 2128 String::Handle(Z, Field::NameFromSetter(instr->function_name()));
2300 const Field& field = 2129 const Field& field = Field::ZoneHandle(Z, GetField(class_id, field_name));
2301 Field::ZoneHandle(Z, GetField(class_id, field_name));
2302 ASSERT(!field.IsNull()); 2130 ASSERT(!field.IsNull());
2303 2131
2304 if (flow_graph()->InstanceCallNeedsClassCheck( 2132 if (flow_graph()->InstanceCallNeedsClassCheck(instr,
2305 instr, RawFunction::kImplicitSetter)) { 2133 RawFunction::kImplicitSetter)) {
2306 return false; 2134 return false;
2307 } 2135 }
2308 2136
2309 // Field guard was detached. 2137 // Field guard was detached.
2310 StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr( 2138 StoreInstanceFieldInstr* store = new (Z)
2311 field, 2139 StoreInstanceFieldInstr(field, new (Z) Value(instr->ArgumentAt(0)),
2312 new(Z) Value(instr->ArgumentAt(0)), 2140 new (Z) Value(instr->ArgumentAt(1)),
2313 new(Z) Value(instr->ArgumentAt(1)), 2141 kEmitStoreBarrier, instr->token_pos());
2314 kEmitStoreBarrier,
2315 instr->token_pos());
2316 2142
2317 // No unboxed stores in precompiled code. 2143 // No unboxed stores in precompiled code.
2318 ASSERT(!store->IsUnboxedStore()); 2144 ASSERT(!store->IsUnboxedStore());
2319 2145
2320 // Discard the environment from the original instruction because the store 2146 // Discard the environment from the original instruction because the store
2321 // can't deoptimize. 2147 // can't deoptimize.
2322 instr->RemoveEnvironment(); 2148 instr->RemoveEnvironment();
2323 ReplaceCall(instr, store); 2149 ReplaceCall(instr, store);
2324 return true; 2150 return true;
2325 } 2151 }
2326 2152
2327 2153
2328 void AotOptimizer::ReplaceArrayBoundChecks() { 2154 void AotOptimizer::ReplaceArrayBoundChecks() {
2329 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 2155 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
2330 !block_it.Done(); 2156 !block_it.Done(); block_it.Advance()) {
2331 block_it.Advance()) {
2332 ForwardInstructionIterator it(block_it.Current()); 2157 ForwardInstructionIterator it(block_it.Current());
2333 current_iterator_ = &it; 2158 current_iterator_ = &it;
2334 for (; !it.Done(); it.Advance()) { 2159 for (; !it.Done(); it.Advance()) {
2335 CheckArrayBoundInstr* check = it.Current()->AsCheckArrayBound(); 2160 CheckArrayBoundInstr* check = it.Current()->AsCheckArrayBound();
2336 if (check != NULL) { 2161 if (check != NULL) {
2337 GenericCheckBoundInstr* new_check = new(Z) GenericCheckBoundInstr( 2162 GenericCheckBoundInstr* new_check = new (Z) GenericCheckBoundInstr(
2338 new(Z) Value(check->length()->definition()), 2163 new (Z) Value(check->length()->definition()),
2339 new(Z) Value(check->index()->definition()), 2164 new (Z) Value(check->index()->definition()), check->deopt_id());
2340 check->deopt_id()); 2165 flow_graph_->InsertBefore(check, new_check, check->env(),
2341 flow_graph_->InsertBefore(check, new_check, 2166 FlowGraph::kEffect);
2342 check->env(), FlowGraph::kEffect);
2343 current_iterator()->RemoveCurrentFromGraph(); 2167 current_iterator()->RemoveCurrentFromGraph();
2344 } 2168 }
2345 } 2169 }
2346 } 2170 }
2347 } 2171 }
2348 2172
2349 #endif // DART_PRECOMPILER 2173 #endif // DART_PRECOMPILER
2350 2174
2351 } // namespace dart 2175 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/aot_optimizer.h ('k') | runtime/vm/assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698