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

Side by Side Diff: runtime/vm/jit_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/jit_optimizer.h ('k') | runtime/vm/json_stream.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/jit_optimizer.h" 5 #include "vm/jit_optimizer.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/branch_optimizer.h" 8 #include "vm/branch_optimizer.h"
9 #include "vm/cha.h" 9 #include "vm/cha.h"
10 #include "vm/compiler.h" 10 #include "vm/compiler.h"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 54
55 // Optimize instance calls using cid. This is called after optimizer 55 // Optimize instance calls using cid. This is called after optimizer
56 // converted instance calls to instructions. Any remaining 56 // converted instance calls to instructions. Any remaining
57 // instance calls are either megamorphic calls, cannot be optimized or 57 // instance calls are either megamorphic calls, cannot be optimized or
58 // have no runtime type feedback collected. 58 // have no runtime type feedback collected.
59 // Attempts to convert an instance call (IC call) using propagated class-ids, 59 // Attempts to convert an instance call (IC call) using propagated class-ids,
60 // e.g., receiver class id, guarded-cid, or by guessing cid-s. 60 // e.g., receiver class id, guarded-cid, or by guessing cid-s.
61 void JitOptimizer::ApplyClassIds() { 61 void JitOptimizer::ApplyClassIds() {
62 ASSERT(current_iterator_ == NULL); 62 ASSERT(current_iterator_ == NULL);
63 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); 63 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
64 !block_it.Done(); 64 !block_it.Done(); block_it.Advance()) {
65 block_it.Advance()) {
66 ForwardInstructionIterator it(block_it.Current()); 65 ForwardInstructionIterator it(block_it.Current());
67 current_iterator_ = ⁢ 66 current_iterator_ = ⁢
68 for (; !it.Done(); it.Advance()) { 67 for (; !it.Done(); it.Advance()) {
69 Instruction* instr = it.Current(); 68 Instruction* instr = it.Current();
70 if (instr->IsInstanceCall()) { 69 if (instr->IsInstanceCall()) {
71 InstanceCallInstr* call = instr->AsInstanceCall(); 70 InstanceCallInstr* call = instr->AsInstanceCall();
72 if (call->HasICData()) { 71 if (call->HasICData()) {
73 if (TryCreateICData(call)) { 72 if (TryCreateICData(call)) {
74 VisitInstanceCall(call); 73 VisitInstanceCall(call);
75 } 74 }
(...skipping 22 matching lines...) Expand all
98 } 97 }
99 98
100 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); 99 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested());
101 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount()); 100 ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount());
102 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) { 101 for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) {
103 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid()); 102 class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid());
104 } 103 }
105 104
106 const Token::Kind op_kind = call->token_kind(); 105 const Token::Kind op_kind = call->token_kind();
107 if (Token::IsRelationalOperator(op_kind) || 106 if (Token::IsRelationalOperator(op_kind) ||
108 Token::IsEqualityOperator(op_kind) || 107 Token::IsEqualityOperator(op_kind) || Token::IsBinaryOperator(op_kind)) {
109 Token::IsBinaryOperator(op_kind)) {
110 // Guess cid: if one of the inputs is a number assume that the other 108 // Guess cid: if one of the inputs is a number assume that the other
111 // is a number of same type. 109 // is a number of same type.
112 if (FLAG_guess_icdata_cid) { 110 if (FLAG_guess_icdata_cid) {
113 const intptr_t cid_0 = class_ids[0]; 111 const intptr_t cid_0 = class_ids[0];
114 const intptr_t cid_1 = class_ids[1]; 112 const intptr_t cid_1 = class_ids[1];
115 if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) { 113 if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) {
116 class_ids[0] = cid_1; 114 class_ids[0] = cid_1;
117 } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) { 115 } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) {
118 class_ids[1] = cid_0; 116 class_ids[1] = cid_0;
119 } 117 }
120 } 118 }
121 } 119 }
122 120
123 bool all_cids_known = true; 121 bool all_cids_known = true;
124 for (intptr_t i = 0; i < class_ids.length(); i++) { 122 for (intptr_t i = 0; i < class_ids.length(); i++) {
125 if (class_ids[i] == kDynamicCid) { 123 if (class_ids[i] == kDynamicCid) {
126 // Not all cid-s known. 124 // Not all cid-s known.
127 all_cids_known = false; 125 all_cids_known = false;
128 break; 126 break;
129 } 127 }
130 } 128 }
131 129
132 if (all_cids_known) { 130 if (all_cids_known) {
133 const Class& receiver_class = Class::Handle(Z, 131 const Class& receiver_class =
134 isolate()->class_table()->At(class_ids[0])); 132 Class::Handle(Z, isolate()->class_table()->At(class_ids[0]));
135 if (!receiver_class.is_finalized()) { 133 if (!receiver_class.is_finalized()) {
136 // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can 134 // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can
137 // cause class finalization, since callee's receiver class may not be 135 // cause class finalization, since callee's receiver class may not be
138 // finalized yet. 136 // finalized yet.
139 return false; 137 return false;
140 } 138 }
141 const Array& args_desc_array = Array::Handle(Z, 139 const Array& args_desc_array =
142 ArgumentsDescriptor::New(call->ArgumentCount(), 140 Array::Handle(Z, ArgumentsDescriptor::New(call->ArgumentCount(),
143 call->argument_names())); 141 call->argument_names()));
144 ArgumentsDescriptor args_desc(args_desc_array); 142 ArgumentsDescriptor args_desc(args_desc_array);
145 const Function& function = Function::Handle(Z, 143 const Function& function =
146 Resolver::ResolveDynamicForReceiverClass( 144 Function::Handle(Z, Resolver::ResolveDynamicForReceiverClass(
147 receiver_class, 145 receiver_class, call->function_name(),
148 call->function_name(), 146 args_desc, false /* allow add */));
149 args_desc,
150 false /* allow add */));
151 if (function.IsNull()) { 147 if (function.IsNull()) {
152 return false; 148 return false;
153 } 149 }
154 150
155 // Create new ICData, do not modify the one attached to the instruction 151 // Create new ICData, do not modify the one attached to the instruction
156 // since it is attached to the assembly instruction itself. 152 // since it is attached to the assembly instruction itself.
157 // TODO(srdjan): Prevent modification of ICData object that is 153 // TODO(srdjan): Prevent modification of ICData object that is
158 // referenced in assembly code. 154 // referenced in assembly code.
159 const ICData& ic_data = ICData::ZoneHandle(Z, 155 const ICData& ic_data = ICData::ZoneHandle(
160 ICData::NewFrom(*call->ic_data(), class_ids.length())); 156 Z, ICData::NewFrom(*call->ic_data(), class_ids.length()));
161 if (class_ids.length() > 1) { 157 if (class_ids.length() > 1) {
162 ic_data.AddCheck(class_ids, function); 158 ic_data.AddCheck(class_ids, function);
163 } else { 159 } else {
164 ASSERT(class_ids.length() == 1); 160 ASSERT(class_ids.length() == 1);
165 ic_data.AddReceiverCheck(class_ids[0], function); 161 ic_data.AddReceiverCheck(class_ids[0], function);
166 } 162 }
167 call->set_ic_data(&ic_data); 163 call->set_ic_data(&ic_data);
168 return true; 164 return true;
169 } 165 }
170 166
171 // Check if getter or setter in function's class and class is currently leaf. 167 // Check if getter or setter in function's class and class is currently leaf.
172 if (FLAG_guess_icdata_cid && 168 if (FLAG_guess_icdata_cid && ((call->token_kind() == Token::kGET) ||
173 ((call->token_kind() == Token::kGET) || 169 (call->token_kind() == Token::kSET))) {
174 (call->token_kind() == Token::kSET))) {
175 const Class& owner_class = Class::Handle(Z, function().Owner()); 170 const Class& owner_class = Class::Handle(Z, function().Owner());
176 if (!owner_class.is_abstract() && 171 if (!owner_class.is_abstract() && !CHA::HasSubclasses(owner_class) &&
177 !CHA::HasSubclasses(owner_class) &&
178 !CHA::IsImplemented(owner_class)) { 172 !CHA::IsImplemented(owner_class)) {
179 const Array& args_desc_array = Array::Handle(Z, 173 const Array& args_desc_array =
180 ArgumentsDescriptor::New(call->ArgumentCount(), 174 Array::Handle(Z, ArgumentsDescriptor::New(call->ArgumentCount(),
181 call->argument_names())); 175 call->argument_names()));
182 ArgumentsDescriptor args_desc(args_desc_array); 176 ArgumentsDescriptor args_desc(args_desc_array);
183 const Function& function = Function::Handle(Z, 177 const Function& function =
184 Resolver::ResolveDynamicForReceiverClass(owner_class, 178 Function::Handle(Z, Resolver::ResolveDynamicForReceiverClass(
185 call->function_name(), 179 owner_class, call->function_name(), args_desc,
186 args_desc, 180 false /* allow_add */));
187 false /* allow_add */));
188 if (!function.IsNull()) { 181 if (!function.IsNull()) {
189 const ICData& ic_data = ICData::ZoneHandle(Z, 182 const ICData& ic_data = ICData::ZoneHandle(
190 ICData::NewFrom(*call->ic_data(), class_ids.length())); 183 Z, ICData::NewFrom(*call->ic_data(), class_ids.length()));
191 ic_data.AddReceiverCheck(owner_class.id(), function); 184 ic_data.AddReceiverCheck(owner_class.id(), function);
192 call->set_ic_data(&ic_data); 185 call->set_ic_data(&ic_data);
193 return true; 186 return true;
194 } 187 }
195 } 188 }
196 } 189 }
197 190
198 return false; 191 return false;
199 } 192 }
200 193
201 194
202 const ICData& JitOptimizer::TrySpecializeICData(const ICData& ic_data, 195 const ICData& JitOptimizer::TrySpecializeICData(const ICData& ic_data,
203 intptr_t cid) { 196 intptr_t cid) {
204 ASSERT(ic_data.NumArgsTested() == 1); 197 ASSERT(ic_data.NumArgsTested() == 1);
205 198
206 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) { 199 if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
207 return ic_data; // Nothing to do 200 return ic_data; // Nothing to do
208 } 201 }
209 202
210 const Function& function = 203 const Function& function =
211 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid)); 204 Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid));
212 // TODO(fschneider): Try looking up the function on the class if it is 205 // TODO(fschneider): Try looking up the function on the class if it is
213 // not found in the ICData. 206 // not found in the ICData.
214 if (!function.IsNull()) { 207 if (!function.IsNull()) {
215 const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New( 208 const ICData& new_ic_data = ICData::ZoneHandle(
216 Function::Handle(Z, ic_data.Owner()), 209 Z, ICData::New(Function::Handle(Z, ic_data.Owner()),
217 String::Handle(Z, ic_data.target_name()), 210 String::Handle(Z, ic_data.target_name()),
218 Object::empty_array(), // Dummy argument descriptor. 211 Object::empty_array(), // Dummy argument descriptor.
219 ic_data.deopt_id(), 212 ic_data.deopt_id(), ic_data.NumArgsTested(), false));
220 ic_data.NumArgsTested(),
221 false));
222 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons()); 213 new_ic_data.SetDeoptReasons(ic_data.DeoptReasons());
223 new_ic_data.AddReceiverCheck(cid, function); 214 new_ic_data.AddReceiverCheck(cid, function);
224 return new_ic_data; 215 return new_ic_data;
225 } 216 }
226 217
227 return ic_data; 218 return ic_data;
228 } 219 }
229 220
230 221
231 void JitOptimizer::SpecializePolymorphicInstanceCall( 222 void JitOptimizer::SpecializePolymorphicInstanceCall(
(...skipping 14 matching lines...) Expand all
246 237
247 const ICData& ic_data = TrySpecializeICData(call->ic_data(), receiver_cid); 238 const ICData& ic_data = TrySpecializeICData(call->ic_data(), receiver_cid);
248 if (ic_data.raw() == call->ic_data().raw()) { 239 if (ic_data.raw() == call->ic_data().raw()) {
249 // No specialization. 240 // No specialization.
250 return; 241 return;
251 } 242 }
252 243
253 const bool with_checks = false; 244 const bool with_checks = false;
254 const bool complete = false; 245 const bool complete = false;
255 PolymorphicInstanceCallInstr* specialized = 246 PolymorphicInstanceCallInstr* specialized =
256 new(Z) PolymorphicInstanceCallInstr(call->instance_call(), 247 new (Z) PolymorphicInstanceCallInstr(call->instance_call(), ic_data,
257 ic_data, 248 with_checks, complete);
258 with_checks,
259 complete);
260 call->ReplaceWith(specialized, current_iterator()); 249 call->ReplaceWith(specialized, current_iterator());
261 } 250 }
262 251
263 252
264 static bool ClassIdIsOneOf(intptr_t class_id, 253 static bool ClassIdIsOneOf(intptr_t class_id,
265 const GrowableArray<intptr_t>& class_ids) { 254 const GrowableArray<intptr_t>& class_ids) {
266 for (intptr_t i = 0; i < class_ids.length(); i++) { 255 for (intptr_t i = 0; i < class_ids.length(); i++) {
267 ASSERT(class_ids[i] != kIllegalCid); 256 ASSERT(class_ids[i] != kIllegalCid);
268 if (class_ids[i] == class_id) { 257 if (class_ids[i] == class_id) {
269 return true; 258 return true;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 (class_ids[1] == argument_class_id)) { 303 (class_ids[1] == argument_class_id)) {
315 return true; 304 return true;
316 } 305 }
317 } 306 }
318 } 307 }
319 return false; 308 return false;
320 } 309 }
321 310
322 311
323 static bool HasOnlyOneSmi(const ICData& ic_data) { 312 static bool HasOnlyOneSmi(const ICData& ic_data) {
324 return (ic_data.NumberOfUsedChecks() == 1) 313 return (ic_data.NumberOfUsedChecks() == 1) &&
325 && ic_data.HasReceiverClassId(kSmiCid); 314 ic_data.HasReceiverClassId(kSmiCid);
326 } 315 }
327 316
328 317
329 static bool HasOnlySmiOrMint(const ICData& ic_data) { 318 static bool HasOnlySmiOrMint(const ICData& ic_data) {
330 if (ic_data.NumberOfUsedChecks() == 1) { 319 if (ic_data.NumberOfUsedChecks() == 1) {
331 return ic_data.HasReceiverClassId(kSmiCid) 320 return ic_data.HasReceiverClassId(kSmiCid) ||
332 || ic_data.HasReceiverClassId(kMintCid); 321 ic_data.HasReceiverClassId(kMintCid);
333 } 322 }
334 return (ic_data.NumberOfUsedChecks() == 2) 323 return (ic_data.NumberOfUsedChecks() == 2) &&
335 && ic_data.HasReceiverClassId(kSmiCid) 324 ic_data.HasReceiverClassId(kSmiCid) &&
336 && ic_data.HasReceiverClassId(kMintCid); 325 ic_data.HasReceiverClassId(kMintCid);
337 } 326 }
338 327
339 328
340 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) { 329 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
341 if (ic_data.NumberOfUsedChecks() != 1) { 330 if (ic_data.NumberOfUsedChecks() != 1) {
342 return false; 331 return false;
343 } 332 }
344 GrowableArray<intptr_t> first; 333 GrowableArray<intptr_t> first;
345 GrowableArray<intptr_t> second; 334 GrowableArray<intptr_t> second;
346 ic_data.GetUsedCidsForTwoArgs(&first, &second); 335 ic_data.GetUsedCidsForTwoArgs(&first, &second);
(...skipping 22 matching lines...) Expand all
369 // of Double and Smi for the receiver and argument classes. 358 // of Double and Smi for the receiver and argument classes.
370 static bool HasTwoDoubleOrSmi(const ICData& ic_data) { 359 static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
371 GrowableArray<intptr_t> class_ids(2); 360 GrowableArray<intptr_t> class_ids(2);
372 class_ids.Add(kSmiCid); 361 class_ids.Add(kSmiCid);
373 class_ids.Add(kDoubleCid); 362 class_ids.Add(kDoubleCid);
374 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); 363 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
375 } 364 }
376 365
377 366
378 static bool HasOnlyOneDouble(const ICData& ic_data) { 367 static bool HasOnlyOneDouble(const ICData& ic_data) {
379 return (ic_data.NumberOfUsedChecks() == 1) 368 return (ic_data.NumberOfUsedChecks() == 1) &&
380 && ic_data.HasReceiverClassId(kDoubleCid); 369 ic_data.HasReceiverClassId(kDoubleCid);
381 } 370 }
382 371
383 372
384 static bool ShouldSpecializeForDouble(const ICData& ic_data) { 373 static bool ShouldSpecializeForDouble(const ICData& ic_data) {
385 // Don't specialize for double if we can't unbox them. 374 // Don't specialize for double if we can't unbox them.
386 if (!CanUnboxDouble()) { 375 if (!CanUnboxDouble()) {
387 return false; 376 return false;
388 } 377 }
389 378
390 // Unboxed double operation can't handle case of two smis. 379 // Unboxed double operation can't handle case of two smis.
391 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 380 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
392 return false; 381 return false;
393 } 382 }
394 383
395 // Check that it have seen only smis and doubles. 384 // Check that it have seen only smis and doubles.
396 return HasTwoDoubleOrSmi(ic_data); 385 return HasTwoDoubleOrSmi(ic_data);
397 } 386 }
398 387
399 388
400 void JitOptimizer::ReplaceCall(Definition* call, 389 void JitOptimizer::ReplaceCall(Definition* call, Definition* replacement) {
401 Definition* replacement) {
402 // Remove the original push arguments. 390 // Remove the original push arguments.
403 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 391 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
404 PushArgumentInstr* push = call->PushArgumentAt(i); 392 PushArgumentInstr* push = call->PushArgumentAt(i);
405 push->ReplaceUsesWith(push->value()->definition()); 393 push->ReplaceUsesWith(push->value()->definition());
406 push->RemoveFromGraph(); 394 push->RemoveFromGraph();
407 } 395 }
408 call->ReplaceWith(replacement, current_iterator()); 396 call->ReplaceWith(replacement, current_iterator());
409 } 397 }
410 398
411 399
412 void JitOptimizer::AddCheckSmi(Definition* to_check, 400 void JitOptimizer::AddCheckSmi(Definition* to_check,
413 intptr_t deopt_id, 401 intptr_t deopt_id,
414 Environment* deopt_environment, 402 Environment* deopt_environment,
415 Instruction* insert_before) { 403 Instruction* insert_before) {
416 if (to_check->Type()->ToCid() != kSmiCid) { 404 if (to_check->Type()->ToCid() != kSmiCid) {
417 InsertBefore(insert_before, 405 InsertBefore(insert_before,
418 new(Z) CheckSmiInstr(new(Z) Value(to_check), 406 new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id,
419 deopt_id, 407 insert_before->token_pos()),
420 insert_before->token_pos()), 408 deopt_environment, FlowGraph::kEffect);
421 deopt_environment,
422 FlowGraph::kEffect);
423 } 409 }
424 } 410 }
425 411
426 412
427 Instruction* JitOptimizer::GetCheckClass(Definition* to_check, 413 Instruction* JitOptimizer::GetCheckClass(Definition* to_check,
428 const ICData& unary_checks, 414 const ICData& unary_checks,
429 intptr_t deopt_id, 415 intptr_t deopt_id,
430 TokenPosition token_pos) { 416 TokenPosition token_pos) {
431 if ((unary_checks.NumberOfUsedChecks() == 1) && 417 if ((unary_checks.NumberOfUsedChecks() == 1) &&
432 unary_checks.HasReceiverClassId(kSmiCid)) { 418 unary_checks.HasReceiverClassId(kSmiCid)) {
433 return new(Z) CheckSmiInstr(new(Z) Value(to_check), 419 return new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, token_pos);
434 deopt_id,
435 token_pos);
436 } 420 }
437 return new(Z) CheckClassInstr( 421 return new (Z) CheckClassInstr(new (Z) Value(to_check), deopt_id,
438 new(Z) Value(to_check), deopt_id, unary_checks, token_pos); 422 unary_checks, token_pos);
439 } 423 }
440 424
441 425
442 void JitOptimizer::AddCheckClass(Definition* to_check, 426 void JitOptimizer::AddCheckClass(Definition* to_check,
443 const ICData& unary_checks, 427 const ICData& unary_checks,
444 intptr_t deopt_id, 428 intptr_t deopt_id,
445 Environment* deopt_environment, 429 Environment* deopt_environment,
446 Instruction* insert_before) { 430 Instruction* insert_before) {
447 // Type propagation has not run yet, we cannot eliminate the check. 431 // Type propagation has not run yet, we cannot eliminate the check.
448 Instruction* check = GetCheckClass( 432 Instruction* check = GetCheckClass(to_check, unary_checks, deopt_id,
449 to_check, unary_checks, deopt_id, insert_before->token_pos()); 433 insert_before->token_pos());
450 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); 434 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect);
451 } 435 }
452 436
453 437
454 void JitOptimizer::AddReceiverCheck(InstanceCallInstr* call) { 438 void JitOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
455 AddCheckClass(call->ArgumentAt(0), 439 AddCheckClass(call->ArgumentAt(0),
456 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()), 440 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
457 call->deopt_id(), 441 call->deopt_id(), call->env(), call);
458 call->env(),
459 call);
460 } 442 }
461 443
462 444
463 static bool ArgIsAlways(intptr_t cid, 445 static bool ArgIsAlways(intptr_t cid,
464 const ICData& ic_data, 446 const ICData& ic_data,
465 intptr_t arg_number) { 447 intptr_t arg_number) {
466 ASSERT(ic_data.NumArgsTested() > arg_number); 448 ASSERT(ic_data.NumArgsTested() > arg_number);
467 if (ic_data.NumberOfUsedChecks() == 0) { 449 if (ic_data.NumberOfUsedChecks() == 0) {
468 return false; 450 return false;
469 } 451 }
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 } 509 }
528 if (IsLengthOneString(left)) { 510 if (IsLengthOneString(left)) {
529 // Optimize if left is a string with length one (either constant or 511 // Optimize if left is a string with length one (either constant or
530 // result of string-from-char-code. 512 // result of string-from-char-code.
531 if (left->IsConstant()) { 513 if (left->IsConstant()) {
532 ConstantInstr* left_const = left->AsConstant(); 514 ConstantInstr* left_const = left->AsConstant();
533 const String& str = String::Cast(left_const->value()); 515 const String& str = String::Cast(left_const->value());
534 ASSERT(str.Length() == 1); 516 ASSERT(str.Length() == 1);
535 ConstantInstr* char_code_left = flow_graph()->GetConstant( 517 ConstantInstr* char_code_left = flow_graph()->GetConstant(
536 Smi::ZoneHandle(Z, Smi::New(static_cast<intptr_t>(str.CharAt(0))))); 518 Smi::ZoneHandle(Z, Smi::New(static_cast<intptr_t>(str.CharAt(0)))));
537 left_val = new(Z) Value(char_code_left); 519 left_val = new (Z) Value(char_code_left);
538 } else if (left->IsOneByteStringFromCharCode()) { 520 } else if (left->IsOneByteStringFromCharCode()) {
539 // Use input of string-from-charcode as left value. 521 // Use input of string-from-charcode as left value.
540 OneByteStringFromCharCodeInstr* instr = 522 OneByteStringFromCharCodeInstr* instr =
541 left->AsOneByteStringFromCharCode(); 523 left->AsOneByteStringFromCharCode();
542 left_val = new(Z) Value(instr->char_code()->definition()); 524 left_val = new (Z) Value(instr->char_code()->definition());
543 to_remove_left = instr; 525 to_remove_left = instr;
544 } else { 526 } else {
545 // IsLengthOneString(left) should have been false. 527 // IsLengthOneString(left) should have been false.
546 UNREACHABLE(); 528 UNREACHABLE();
547 } 529 }
548 530
549 Definition* to_remove_right = NULL; 531 Definition* to_remove_right = NULL;
550 Value* right_val = NULL; 532 Value* right_val = NULL;
551 if (right->IsOneByteStringFromCharCode()) { 533 if (right->IsOneByteStringFromCharCode()) {
552 // Skip string-from-char-code, and use its input as right value. 534 // Skip string-from-char-code, and use its input as right value.
553 OneByteStringFromCharCodeInstr* right_instr = 535 OneByteStringFromCharCodeInstr* right_instr =
554 right->AsOneByteStringFromCharCode(); 536 right->AsOneByteStringFromCharCode();
555 right_val = new(Z) Value(right_instr->char_code()->definition()); 537 right_val = new (Z) Value(right_instr->char_code()->definition());
556 to_remove_right = right_instr; 538 to_remove_right = right_instr;
557 } else { 539 } else {
558 const ICData& unary_checks_1 = 540 const ICData& unary_checks_1 =
559 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); 541 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
560 AddCheckClass(right, 542 AddCheckClass(right, unary_checks_1, call->deopt_id(), call->env(), call);
561 unary_checks_1,
562 call->deopt_id(),
563 call->env(),
564 call);
565 // String-to-char-code instructions returns -1 (illegal charcode) if 543 // String-to-char-code instructions returns -1 (illegal charcode) if
566 // string is not of length one. 544 // string is not of length one.
567 StringToCharCodeInstr* char_code_right = 545 StringToCharCodeInstr* char_code_right = new (Z)
568 new(Z) StringToCharCodeInstr(new(Z) Value(right), kOneByteStringCid); 546 StringToCharCodeInstr(new (Z) Value(right), kOneByteStringCid);
569 InsertBefore(call, char_code_right, call->env(), FlowGraph::kValue); 547 InsertBefore(call, char_code_right, call->env(), FlowGraph::kValue);
570 right_val = new(Z) Value(char_code_right); 548 right_val = new (Z) Value(char_code_right);
571 } 549 }
572 550
573 // Comparing char-codes instead of strings. 551 // Comparing char-codes instead of strings.
574 EqualityCompareInstr* comp = 552 EqualityCompareInstr* comp =
575 new(Z) EqualityCompareInstr(call->token_pos(), 553 new (Z) EqualityCompareInstr(call->token_pos(), op_kind, left_val,
576 op_kind, 554 right_val, kSmiCid, call->deopt_id());
577 left_val,
578 right_val,
579 kSmiCid,
580 call->deopt_id());
581 ReplaceCall(call, comp); 555 ReplaceCall(call, comp);
582 556
583 // Remove dead instructions. 557 // Remove dead instructions.
584 if ((to_remove_left != NULL) && 558 if ((to_remove_left != NULL) &&
585 (to_remove_left->input_use_list() == NULL)) { 559 (to_remove_left->input_use_list() == NULL)) {
586 to_remove_left->ReplaceUsesWith(flow_graph()->constant_null()); 560 to_remove_left->ReplaceUsesWith(flow_graph()->constant_null());
587 to_remove_left->RemoveFromGraph(); 561 to_remove_left->RemoveFromGraph();
588 } 562 }
589 if ((to_remove_right != NULL) && 563 if ((to_remove_right != NULL) &&
590 (to_remove_right->input_use_list() == NULL)) { 564 (to_remove_right->input_use_list() == NULL)) {
591 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null()); 565 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null());
592 to_remove_right->RemoveFromGraph(); 566 to_remove_right->RemoveFromGraph();
593 } 567 }
594 return true; 568 return true;
595 } 569 }
596 return false; 570 return false;
597 } 571 }
598 572
599 573
600 static bool SmiFitsInDouble() { return kSmiBits < 53; } 574 static bool SmiFitsInDouble() {
575 return kSmiBits < 53;
576 }
601 577
602 bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, 578 bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
603 Token::Kind op_kind) { 579 Token::Kind op_kind) {
604 const ICData& ic_data = *call->ic_data(); 580 const ICData& ic_data = *call->ic_data();
605 ASSERT(ic_data.NumArgsTested() == 2); 581 ASSERT(ic_data.NumArgsTested() == 2);
606 582
607 ASSERT(call->ArgumentCount() == 2); 583 ASSERT(call->ArgumentCount() == 2);
608 Definition* left = call->ArgumentAt(0); 584 Definition* left = call->ArgumentAt(0);
609 Definition* right = call->ArgumentAt(1); 585 Definition* right = call->ArgumentAt(1);
610 586
611 intptr_t cid = kIllegalCid; 587 intptr_t cid = kIllegalCid;
612 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) { 588 if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
613 if (TryStringLengthOneEquality(call, op_kind)) { 589 if (TryStringLengthOneEquality(call, op_kind)) {
614 return true; 590 return true;
615 } else { 591 } else {
616 return false; 592 return false;
617 } 593 }
618 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) { 594 } else if (HasOnlyTwoOf(ic_data, kSmiCid)) {
619 InsertBefore(call, 595 InsertBefore(call,
620 new(Z) CheckSmiInstr(new(Z) Value(left), 596 new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(),
621 call->deopt_id(), 597 call->token_pos()),
622 call->token_pos()), 598 call->env(), FlowGraph::kEffect);
623 call->env(),
624 FlowGraph::kEffect);
625 InsertBefore(call, 599 InsertBefore(call,
626 new(Z) CheckSmiInstr(new(Z) Value(right), 600 new (Z) CheckSmiInstr(new (Z) Value(right), call->deopt_id(),
627 call->deopt_id(), 601 call->token_pos()),
628 call->token_pos()), 602 call->env(), FlowGraph::kEffect);
629 call->env(),
630 FlowGraph::kEffect);
631 cid = kSmiCid; 603 cid = kSmiCid;
632 } else if (HasTwoMintOrSmi(ic_data) && 604 } else if (HasTwoMintOrSmi(ic_data) &&
633 FlowGraphCompiler::SupportsUnboxedMints()) { 605 FlowGraphCompiler::SupportsUnboxedMints()) {
634 cid = kMintCid; 606 cid = kMintCid;
635 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { 607 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
636 // Use double comparison. 608 // Use double comparison.
637 if (SmiFitsInDouble()) { 609 if (SmiFitsInDouble()) {
638 cid = kDoubleCid; 610 cid = kDoubleCid;
639 } else { 611 } else {
640 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 612 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
641 // We cannot use double comparison on two smis. Need polymorphic 613 // We cannot use double comparison on two smis. Need polymorphic
642 // call. 614 // call.
643 return false; 615 return false;
644 } else { 616 } else {
645 InsertBefore(call, 617 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left),
646 new(Z) CheckEitherNonSmiInstr( 618 new (Z) Value(right),
647 new(Z) Value(left), 619 call->deopt_id()),
648 new(Z) Value(right), 620 call->env(), FlowGraph::kEffect);
649 call->deopt_id()),
650 call->env(),
651 FlowGraph::kEffect);
652 cid = kDoubleCid; 621 cid = kDoubleCid;
653 } 622 }
654 } 623 }
655 } else { 624 } else {
656 // Check if ICDData contains checks with Smi/Null combinations. In that case 625 // Check if ICDData contains checks with Smi/Null combinations. In that case
657 // we can still emit the optimized Smi equality operation but need to add 626 // we can still emit the optimized Smi equality operation but need to add
658 // checks for null or Smi. 627 // checks for null or Smi.
659 GrowableArray<intptr_t> smi_or_null(2); 628 GrowableArray<intptr_t> smi_or_null(2);
660 smi_or_null.Add(kSmiCid); 629 smi_or_null.Add(kSmiCid);
661 smi_or_null.Add(kNullCid); 630 smi_or_null.Add(kNullCid);
662 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, 631 if (ICDataHasOnlyReceiverArgumentClassIds(ic_data, smi_or_null,
663 smi_or_null,
664 smi_or_null)) { 632 smi_or_null)) {
665 const ICData& unary_checks_0 = 633 const ICData& unary_checks_0 =
666 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 634 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
667 AddCheckClass(left, 635 AddCheckClass(left, unary_checks_0, call->deopt_id(), call->env(), call);
668 unary_checks_0,
669 call->deopt_id(),
670 call->env(),
671 call);
672 636
673 const ICData& unary_checks_1 = 637 const ICData& unary_checks_1 =
674 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)); 638 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
675 AddCheckClass(right, 639 AddCheckClass(right, unary_checks_1, call->deopt_id(), call->env(), call);
676 unary_checks_1,
677 call->deopt_id(),
678 call->env(),
679 call);
680 cid = kSmiCid; 640 cid = kSmiCid;
681 } else { 641 } else {
682 // Shortcut for equality with null. 642 // Shortcut for equality with null.
683 ConstantInstr* right_const = right->AsConstant(); 643 ConstantInstr* right_const = right->AsConstant();
684 ConstantInstr* left_const = left->AsConstant(); 644 ConstantInstr* left_const = left->AsConstant();
685 if ((right_const != NULL && right_const->value().IsNull()) || 645 if ((right_const != NULL && right_const->value().IsNull()) ||
686 (left_const != NULL && left_const->value().IsNull())) { 646 (left_const != NULL && left_const->value().IsNull())) {
687 StrictCompareInstr* comp = 647 StrictCompareInstr* comp = new (Z)
688 new(Z) StrictCompareInstr(call->token_pos(), 648 StrictCompareInstr(call->token_pos(), Token::kEQ_STRICT,
689 Token::kEQ_STRICT, 649 new (Z) Value(left), new (Z) Value(right),
690 new(Z) Value(left), 650 false); // No number check.
691 new(Z) Value(right),
692 false); // No number check.
693 ReplaceCall(call, comp); 651 ReplaceCall(call, comp);
694 return true; 652 return true;
695 } 653 }
696 return false; 654 return false;
697 } 655 }
698 } 656 }
699 ASSERT(cid != kIllegalCid); 657 ASSERT(cid != kIllegalCid);
700 EqualityCompareInstr* comp = new(Z) EqualityCompareInstr(call->token_pos(), 658 EqualityCompareInstr* comp = new (Z)
701 op_kind, 659 EqualityCompareInstr(call->token_pos(), op_kind, new (Z) Value(left),
702 new(Z) Value(left), 660 new (Z) Value(right), cid, call->deopt_id());
703 new(Z) Value(right),
704 cid,
705 call->deopt_id());
706 ReplaceCall(call, comp); 661 ReplaceCall(call, comp);
707 return true; 662 return true;
708 } 663 }
709 664
710 665
711 bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, 666 bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
712 Token::Kind op_kind) { 667 Token::Kind op_kind) {
713 const ICData& ic_data = *call->ic_data(); 668 const ICData& ic_data = *call->ic_data();
714 ASSERT(ic_data.NumArgsTested() == 2); 669 ASSERT(ic_data.NumArgsTested() == 2);
715 670
716 ASSERT(call->ArgumentCount() == 2); 671 ASSERT(call->ArgumentCount() == 2);
717 Definition* left = call->ArgumentAt(0); 672 Definition* left = call->ArgumentAt(0);
718 Definition* right = call->ArgumentAt(1); 673 Definition* right = call->ArgumentAt(1);
719 674
720 intptr_t cid = kIllegalCid; 675 intptr_t cid = kIllegalCid;
721 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 676 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
722 InsertBefore(call, 677 InsertBefore(call,
723 new(Z) CheckSmiInstr(new(Z) Value(left), 678 new (Z) CheckSmiInstr(new (Z) Value(left), call->deopt_id(),
724 call->deopt_id(), 679 call->token_pos()),
725 call->token_pos()), 680 call->env(), FlowGraph::kEffect);
726 call->env(),
727 FlowGraph::kEffect);
728 InsertBefore(call, 681 InsertBefore(call,
729 new(Z) CheckSmiInstr(new(Z) Value(right), 682 new (Z) CheckSmiInstr(new (Z) Value(right), call->deopt_id(),
730 call->deopt_id(), 683 call->token_pos()),
731 call->token_pos()), 684 call->env(), FlowGraph::kEffect);
732 call->env(),
733 FlowGraph::kEffect);
734 cid = kSmiCid; 685 cid = kSmiCid;
735 } else if (HasTwoMintOrSmi(ic_data) && 686 } else if (HasTwoMintOrSmi(ic_data) &&
736 FlowGraphCompiler::SupportsUnboxedMints()) { 687 FlowGraphCompiler::SupportsUnboxedMints()) {
737 cid = kMintCid; 688 cid = kMintCid;
738 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { 689 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
739 // Use double comparison. 690 // Use double comparison.
740 if (SmiFitsInDouble()) { 691 if (SmiFitsInDouble()) {
741 cid = kDoubleCid; 692 cid = kDoubleCid;
742 } else { 693 } else {
743 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { 694 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
744 // We cannot use double comparison on two smis. Need polymorphic 695 // We cannot use double comparison on two smis. Need polymorphic
745 // call. 696 // call.
746 return false; 697 return false;
747 } else { 698 } else {
748 InsertBefore(call, 699 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left),
749 new(Z) CheckEitherNonSmiInstr( 700 new (Z) Value(right),
750 new(Z) Value(left), 701 call->deopt_id()),
751 new(Z) Value(right), 702 call->env(), FlowGraph::kEffect);
752 call->deopt_id()),
753 call->env(),
754 FlowGraph::kEffect);
755 cid = kDoubleCid; 703 cid = kDoubleCid;
756 } 704 }
757 } 705 }
758 } else { 706 } else {
759 return false; 707 return false;
760 } 708 }
761 ASSERT(cid != kIllegalCid); 709 ASSERT(cid != kIllegalCid);
762 RelationalOpInstr* comp = new(Z) RelationalOpInstr(call->token_pos(), 710 RelationalOpInstr* comp =
763 op_kind, 711 new (Z) RelationalOpInstr(call->token_pos(), op_kind, new (Z) Value(left),
764 new(Z) Value(left), 712 new (Z) Value(right), cid, call->deopt_id());
765 new(Z) Value(right),
766 cid,
767 call->deopt_id());
768 ReplaceCall(call, comp); 713 ReplaceCall(call, comp);
769 return true; 714 return true;
770 } 715 }
771 716
772 717
773 bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, 718 bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
774 Token::Kind op_kind) { 719 Token::Kind op_kind) {
775 intptr_t operands_type = kIllegalCid; 720 intptr_t operands_type = kIllegalCid;
776 ASSERT(call->HasICData()); 721 ASSERT(call->HasICData());
777 const ICData& ic_data = *call->ic_data(); 722 const ICData& ic_data = *call->ic_data();
778 switch (op_kind) { 723 switch (op_kind) {
779 case Token::kADD: 724 case Token::kADD:
780 case Token::kSUB: 725 case Token::kSUB:
781 case Token::kMUL: 726 case Token::kMUL:
782 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 727 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
783 // Don't generate smi code if the IC data is marked because 728 // Don't generate smi code if the IC data is marked because
784 // of an overflow. 729 // of an overflow.
785 operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp) 730 operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
786 ? kMintCid 731 ? kMintCid
787 : kSmiCid; 732 : kSmiCid;
788 } else if (HasTwoMintOrSmi(ic_data) && 733 } else if (HasTwoMintOrSmi(ic_data) &&
789 FlowGraphCompiler::SupportsUnboxedMints()) { 734 FlowGraphCompiler::SupportsUnboxedMints()) {
790 // Don't generate mint code if the IC data is marked because of an 735 // Don't generate mint code if the IC data is marked because of an
791 // overflow. 736 // overflow.
792 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) return false; 737 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) return false;
793 operands_type = kMintCid; 738 operands_type = kMintCid;
794 } else if (ShouldSpecializeForDouble(ic_data)) { 739 } else if (ShouldSpecializeForDouble(ic_data)) {
795 operands_type = kDoubleCid; 740 operands_type = kDoubleCid;
796 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) { 741 } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
797 operands_type = kFloat32x4Cid; 742 operands_type = kFloat32x4Cid;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
833 case Token::kSHR: 778 case Token::kSHR:
834 case Token::kSHL: 779 case Token::kSHL:
835 if (HasOnlyTwoOf(ic_data, kSmiCid)) { 780 if (HasOnlyTwoOf(ic_data, kSmiCid)) {
836 // Left shift may overflow from smi into mint or big ints. 781 // Left shift may overflow from smi into mint or big ints.
837 // Don't generate smi code if the IC data is marked because 782 // Don't generate smi code if the IC data is marked because
838 // of an overflow. 783 // of an overflow.
839 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) { 784 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
840 return false; 785 return false;
841 } 786 }
842 operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp) 787 operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
843 ? kMintCid 788 ? kMintCid
844 : kSmiCid; 789 : kSmiCid;
845 } else if (HasTwoMintOrSmi(ic_data) && 790 } else if (HasTwoMintOrSmi(ic_data) &&
846 HasOnlyOneSmi(ICData::Handle(Z, 791 HasOnlyOneSmi(ICData::Handle(
847 ic_data.AsUnaryClassChecksForArgNr(1)))) { 792 Z, ic_data.AsUnaryClassChecksForArgNr(1)))) {
848 // Don't generate mint code if the IC data is marked because of an 793 // Don't generate mint code if the IC data is marked because of an
849 // overflow. 794 // overflow.
850 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) { 795 if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
851 return false; 796 return false;
852 } 797 }
853 // Check for smi/mint << smi or smi/mint >> smi. 798 // Check for smi/mint << smi or smi/mint >> smi.
854 operands_type = kMintCid; 799 operands_type = kMintCid;
855 } else { 800 } else {
856 return false; 801 return false;
857 } 802 }
(...skipping 18 matching lines...) Expand all
876 Definition* left = call->ArgumentAt(0); 821 Definition* left = call->ArgumentAt(0);
877 Definition* right = call->ArgumentAt(1); 822 Definition* right = call->ArgumentAt(1);
878 if (operands_type == kDoubleCid) { 823 if (operands_type == kDoubleCid) {
879 if (!CanUnboxDouble()) { 824 if (!CanUnboxDouble()) {
880 return false; 825 return false;
881 } 826 }
882 // Check that either left or right are not a smi. Result of a 827 // Check that either left or right are not a smi. Result of a
883 // binary operation with two smis is a smi not a double, except '/' which 828 // binary operation with two smis is a smi not a double, except '/' which
884 // returns a double for two smis. 829 // returns a double for two smis.
885 if (op_kind != Token::kDIV) { 830 if (op_kind != Token::kDIV) {
886 InsertBefore(call, 831 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left),
887 new(Z) CheckEitherNonSmiInstr( 832 new (Z) Value(right),
888 new(Z) Value(left), 833 call->deopt_id()),
889 new(Z) Value(right), 834 call->env(), FlowGraph::kEffect);
890 call->deopt_id()),
891 call->env(),
892 FlowGraph::kEffect);
893 } 835 }
894 836
895 BinaryDoubleOpInstr* double_bin_op = 837 BinaryDoubleOpInstr* double_bin_op = new (Z)
896 new(Z) BinaryDoubleOpInstr(op_kind, 838 BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right),
897 new(Z) Value(left), 839 call->deopt_id(), call->token_pos());
898 new(Z) Value(right),
899 call->deopt_id(), call->token_pos());
900 ReplaceCall(call, double_bin_op); 840 ReplaceCall(call, double_bin_op);
901 } else if (operands_type == kMintCid) { 841 } else if (operands_type == kMintCid) {
902 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; 842 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false;
903 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { 843 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
904 ShiftMintOpInstr* shift_op = 844 ShiftMintOpInstr* shift_op = new (Z) ShiftMintOpInstr(
905 new(Z) ShiftMintOpInstr( 845 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
906 op_kind, new(Z) Value(left), new(Z) Value(right),
907 call->deopt_id());
908 ReplaceCall(call, shift_op); 846 ReplaceCall(call, shift_op);
909 } else { 847 } else {
910 BinaryMintOpInstr* bin_op = 848 BinaryMintOpInstr* bin_op = new (Z) BinaryMintOpInstr(
911 new(Z) BinaryMintOpInstr( 849 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
912 op_kind, new(Z) Value(left), new(Z) Value(right),
913 call->deopt_id());
914 ReplaceCall(call, bin_op); 850 ReplaceCall(call, bin_op);
915 } 851 }
916 } else if (operands_type == kFloat32x4Cid) { 852 } else if (operands_type == kFloat32x4Cid) {
917 return InlineFloat32x4BinaryOp(call, op_kind); 853 return InlineFloat32x4BinaryOp(call, op_kind);
918 } else if (operands_type == kInt32x4Cid) { 854 } else if (operands_type == kInt32x4Cid) {
919 return InlineInt32x4BinaryOp(call, op_kind); 855 return InlineInt32x4BinaryOp(call, op_kind);
920 } else if (operands_type == kFloat64x2Cid) { 856 } else if (operands_type == kFloat64x2Cid) {
921 return InlineFloat64x2BinaryOp(call, op_kind); 857 return InlineFloat64x2BinaryOp(call, op_kind);
922 } else if (op_kind == Token::kMOD) { 858 } else if (op_kind == Token::kMOD) {
923 ASSERT(operands_type == kSmiCid); 859 ASSERT(operands_type == kSmiCid);
924 if (right->IsConstant()) { 860 if (right->IsConstant()) {
925 const Object& obj = right->AsConstant()->value(); 861 const Object& obj = right->AsConstant()->value();
926 if (obj.IsSmi() && Utils::IsPowerOfTwo(Smi::Cast(obj).Value())) { 862 if (obj.IsSmi() && Utils::IsPowerOfTwo(Smi::Cast(obj).Value())) {
927 // Insert smi check and attach a copy of the original environment 863 // Insert smi check and attach a copy of the original environment
928 // because the smi operation can still deoptimize. 864 // because the smi operation can still deoptimize.
929 InsertBefore(call, 865 InsertBefore(call,
930 new(Z) CheckSmiInstr(new(Z) Value(left), 866 new (Z) CheckSmiInstr(new (Z) Value(left),
931 call->deopt_id(), 867 call->deopt_id(), call->token_pos()),
932 call->token_pos()), 868 call->env(), FlowGraph::kEffect);
933 call->env(), 869 ConstantInstr* constant = flow_graph()->GetConstant(
934 FlowGraph::kEffect); 870 Smi::Handle(Z, Smi::New(Smi::Cast(obj).Value() - 1)));
935 ConstantInstr* constant =
936 flow_graph()->GetConstant(Smi::Handle(Z,
937 Smi::New(Smi::Cast(obj).Value() - 1)));
938 BinarySmiOpInstr* bin_op = 871 BinarySmiOpInstr* bin_op =
939 new(Z) BinarySmiOpInstr(Token::kBIT_AND, 872 new (Z) BinarySmiOpInstr(Token::kBIT_AND, new (Z) Value(left),
940 new(Z) Value(left), 873 new (Z) Value(constant), call->deopt_id());
941 new(Z) Value(constant),
942 call->deopt_id());
943 ReplaceCall(call, bin_op); 874 ReplaceCall(call, bin_op);
944 return true; 875 return true;
945 } 876 }
946 } 877 }
947 // Insert two smi checks and attach a copy of the original 878 // Insert two smi checks and attach a copy of the original
948 // environment because the smi operation can still deoptimize. 879 // environment because the smi operation can still deoptimize.
949 AddCheckSmi(left, call->deopt_id(), call->env(), call); 880 AddCheckSmi(left, call->deopt_id(), call->env(), call);
950 AddCheckSmi(right, call->deopt_id(), call->env(), call); 881 AddCheckSmi(right, call->deopt_id(), call->env(), call);
951 BinarySmiOpInstr* bin_op = 882 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr(
952 new(Z) BinarySmiOpInstr(op_kind, 883 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
953 new(Z) Value(left),
954 new(Z) Value(right),
955 call->deopt_id());
956 ReplaceCall(call, bin_op); 884 ReplaceCall(call, bin_op);
957 } else { 885 } else {
958 ASSERT(operands_type == kSmiCid); 886 ASSERT(operands_type == kSmiCid);
959 // Insert two smi checks and attach a copy of the original 887 // Insert two smi checks and attach a copy of the original
960 // environment because the smi operation can still deoptimize. 888 // environment because the smi operation can still deoptimize.
961 AddCheckSmi(left, call->deopt_id(), call->env(), call); 889 AddCheckSmi(left, call->deopt_id(), call->env(), call);
962 AddCheckSmi(right, call->deopt_id(), call->env(), call); 890 AddCheckSmi(right, call->deopt_id(), call->env(), call);
963 if (left->IsConstant() && 891 if (left->IsConstant() &&
964 ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) { 892 ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) {
965 // Constant should be on the right side. 893 // Constant should be on the right side.
966 Definition* temp = left; 894 Definition* temp = left;
967 left = right; 895 left = right;
968 right = temp; 896 right = temp;
969 } 897 }
970 BinarySmiOpInstr* bin_op = 898 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr(
971 new(Z) BinarySmiOpInstr( 899 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
972 op_kind,
973 new(Z) Value(left),
974 new(Z) Value(right),
975 call->deopt_id());
976 ReplaceCall(call, bin_op); 900 ReplaceCall(call, bin_op);
977 } 901 }
978 return true; 902 return true;
979 } 903 }
980 904
981 905
982 bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, 906 bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
983 Token::Kind op_kind) { 907 Token::Kind op_kind) {
984 ASSERT(call->ArgumentCount() == 1); 908 ASSERT(call->ArgumentCount() == 1);
985 Definition* input = call->ArgumentAt(0); 909 Definition* input = call->ArgumentAt(0);
986 Definition* unary_op = NULL; 910 Definition* unary_op = NULL;
987 if (HasOnlyOneSmi(*call->ic_data())) { 911 if (HasOnlyOneSmi(*call->ic_data())) {
988 InsertBefore(call, 912 InsertBefore(call,
989 new(Z) CheckSmiInstr(new(Z) Value(input), 913 new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(),
990 call->deopt_id(), 914 call->token_pos()),
991 call->token_pos()), 915 call->env(), FlowGraph::kEffect);
992 call->env(), 916 unary_op = new (Z)
993 FlowGraph::kEffect); 917 UnarySmiOpInstr(op_kind, new (Z) Value(input), call->deopt_id());
994 unary_op = new(Z) UnarySmiOpInstr(
995 op_kind, new(Z) Value(input), call->deopt_id());
996 } else if ((op_kind == Token::kBIT_NOT) && 918 } else if ((op_kind == Token::kBIT_NOT) &&
997 HasOnlySmiOrMint(*call->ic_data()) && 919 HasOnlySmiOrMint(*call->ic_data()) &&
998 FlowGraphCompiler::SupportsUnboxedMints()) { 920 FlowGraphCompiler::SupportsUnboxedMints()) {
999 unary_op = new(Z) UnaryMintOpInstr( 921 unary_op = new (Z)
1000 op_kind, new(Z) Value(input), call->deopt_id()); 922 UnaryMintOpInstr(op_kind, new (Z) Value(input), call->deopt_id());
1001 } else if (HasOnlyOneDouble(*call->ic_data()) && 923 } else if (HasOnlyOneDouble(*call->ic_data()) &&
1002 (op_kind == Token::kNEGATE) && 924 (op_kind == Token::kNEGATE) && CanUnboxDouble()) {
1003 CanUnboxDouble()) {
1004 AddReceiverCheck(call); 925 AddReceiverCheck(call);
1005 unary_op = new(Z) UnaryDoubleOpInstr( 926 unary_op = new (Z) UnaryDoubleOpInstr(Token::kNEGATE, new (Z) Value(input),
1006 Token::kNEGATE, new(Z) Value(input), call->deopt_id()); 927 call->deopt_id());
1007 } else { 928 } else {
1008 return false; 929 return false;
1009 } 930 }
1010 ASSERT(unary_op != NULL); 931 ASSERT(unary_op != NULL);
1011 ReplaceCall(call, unary_op); 932 ReplaceCall(call, unary_op);
1012 return true; 933 return true;
1013 } 934 }
1014 935
1015 936
1016 // Using field class. 937 // Using field class.
1017 RawField* JitOptimizer::GetField(intptr_t class_id, 938 RawField* JitOptimizer::GetField(intptr_t class_id, const String& field_name) {
1018 const String& field_name) {
1019 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); 939 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
1020 Field& field = Field::Handle(Z); 940 Field& field = Field::Handle(Z);
1021 while (!cls.IsNull()) { 941 while (!cls.IsNull()) {
1022 field = cls.LookupInstanceField(field_name); 942 field = cls.LookupInstanceField(field_name);
1023 if (!field.IsNull()) { 943 if (!field.IsNull()) {
1024 if (Compiler::IsBackgroundCompilation() || 944 if (Compiler::IsBackgroundCompilation() ||
1025 FLAG_force_clone_compiler_objects) { 945 FLAG_force_clone_compiler_objects) {
1026 return field.CloneFromOriginal(); 946 return field.CloneFromOriginal();
1027 } else { 947 } else {
1028 return field.raw(); 948 return field.raw();
1029 } 949 }
1030 } 950 }
1031 cls = cls.SuperClass(); 951 cls = cls.SuperClass();
1032 } 952 }
1033 return Field::null(); 953 return Field::null();
1034 } 954 }
1035 955
1036 956
1037 bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { 957 bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
1038 ASSERT(call->HasICData()); 958 ASSERT(call->HasICData());
1039 const ICData& ic_data = *call->ic_data(); 959 const ICData& ic_data = *call->ic_data();
1040 ASSERT(ic_data.HasOneTarget()); 960 ASSERT(ic_data.HasOneTarget());
1041 GrowableArray<intptr_t> class_ids; 961 GrowableArray<intptr_t> class_ids;
1042 ic_data.GetClassIdsAt(0, &class_ids); 962 ic_data.GetClassIdsAt(0, &class_ids);
1043 ASSERT(class_ids.length() == 1); 963 ASSERT(class_ids.length() == 1);
1044 // Inline implicit instance getter. 964 // Inline implicit instance getter.
1045 const String& field_name = 965 const String& field_name =
1046 String::Handle(Z, Field::NameFromGetter(call->function_name())); 966 String::Handle(Z, Field::NameFromGetter(call->function_name()));
1047 const Field& field = 967 const Field& field = Field::ZoneHandle(Z, GetField(class_ids[0], field_name));
1048 Field::ZoneHandle(Z, GetField(class_ids[0], field_name));
1049 ASSERT(!field.IsNull()); 968 ASSERT(!field.IsNull());
1050 969
1051 if (flow_graph()->InstanceCallNeedsClassCheck( 970 if (flow_graph()->InstanceCallNeedsClassCheck(call,
1052 call, RawFunction::kImplicitGetter)) { 971 RawFunction::kImplicitGetter)) {
1053 AddReceiverCheck(call); 972 AddReceiverCheck(call);
1054 } 973 }
1055 LoadFieldInstr* load = new(Z) LoadFieldInstr( 974 LoadFieldInstr* load = new (Z) LoadFieldInstr(
1056 new(Z) Value(call->ArgumentAt(0)), 975 new (Z) Value(call->ArgumentAt(0)), &field,
1057 &field, 976 AbstractType::ZoneHandle(Z, field.type()), call->token_pos());
1058 AbstractType::ZoneHandle(Z, field.type()),
1059 call->token_pos());
1060 load->set_is_immutable(field.is_final()); 977 load->set_is_immutable(field.is_final());
1061 if (field.guarded_cid() != kIllegalCid) { 978 if (field.guarded_cid() != kIllegalCid) {
1062 if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) { 979 if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) {
1063 load->set_result_cid(field.guarded_cid()); 980 load->set_result_cid(field.guarded_cid());
1064 } 981 }
1065 flow_graph()->parsed_function().AddToGuardedFields(&field); 982 flow_graph()->parsed_function().AddToGuardedFields(&field);
1066 } 983 }
1067 984
1068 // Discard the environment from the original instruction because the load 985 // Discard the environment from the original instruction because the load
1069 // can't deoptimize. 986 // can't deoptimize.
1070 call->RemoveEnvironment(); 987 call->RemoveEnvironment();
1071 ReplaceCall(call, load); 988 ReplaceCall(call, load);
1072 989
1073 if (load->result_cid() != kDynamicCid) { 990 if (load->result_cid() != kDynamicCid) {
1074 // Reset value types if guarded_cid was used. 991 // Reset value types if guarded_cid was used.
1075 for (Value::Iterator it(load->input_use_list()); 992 for (Value::Iterator it(load->input_use_list()); !it.Done(); it.Advance()) {
1076 !it.Done();
1077 it.Advance()) {
1078 it.Current()->SetReachingType(NULL); 993 it.Current()->SetReachingType(NULL);
1079 } 994 }
1080 } 995 }
1081 return true; 996 return true;
1082 } 997 }
1083 998
1084 999
1085 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, 1000 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
1086 Token::Kind op_kind) { 1001 Token::Kind op_kind) {
1087 if (!ShouldInlineSimd()) { 1002 if (!ShouldInlineSimd()) {
1088 return false; 1003 return false;
1089 } 1004 }
1090 ASSERT(call->ArgumentCount() == 2); 1005 ASSERT(call->ArgumentCount() == 2);
1091 Definition* left = call->ArgumentAt(0); 1006 Definition* left = call->ArgumentAt(0);
1092 Definition* right = call->ArgumentAt(1); 1007 Definition* right = call->ArgumentAt(1);
1093 // Type check left. 1008 // Type check left.
1094 AddCheckClass(left, 1009 AddCheckClass(left, ICData::ZoneHandle(
1095 ICData::ZoneHandle( 1010 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1096 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1011 call->deopt_id(), call->env(), call);
1097 call->deopt_id(),
1098 call->env(),
1099 call);
1100 // Type check right. 1012 // Type check right.
1101 AddCheckClass(right, 1013 AddCheckClass(right, ICData::ZoneHandle(
1102 ICData::ZoneHandle( 1014 Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)),
1103 Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)), 1015 call->deopt_id(), call->env(), call);
1104 call->deopt_id(),
1105 call->env(),
1106 call);
1107 // Replace call. 1016 // Replace call.
1108 BinaryFloat32x4OpInstr* float32x4_bin_op = 1017 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr(
1109 new(Z) BinaryFloat32x4OpInstr( 1018 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1110 op_kind, new(Z) Value(left), new(Z) Value(right),
1111 call->deopt_id());
1112 ReplaceCall(call, float32x4_bin_op); 1019 ReplaceCall(call, float32x4_bin_op);
1113 1020
1114 return true; 1021 return true;
1115 } 1022 }
1116 1023
1117 1024
1118 bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, 1025 bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
1119 Token::Kind op_kind) { 1026 Token::Kind op_kind) {
1120 if (!ShouldInlineSimd()) { 1027 if (!ShouldInlineSimd()) {
1121 return false; 1028 return false;
1122 } 1029 }
1123 ASSERT(call->ArgumentCount() == 2); 1030 ASSERT(call->ArgumentCount() == 2);
1124 Definition* left = call->ArgumentAt(0); 1031 Definition* left = call->ArgumentAt(0);
1125 Definition* right = call->ArgumentAt(1); 1032 Definition* right = call->ArgumentAt(1);
1126 // Type check left. 1033 // Type check left.
1127 AddCheckClass(left, 1034 AddCheckClass(left, ICData::ZoneHandle(
1128 ICData::ZoneHandle( 1035 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1129 Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1036 call->deopt_id(), call->env(), call);
1130 call->deopt_id(),
1131 call->env(),
1132 call);
1133 // Type check right. 1037 // Type check right.
1134 AddCheckClass(right, 1038 AddCheckClass(right, ICData::ZoneHandle(
1135 ICData::ZoneHandle(Z, 1039 Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)),
1136 call->ic_data()->AsUnaryClassChecksForArgNr(1)), 1040 call->deopt_id(), call->env(), call);
1137 call->deopt_id(),
1138 call->env(),
1139 call);
1140 // Replace call. 1041 // Replace call.
1141 BinaryInt32x4OpInstr* int32x4_bin_op = 1042 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr(
1142 new(Z) BinaryInt32x4OpInstr( 1043 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1143 op_kind, new(Z) Value(left), new(Z) Value(right),
1144 call->deopt_id());
1145 ReplaceCall(call, int32x4_bin_op); 1044 ReplaceCall(call, int32x4_bin_op);
1146 return true; 1045 return true;
1147 } 1046 }
1148 1047
1149 1048
1150 bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, 1049 bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
1151 Token::Kind op_kind) { 1050 Token::Kind op_kind) {
1152 if (!ShouldInlineSimd()) { 1051 if (!ShouldInlineSimd()) {
1153 return false; 1052 return false;
1154 } 1053 }
1155 ASSERT(call->ArgumentCount() == 2); 1054 ASSERT(call->ArgumentCount() == 2);
1156 Definition* left = call->ArgumentAt(0); 1055 Definition* left = call->ArgumentAt(0);
1157 Definition* right = call->ArgumentAt(1); 1056 Definition* right = call->ArgumentAt(1);
1158 // Type check left. 1057 // Type check left.
1159 AddCheckClass(left, 1058 AddCheckClass(
1160 ICData::ZoneHandle( 1059 left, ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(0)),
1161 call->ic_data()->AsUnaryClassChecksForArgNr(0)), 1060 call->deopt_id(), call->env(), call);
1162 call->deopt_id(),
1163 call->env(),
1164 call);
1165 // Type check right. 1061 // Type check right.
1166 AddCheckClass(right, 1062 AddCheckClass(
1167 ICData::ZoneHandle( 1063 right, ICData::ZoneHandle(call->ic_data()->AsUnaryClassChecksForArgNr(1)),
1168 call->ic_data()->AsUnaryClassChecksForArgNr(1)), 1064 call->deopt_id(), call->env(), call);
1169 call->deopt_id(),
1170 call->env(),
1171 call);
1172 // Replace call. 1065 // Replace call.
1173 BinaryFloat64x2OpInstr* float64x2_bin_op = 1066 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr(
1174 new(Z) BinaryFloat64x2OpInstr( 1067 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id());
1175 op_kind, new(Z) Value(left), new(Z) Value(right),
1176 call->deopt_id());
1177 ReplaceCall(call, float64x2_bin_op); 1068 ReplaceCall(call, float64x2_bin_op);
1178 return true; 1069 return true;
1179 } 1070 }
1180 1071
1181 1072
1182 // Only unique implicit instance getters can be currently handled. 1073 // Only unique implicit instance getters can be currently handled.
1183 bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { 1074 bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
1184 ASSERT(call->HasICData()); 1075 ASSERT(call->HasICData());
1185 const ICData& ic_data = *call->ic_data(); 1076 const ICData& ic_data = *call->ic_data();
1186 if (ic_data.NumberOfUsedChecks() == 0) { 1077 if (ic_data.NumberOfUsedChecks() == 0) {
(...skipping 15 matching lines...) Expand all
1202 } 1093 }
1203 return InlineImplicitInstanceGetter(call); 1094 return InlineImplicitInstanceGetter(call);
1204 } 1095 }
1205 1096
1206 1097
1207 void JitOptimizer::ReplaceWithMathCFunction( 1098 void JitOptimizer::ReplaceWithMathCFunction(
1208 InstanceCallInstr* call, 1099 InstanceCallInstr* call,
1209 MethodRecognizer::Kind recognized_kind) { 1100 MethodRecognizer::Kind recognized_kind) {
1210 AddReceiverCheck(call); 1101 AddReceiverCheck(call);
1211 ZoneGrowableArray<Value*>* args = 1102 ZoneGrowableArray<Value*>* args =
1212 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); 1103 new (Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
1213 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { 1104 for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
1214 args->Add(new(Z) Value(call->ArgumentAt(i))); 1105 args->Add(new (Z) Value(call->ArgumentAt(i)));
1215 } 1106 }
1216 InvokeMathCFunctionInstr* invoke = 1107 InvokeMathCFunctionInstr* invoke = new (Z) InvokeMathCFunctionInstr(
1217 new(Z) InvokeMathCFunctionInstr(args, 1108 args, call->deopt_id(), recognized_kind, call->token_pos());
1218 call->deopt_id(),
1219 recognized_kind,
1220 call->token_pos());
1221 ReplaceCall(call, invoke); 1109 ReplaceCall(call, invoke);
1222 } 1110 }
1223 1111
1224 1112
1225 // Inline only simple, frequently called core library methods. 1113 // Inline only simple, frequently called core library methods.
1226 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { 1114 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
1227 ASSERT(call->HasICData()); 1115 ASSERT(call->HasICData());
1228 const ICData& ic_data = *call->ic_data(); 1116 const ICData& ic_data = *call->ic_data();
1229 if (ic_data.NumberOfUsedChecks() != 1) { 1117 if (ic_data.NumberOfUsedChecks() != 1) {
1230 // No type feedback collected or multiple targets found. 1118 // No type feedback collected or multiple targets found.
1231 return false; 1119 return false;
1232 } 1120 }
1233 1121
1234 Function& target = Function::Handle(Z); 1122 Function& target = Function::Handle(Z);
1235 GrowableArray<intptr_t> class_ids; 1123 GrowableArray<intptr_t> class_ids;
1236 ic_data.GetCheckAt(0, &class_ids, &target); 1124 ic_data.GetCheckAt(0, &class_ids, &target);
1237 MethodRecognizer::Kind recognized_kind = 1125 MethodRecognizer::Kind recognized_kind =
1238 MethodRecognizer::RecognizeKind(target); 1126 MethodRecognizer::RecognizeKind(target);
1239 1127
1240 if (CanUnboxDouble() && 1128 if (CanUnboxDouble() &&
1241 (recognized_kind == MethodRecognizer::kIntegerToDouble)) { 1129 (recognized_kind == MethodRecognizer::kIntegerToDouble)) {
1242 if (class_ids[0] == kSmiCid) { 1130 if (class_ids[0] == kSmiCid) {
1243 AddReceiverCheck(call); 1131 AddReceiverCheck(call);
1244 ReplaceCall(call, 1132 ReplaceCall(call,
1245 new(Z) SmiToDoubleInstr( 1133 new (Z) SmiToDoubleInstr(new (Z) Value(call->ArgumentAt(0)),
1246 new(Z) Value(call->ArgumentAt(0)), 1134 call->token_pos()));
1247 call->token_pos()));
1248 return true; 1135 return true;
1249 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) { 1136 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) {
1250 AddReceiverCheck(call); 1137 AddReceiverCheck(call);
1251 ReplaceCall(call, 1138 ReplaceCall(call,
1252 new(Z) MintToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), 1139 new (Z) MintToDoubleInstr(new (Z) Value(call->ArgumentAt(0)),
1253 call->deopt_id())); 1140 call->deopt_id()));
1254 return true; 1141 return true;
1255 } 1142 }
1256 } 1143 }
1257 1144
1258 if (class_ids[0] == kDoubleCid) { 1145 if (class_ids[0] == kDoubleCid) {
1259 if (!CanUnboxDouble()) { 1146 if (!CanUnboxDouble()) {
1260 return false; 1147 return false;
1261 } 1148 }
1262 switch (recognized_kind) { 1149 switch (recognized_kind) {
1263 case MethodRecognizer::kDoubleToInteger: { 1150 case MethodRecognizer::kDoubleToInteger: {
1264 AddReceiverCheck(call); 1151 AddReceiverCheck(call);
1265 ASSERT(call->HasICData()); 1152 ASSERT(call->HasICData());
1266 const ICData& ic_data = *call->ic_data(); 1153 const ICData& ic_data = *call->ic_data();
1267 Definition* input = call->ArgumentAt(0); 1154 Definition* input = call->ArgumentAt(0);
1268 Definition* d2i_instr = NULL; 1155 Definition* d2i_instr = NULL;
1269 if (ic_data.HasDeoptReason(ICData::kDeoptDoubleToSmi)) { 1156 if (ic_data.HasDeoptReason(ICData::kDeoptDoubleToSmi)) {
1270 // Do not repeatedly deoptimize because result didn't fit into Smi. 1157 // Do not repeatedly deoptimize because result didn't fit into Smi.
1271 d2i_instr = new(Z) DoubleToIntegerInstr( 1158 d2i_instr = new (Z) DoubleToIntegerInstr(new (Z) Value(input), call);
1272 new(Z) Value(input), call);
1273 } else { 1159 } else {
1274 // Optimistically assume result fits into Smi. 1160 // Optimistically assume result fits into Smi.
1275 d2i_instr = new(Z) DoubleToSmiInstr( 1161 d2i_instr =
1276 new(Z) Value(input), call->deopt_id()); 1162 new (Z) DoubleToSmiInstr(new (Z) Value(input), call->deopt_id());
1277 } 1163 }
1278 ReplaceCall(call, d2i_instr); 1164 ReplaceCall(call, d2i_instr);
1279 return true; 1165 return true;
1280 } 1166 }
1281 case MethodRecognizer::kDoubleMod: 1167 case MethodRecognizer::kDoubleMod:
1282 case MethodRecognizer::kDoubleRound: 1168 case MethodRecognizer::kDoubleRound:
1283 ReplaceWithMathCFunction(call, recognized_kind); 1169 ReplaceWithMathCFunction(call, recognized_kind);
1284 return true; 1170 return true;
1285 case MethodRecognizer::kDoubleTruncate: 1171 case MethodRecognizer::kDoubleTruncate:
1286 case MethodRecognizer::kDoubleFloor: 1172 case MethodRecognizer::kDoubleFloor:
1287 case MethodRecognizer::kDoubleCeil: 1173 case MethodRecognizer::kDoubleCeil:
1288 if (!TargetCPUFeatures::double_truncate_round_supported()) { 1174 if (!TargetCPUFeatures::double_truncate_round_supported()) {
1289 ReplaceWithMathCFunction(call, recognized_kind); 1175 ReplaceWithMathCFunction(call, recognized_kind);
1290 } else { 1176 } else {
1291 AddReceiverCheck(call); 1177 AddReceiverCheck(call);
1292 DoubleToDoubleInstr* d2d_instr = 1178 DoubleToDoubleInstr* d2d_instr =
1293 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), 1179 new (Z) DoubleToDoubleInstr(new (Z) Value(call->ArgumentAt(0)),
1294 recognized_kind, call->deopt_id()); 1180 recognized_kind, call->deopt_id());
1295 ReplaceCall(call, d2d_instr); 1181 ReplaceCall(call, d2d_instr);
1296 } 1182 }
1297 return true; 1183 return true;
1298 default: 1184 default:
1299 break; 1185 break;
1300 } 1186 }
1301 } 1187 }
1302 1188
1303 return FlowGraphInliner::TryReplaceInstanceCallWithInline( 1189 return FlowGraphInliner::TryReplaceInstanceCallWithInline(
1304 flow_graph_, current_iterator(), call); 1190 flow_graph_, current_iterator(), call);
(...skipping 19 matching lines...) Expand all
1324 const Class& type_class = Class::Handle(Z, type.type_class()); 1210 const Class& type_class = Class::Handle(Z, type.type_class());
1325 const intptr_t num_type_args = type_class.NumTypeArguments(); 1211 const intptr_t num_type_args = type_class.NumTypeArguments();
1326 if (num_type_args > 0) { 1212 if (num_type_args > 0) {
1327 // Only raw types can be directly compared, thus disregarding type 1213 // Only raw types can be directly compared, thus disregarding type
1328 // arguments. 1214 // arguments.
1329 const intptr_t num_type_params = type_class.NumTypeParameters(); 1215 const intptr_t num_type_params = type_class.NumTypeParameters();
1330 const intptr_t from_index = num_type_args - num_type_params; 1216 const intptr_t from_index = num_type_args - num_type_params;
1331 const TypeArguments& type_arguments = 1217 const TypeArguments& type_arguments =
1332 TypeArguments::Handle(Z, type.arguments()); 1218 TypeArguments::Handle(Z, type.arguments());
1333 const bool is_raw_type = type_arguments.IsNull() || 1219 const bool is_raw_type = type_arguments.IsNull() ||
1334 type_arguments.IsRaw(from_index, num_type_params); 1220 type_arguments.IsRaw(from_index, num_type_params);
1335 if (!is_raw_type) { 1221 if (!is_raw_type) {
1336 // Unknown result. 1222 // Unknown result.
1337 return Bool::null(); 1223 return Bool::null();
1338 } 1224 }
1339 } 1225 }
1340 1226
1341 const ClassTable& class_table = *isolate()->class_table(); 1227 const ClassTable& class_table = *isolate()->class_table();
1342 Bool& prev = Bool::Handle(Z); 1228 Bool& prev = Bool::Handle(Z);
1343 Class& cls = Class::Handle(Z); 1229 Class& cls = Class::Handle(Z);
1344 1230
1345 bool results_differ = false; 1231 bool results_differ = false;
1346 for (int i = 0; i < ic_data.NumberOfChecks(); i++) { 1232 for (int i = 0; i < ic_data.NumberOfChecks(); i++) {
1347 cls = class_table.At(ic_data.GetReceiverClassIdAt(i)); 1233 cls = class_table.At(ic_data.GetReceiverClassIdAt(i));
1348 if (cls.NumTypeArguments() > 0) { 1234 if (cls.NumTypeArguments() > 0) {
1349 return Bool::null(); 1235 return Bool::null();
1350 } 1236 }
1351 const bool is_subtype = cls.IsSubtypeOf( 1237 const bool is_subtype =
1352 TypeArguments::Handle(Z), 1238 cls.IsSubtypeOf(TypeArguments::Handle(Z), type_class,
1353 type_class, 1239 TypeArguments::Handle(Z), NULL, NULL, Heap::kOld);
1354 TypeArguments::Handle(Z),
1355 NULL,
1356 NULL,
1357 Heap::kOld);
1358 results->Add(cls.id()); 1240 results->Add(cls.id());
1359 results->Add(is_subtype); 1241 results->Add(is_subtype);
1360 if (prev.IsNull()) { 1242 if (prev.IsNull()) {
1361 prev = Bool::Get(is_subtype).raw(); 1243 prev = Bool::Get(is_subtype).raw();
1362 } else { 1244 } else {
1363 if (is_subtype != prev.value()) { 1245 if (is_subtype != prev.value()) {
1364 results_differ = true; 1246 results_differ = true;
1365 } 1247 }
1366 } 1248 }
1367 } 1249 }
1368 return results_differ ? Bool::null() : prev.raw(); 1250 return results_differ ? Bool::null() : prev.raw();
1369 } 1251 }
1370 1252
1371 1253
1372 // Returns true if checking against this type is a direct class id comparison. 1254 // Returns true if checking against this type is a direct class id comparison.
1373 bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { 1255 bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
1374 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); 1256 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
1375 // Requires CHA. 1257 // Requires CHA.
1376 if (!type.IsInstantiated()) return false; 1258 if (!type.IsInstantiated()) return false;
1377 // Function types have different type checking rules. 1259 // Function types have different type checking rules.
1378 if (type.IsFunctionType()) return false; 1260 if (type.IsFunctionType()) return false;
1379 const Class& type_class = Class::Handle(type.type_class()); 1261 const Class& type_class = Class::Handle(type.type_class());
1380 // Could be an interface check? 1262 // Could be an interface check?
1381 if (CHA::IsImplemented(type_class)) return false; 1263 if (CHA::IsImplemented(type_class)) return false;
1382 // Check if there are subclasses. 1264 // Check if there are subclasses.
1383 if (CHA::HasSubclasses(type_class)) { 1265 if (CHA::HasSubclasses(type_class)) {
1384 return false; 1266 return false;
1385 } 1267 }
1386 1268
1387 // Private classes cannot be subclassed by later loaded libs. 1269 // Private classes cannot be subclassed by later loaded libs.
1388 if (!type_class.IsPrivate()) { 1270 if (!type_class.IsPrivate()) {
1389 if (FLAG_use_cha_deopt || isolate()->all_classes_finalized()) { 1271 if (FLAG_use_cha_deopt || isolate()->all_classes_finalized()) {
1390 if (FLAG_trace_cha) { 1272 if (FLAG_trace_cha) {
1391 THR_Print(" **(CHA) Typecheck as class equality since no " 1273 THR_Print(
1274 " **(CHA) Typecheck as class equality since no "
1392 "subclasses: %s\n", 1275 "subclasses: %s\n",
1393 type_class.ToCString()); 1276 type_class.ToCString());
1394 } 1277 }
1395 if (FLAG_use_cha_deopt) { 1278 if (FLAG_use_cha_deopt) {
1396 thread()->cha()->AddToGuardedClasses(type_class, /*subclass_count=*/0); 1279 thread()->cha()->AddToGuardedClasses(type_class, /*subclass_count=*/0);
1397 } 1280 }
1398 } else { 1281 } else {
1399 return false; 1282 return false;
1400 } 1283 }
1401 } 1284 }
1402 const intptr_t num_type_args = type_class.NumTypeArguments(); 1285 const intptr_t num_type_args = type_class.NumTypeArguments();
1403 if (num_type_args > 0) { 1286 if (num_type_args > 0) {
1404 // Only raw types can be directly compared, thus disregarding type 1287 // Only raw types can be directly compared, thus disregarding type
1405 // arguments. 1288 // arguments.
1406 const intptr_t num_type_params = type_class.NumTypeParameters(); 1289 const intptr_t num_type_params = type_class.NumTypeParameters();
1407 const intptr_t from_index = num_type_args - num_type_params; 1290 const intptr_t from_index = num_type_args - num_type_params;
1408 const TypeArguments& type_arguments = 1291 const TypeArguments& type_arguments =
1409 TypeArguments::Handle(type.arguments()); 1292 TypeArguments::Handle(type.arguments());
1410 const bool is_raw_type = type_arguments.IsNull() || 1293 const bool is_raw_type = type_arguments.IsNull() ||
1411 type_arguments.IsRaw(from_index, num_type_params); 1294 type_arguments.IsRaw(from_index, num_type_params);
1412 return is_raw_type; 1295 return is_raw_type;
1413 } 1296 }
1414 return true; 1297 return true;
1415 } 1298 }
1416 1299
1417 1300
1418 static bool CidTestResultsContains(const ZoneGrowableArray<intptr_t>& results, 1301 static bool CidTestResultsContains(const ZoneGrowableArray<intptr_t>& results,
1419 intptr_t test_cid) { 1302 intptr_t test_cid) {
1420 for (intptr_t i = 0; i < results.length(); i += 2) { 1303 for (intptr_t i = 0; i < results.length(); i += 2) {
1421 if (results[i] == test_cid) return true; 1304 if (results[i] == test_cid) return true;
(...skipping 15 matching lines...) Expand all
1437 // Tries to add cid tests to 'results' so that no deoptimization is 1320 // Tries to add cid tests to 'results' so that no deoptimization is
1438 // necessary. 1321 // necessary.
1439 // TODO(srdjan): Do also for other than 'int' type. 1322 // TODO(srdjan): Do also for other than 'int' type.
1440 static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results, 1323 static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results,
1441 const AbstractType& type) { 1324 const AbstractType& type) {
1442 ASSERT(results->length() >= 2); // At least on eentry. 1325 ASSERT(results->length() >= 2); // At least on eentry.
1443 const ClassTable& class_table = *Isolate::Current()->class_table(); 1326 const ClassTable& class_table = *Isolate::Current()->class_table();
1444 if ((*results)[0] != kSmiCid) { 1327 if ((*results)[0] != kSmiCid) {
1445 const Class& cls = Class::Handle(class_table.At(kSmiCid)); 1328 const Class& cls = Class::Handle(class_table.At(kSmiCid));
1446 const Class& type_class = Class::Handle(type.type_class()); 1329 const Class& type_class = Class::Handle(type.type_class());
1447 const bool smi_is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(), 1330 const bool smi_is_subtype =
1448 type_class, 1331 cls.IsSubtypeOf(TypeArguments::Handle(), type_class,
1449 TypeArguments::Handle(), 1332 TypeArguments::Handle(), NULL, NULL, Heap::kOld);
1450 NULL,
1451 NULL,
1452 Heap::kOld);
1453 results->Add((*results)[results->length() - 2]); 1333 results->Add((*results)[results->length() - 2]);
1454 results->Add((*results)[results->length() - 2]); 1334 results->Add((*results)[results->length() - 2]);
1455 for (intptr_t i = results->length() - 3; i > 1; --i) { 1335 for (intptr_t i = results->length() - 3; i > 1; --i) {
1456 (*results)[i] = (*results)[i - 2]; 1336 (*results)[i] = (*results)[i - 2];
1457 } 1337 }
1458 (*results)[0] = kSmiCid; 1338 (*results)[0] = kSmiCid;
1459 (*results)[1] = smi_is_subtype; 1339 (*results)[1] = smi_is_subtype;
1460 } 1340 }
1461 1341
1462 ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded()); 1342 ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded());
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1499 type = Type::IntType(); 1379 type = Type::IntType();
1500 } else if (matches_core(call, Symbols::_instanceOfSmi())) { 1380 } else if (matches_core(call, Symbols::_instanceOfSmi())) {
1501 type = Type::SmiType(); 1381 type = Type::SmiType();
1502 } else if (matches_core(call, Symbols::_instanceOfDouble())) { 1382 } else if (matches_core(call, Symbols::_instanceOfDouble())) {
1503 type = Type::Double(); 1383 type = Type::Double();
1504 } else if (matches_core(call, Symbols::_instanceOfString())) { 1384 } else if (matches_core(call, Symbols::_instanceOfString())) {
1505 type = Type::StringType(); 1385 type = Type::StringType();
1506 } else { 1386 } else {
1507 UNIMPLEMENTED(); 1387 UNIMPLEMENTED();
1508 } 1388 }
1509 negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition() 1389 negate =
1510 ->AsConstant()->value()).value(); 1390 Bool::Cast(
1391 call->ArgumentAt(1)->OriginalDefinition()->AsConstant()->value())
1392 .value();
1511 } 1393 }
1512 } else { 1394 } else {
1513 type_args = call->ArgumentAt(1); 1395 type_args = call->ArgumentAt(1);
1514 type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw(); 1396 type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw();
1515 negate = Bool::Cast(call->ArgumentAt(3)->OriginalDefinition() 1397 negate =
1516 ->AsConstant()->value()).value(); 1398 Bool::Cast(
1399 call->ArgumentAt(3)->OriginalDefinition()->AsConstant()->value())
1400 .value();
1517 } 1401 }
1518 const ICData& unary_checks = 1402 const ICData& unary_checks =
1519 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 1403 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
1520 if ((unary_checks.NumberOfChecks() > 0) && 1404 if ((unary_checks.NumberOfChecks() > 0) &&
1521 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { 1405 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
1522 ZoneGrowableArray<intptr_t>* results = 1406 ZoneGrowableArray<intptr_t>* results =
1523 new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); 1407 new (Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
1524 Bool& as_bool = 1408 Bool& as_bool =
1525 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results)); 1409 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results));
1526 if (as_bool.IsNull()) { 1410 if (as_bool.IsNull()) {
1527 if (results->length() == unary_checks.NumberOfChecks() * 2) { 1411 if (results->length() == unary_checks.NumberOfChecks() * 2) {
1528 const bool can_deopt = TryExpandTestCidsResult(results, type); 1412 const bool can_deopt = TryExpandTestCidsResult(results, type);
1529 TestCidsInstr* test_cids = new(Z) TestCidsInstr( 1413 TestCidsInstr* test_cids = new (Z) TestCidsInstr(
1530 call->token_pos(), 1414 call->token_pos(), negate ? Token::kISNOT : Token::kIS,
1531 negate ? Token::kISNOT : Token::kIS, 1415 new (Z) Value(left), *results,
1532 new(Z) Value(left),
1533 *results,
1534 can_deopt ? call->deopt_id() : Thread::kNoDeoptId); 1416 can_deopt ? call->deopt_id() : Thread::kNoDeoptId);
1535 // Remove type. 1417 // Remove type.
1536 ReplaceCall(call, test_cids); 1418 ReplaceCall(call, test_cids);
1537 return; 1419 return;
1538 } 1420 }
1539 } else { 1421 } else {
1540 // TODO(srdjan): Use TestCidsInstr also for this case. 1422 // TODO(srdjan): Use TestCidsInstr also for this case.
1541 // One result only. 1423 // One result only.
1542 AddReceiverCheck(call); 1424 AddReceiverCheck(call);
1543 if (negate) { 1425 if (negate) {
1544 as_bool = Bool::Get(!as_bool.value()).raw(); 1426 as_bool = Bool::Get(!as_bool.value()).raw();
1545 } 1427 }
1546 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool); 1428 ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool);
1547 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 1429 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
1548 PushArgumentInstr* push = call->PushArgumentAt(i); 1430 PushArgumentInstr* push = call->PushArgumentAt(i);
1549 push->ReplaceUsesWith(push->value()->definition()); 1431 push->ReplaceUsesWith(push->value()->definition());
1550 push->RemoveFromGraph(); 1432 push->RemoveFromGraph();
1551 } 1433 }
1552 call->ReplaceUsesWith(bool_const); 1434 call->ReplaceUsesWith(bool_const);
1553 ASSERT(current_iterator()->Current() == call); 1435 ASSERT(current_iterator()->Current() == call);
1554 current_iterator()->RemoveCurrentFromGraph(); 1436 current_iterator()->RemoveCurrentFromGraph();
1555 return; 1437 return;
1556 } 1438 }
1557 } 1439 }
1558 1440
1559 if (TypeCheckAsClassEquality(type)) { 1441 if (TypeCheckAsClassEquality(type)) {
1560 LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left)); 1442 LoadClassIdInstr* left_cid = new (Z) LoadClassIdInstr(new (Z) Value(left));
1561 InsertBefore(call, 1443 InsertBefore(call, left_cid, NULL, FlowGraph::kValue);
1562 left_cid,
1563 NULL,
1564 FlowGraph::kValue);
1565 const intptr_t type_cid = Class::Handle(Z, type.type_class()).id(); 1444 const intptr_t type_cid = Class::Handle(Z, type.type_class()).id();
1566 ConstantInstr* cid = 1445 ConstantInstr* cid =
1567 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid))); 1446 flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid)));
1568 1447
1569 StrictCompareInstr* check_cid = 1448 StrictCompareInstr* check_cid = new (Z) StrictCompareInstr(
1570 new(Z) StrictCompareInstr( 1449 call->token_pos(), negate ? Token::kNE_STRICT : Token::kEQ_STRICT,
1571 call->token_pos(), 1450 new (Z) Value(left_cid), new (Z) Value(cid),
1572 negate ? Token::kNE_STRICT : Token::kEQ_STRICT, 1451 false); // No number check.
1573 new(Z) Value(left_cid),
1574 new(Z) Value(cid),
1575 false); // No number check.
1576 ReplaceCall(call, check_cid); 1452 ReplaceCall(call, check_cid);
1577 return; 1453 return;
1578 } 1454 }
1579 1455
1580 InstanceOfInstr* instance_of = 1456 InstanceOfInstr* instance_of = new (Z)
1581 new(Z) InstanceOfInstr(call->token_pos(), 1457 InstanceOfInstr(call->token_pos(), new (Z) Value(left),
1582 new(Z) Value(left), 1458 new (Z) Value(type_args), type, negate, call->deopt_id());
1583 new(Z) Value(type_args),
1584 type,
1585 negate,
1586 call->deopt_id());
1587 ReplaceCall(call, instance_of); 1459 ReplaceCall(call, instance_of);
1588 } 1460 }
1589 1461
1590 1462
1591 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). 1463 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
1592 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { 1464 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
1593 ASSERT(Token::IsTypeCastOperator(call->token_kind())); 1465 ASSERT(Token::IsTypeCastOperator(call->token_kind()));
1594 Definition* left = call->ArgumentAt(0); 1466 Definition* left = call->ArgumentAt(0);
1595 Definition* type_args = call->ArgumentAt(1); 1467 Definition* type_args = call->ArgumentAt(1);
1596 const AbstractType& type = 1468 const AbstractType& type =
1597 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()); 1469 AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value());
1598 ASSERT(!type.IsMalformedOrMalbounded()); 1470 ASSERT(!type.IsMalformedOrMalbounded());
1599 const ICData& unary_checks = 1471 const ICData& unary_checks =
1600 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()); 1472 ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
1601 if ((unary_checks.NumberOfChecks() > 0) && 1473 if ((unary_checks.NumberOfChecks() > 0) &&
1602 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) { 1474 (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
1603 ZoneGrowableArray<intptr_t>* results = 1475 ZoneGrowableArray<intptr_t>* results =
1604 new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2); 1476 new (Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
1605 const Bool& as_bool = Bool::ZoneHandle(Z, 1477 const Bool& as_bool =
1606 InstanceOfAsBool(unary_checks, type, results)); 1478 Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results));
1607 if (as_bool.raw() == Bool::True().raw()) { 1479 if (as_bool.raw() == Bool::True().raw()) {
1608 AddReceiverCheck(call); 1480 AddReceiverCheck(call);
1609 // Remove the original push arguments. 1481 // Remove the original push arguments.
1610 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 1482 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
1611 PushArgumentInstr* push = call->PushArgumentAt(i); 1483 PushArgumentInstr* push = call->PushArgumentAt(i);
1612 push->ReplaceUsesWith(push->value()->definition()); 1484 push->ReplaceUsesWith(push->value()->definition());
1613 push->RemoveFromGraph(); 1485 push->RemoveFromGraph();
1614 } 1486 }
1615 // Remove call, replace it with 'left'. 1487 // Remove call, replace it with 'left'.
1616 call->ReplaceUsesWith(left); 1488 call->ReplaceUsesWith(left);
1617 ASSERT(current_iterator()->Current() == call); 1489 ASSERT(current_iterator()->Current() == call);
1618 current_iterator()->RemoveCurrentFromGraph(); 1490 current_iterator()->RemoveCurrentFromGraph();
1619 return; 1491 return;
1620 } 1492 }
1621 } 1493 }
1622 AssertAssignableInstr* assert_as = 1494 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr(
1623 new(Z) AssertAssignableInstr(call->token_pos(), 1495 call->token_pos(), new (Z) Value(left), new (Z) Value(type_args), type,
1624 new(Z) Value(left), 1496 Symbols::InTypeCast(), call->deopt_id());
1625 new(Z) Value(type_args),
1626 type,
1627 Symbols::InTypeCast(),
1628 call->deopt_id());
1629 ReplaceCall(call, assert_as); 1497 ReplaceCall(call, assert_as);
1630 } 1498 }
1631 1499
1632 1500
1633 // Tries to optimize instance call by replacing it with a faster instruction 1501 // Tries to optimize instance call by replacing it with a faster instruction
1634 // (e.g, binary op, field load, ..). 1502 // (e.g, binary op, field load, ..).
1635 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { 1503 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
1636 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { 1504 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
1637 return; 1505 return;
1638 } 1506 }
1639 const Token::Kind op_kind = instr->token_kind(); 1507 const Token::Kind op_kind = instr->token_kind();
1640 1508
1641 // Type test is special as it always gets converted into inlined code. 1509 // Type test is special as it always gets converted into inlined code.
1642 if (Token::IsTypeTestOperator(op_kind)) { 1510 if (Token::IsTypeTestOperator(op_kind)) {
1643 ReplaceWithInstanceOf(instr); 1511 ReplaceWithInstanceOf(instr);
1644 return; 1512 return;
1645 } 1513 }
1646 1514
1647 if (Token::IsTypeCastOperator(op_kind)) { 1515 if (Token::IsTypeCastOperator(op_kind)) {
1648 ReplaceWithTypeCast(instr); 1516 ReplaceWithTypeCast(instr);
1649 return; 1517 return;
1650 } 1518 }
1651 1519
1652 const ICData& unary_checks = 1520 const ICData& unary_checks =
1653 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); 1521 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
1654 1522
1655 const bool is_dense = CheckClassInstr::IsDenseCidRange(unary_checks); 1523 const bool is_dense = CheckClassInstr::IsDenseCidRange(unary_checks);
1656 const intptr_t max_checks = (op_kind == Token::kEQ) 1524 const intptr_t max_checks = (op_kind == Token::kEQ)
1657 ? FLAG_max_equality_polymorphic_checks 1525 ? FLAG_max_equality_polymorphic_checks
1658 : FLAG_max_polymorphic_checks; 1526 : FLAG_max_polymorphic_checks;
1659 if ((unary_checks.NumberOfChecks() > max_checks) && 1527 if ((unary_checks.NumberOfChecks() > max_checks) && !is_dense &&
1660 !is_dense &&
1661 flow_graph()->InstanceCallNeedsClassCheck( 1528 flow_graph()->InstanceCallNeedsClassCheck(
1662 instr, RawFunction::kRegularFunction)) { 1529 instr, RawFunction::kRegularFunction)) {
1663 // Too many checks, it will be megamorphic which needs unary checks. 1530 // Too many checks, it will be megamorphic which needs unary checks.
1664 instr->set_ic_data(&unary_checks); 1531 instr->set_ic_data(&unary_checks);
1665 return; 1532 return;
1666 } 1533 }
1667 1534
1668 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { 1535 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
1669 return; 1536 return;
1670 } 1537 }
(...skipping 27 matching lines...) Expand all
1698 } 1565 }
1699 if (TryInlineInstanceMethod(instr)) { 1566 if (TryInlineInstanceMethod(instr)) {
1700 return; 1567 return;
1701 } 1568 }
1702 1569
1703 bool has_one_target = unary_checks.HasOneTarget(); 1570 bool has_one_target = unary_checks.HasOneTarget();
1704 1571
1705 if (has_one_target) { 1572 if (has_one_target) {
1706 // Check if the single target is a polymorphic target, if it is, 1573 // Check if the single target is a polymorphic target, if it is,
1707 // we don't have one target. 1574 // we don't have one target.
1708 const Function& target = 1575 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
1709 Function::Handle(Z, unary_checks.GetTargetAt(0));
1710 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) { 1576 if (target.recognized_kind() == MethodRecognizer::kObjectRuntimeType) {
1711 has_one_target = 1577 has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType(
1712 PolymorphicInstanceCallInstr::ComputeRuntimeType(unary_checks) != 1578 unary_checks) != Type::null();
1713 Type::null();
1714 } else { 1579 } else {
1715 const bool polymorphic_target = 1580 const bool polymorphic_target =
1716 MethodRecognizer::PolymorphicTarget(target); 1581 MethodRecognizer::PolymorphicTarget(target);
1717 has_one_target = !polymorphic_target; 1582 has_one_target = !polymorphic_target;
1718 } 1583 }
1719 } 1584 }
1720 1585
1721 if (has_one_target) { 1586 if (has_one_target) {
1722 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0)); 1587 const Function& target = Function::Handle(Z, unary_checks.GetTargetAt(0));
1723 const RawFunction::Kind function_kind = target.kind(); 1588 const RawFunction::Kind function_kind = target.kind();
1724 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) { 1589 if (!flow_graph()->InstanceCallNeedsClassCheck(instr, function_kind)) {
1725 PolymorphicInstanceCallInstr* call = 1590 PolymorphicInstanceCallInstr* call =
1726 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, 1591 new (Z) PolymorphicInstanceCallInstr(instr, unary_checks,
1727 /* call_with_checks = */ false, 1592 /* call_with_checks = */ false,
1728 /* complete = */ false); 1593 /* complete = */ false);
1729 instr->ReplaceWith(call, current_iterator()); 1594 instr->ReplaceWith(call, current_iterator());
1730 return; 1595 return;
1731 } 1596 }
1732 } 1597 }
1733 1598
1734 if ((unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) || 1599 if ((unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) ||
1735 (has_one_target && is_dense)) { 1600 (has_one_target && is_dense)) {
1736 bool call_with_checks; 1601 bool call_with_checks;
1737 if (has_one_target && FLAG_polymorphic_with_deopt) { 1602 if (has_one_target && FLAG_polymorphic_with_deopt) {
1738 // Type propagation has not run yet, we cannot eliminate the check. 1603 // Type propagation has not run yet, we cannot eliminate the check.
1739 AddReceiverCheck(instr); 1604 AddReceiverCheck(instr);
1740 // Call can still deoptimize, do not detach environment from instr. 1605 // Call can still deoptimize, do not detach environment from instr.
1741 call_with_checks = false; 1606 call_with_checks = false;
1742 } else { 1607 } else {
1743 call_with_checks = true; 1608 call_with_checks = true;
1744 } 1609 }
1745 PolymorphicInstanceCallInstr* call = 1610 PolymorphicInstanceCallInstr* call = new (Z)
1746 new(Z) PolymorphicInstanceCallInstr(instr, unary_checks, 1611 PolymorphicInstanceCallInstr(instr, unary_checks, call_with_checks,
1747 call_with_checks, 1612 /* complete = */ false);
1748 /* complete = */ false);
1749 instr->ReplaceWith(call, current_iterator()); 1613 instr->ReplaceWith(call, current_iterator());
1750 } 1614 }
1751 } 1615 }
1752 1616
1753 1617
1754 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { 1618 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
1755 MethodRecognizer::Kind recognized_kind = 1619 MethodRecognizer::Kind recognized_kind =
1756 MethodRecognizer::RecognizeKind(call->function()); 1620 MethodRecognizer::RecognizeKind(call->function());
1757 switch (recognized_kind) { 1621 switch (recognized_kind) {
1758 case MethodRecognizer::kObjectConstructor: 1622 case MethodRecognizer::kObjectConstructor:
(...skipping 17 matching lines...) Expand all
1776 case MethodRecognizer::kMathAcos: 1640 case MethodRecognizer::kMathAcos:
1777 case MethodRecognizer::kMathAtan: 1641 case MethodRecognizer::kMathAtan:
1778 case MethodRecognizer::kMathAtan2: 1642 case MethodRecognizer::kMathAtan2:
1779 FlowGraphInliner::TryReplaceStaticCallWithInline( 1643 FlowGraphInliner::TryReplaceStaticCallWithInline(
1780 flow_graph_, current_iterator(), call); 1644 flow_graph_, current_iterator(), call);
1781 break; 1645 break;
1782 case MethodRecognizer::kMathMin: 1646 case MethodRecognizer::kMathMin:
1783 case MethodRecognizer::kMathMax: { 1647 case MethodRecognizer::kMathMax: {
1784 // We can handle only monomorphic min/max call sites with both arguments 1648 // We can handle only monomorphic min/max call sites with both arguments
1785 // being either doubles or smis. 1649 // being either doubles or smis.
1786 if (CanUnboxDouble() && 1650 if (CanUnboxDouble() && call->HasICData() &&
1787 call->HasICData() &&
1788 (call->ic_data()->NumberOfChecks() == 1)) { 1651 (call->ic_data()->NumberOfChecks() == 1)) {
1789 const ICData& ic_data = *call->ic_data(); 1652 const ICData& ic_data = *call->ic_data();
1790 intptr_t result_cid = kIllegalCid; 1653 intptr_t result_cid = kIllegalCid;
1791 if (ICDataHasReceiverArgumentClassIds(ic_data, 1654 if (ICDataHasReceiverArgumentClassIds(ic_data, kDoubleCid,
1792 kDoubleCid, kDoubleCid)) { 1655 kDoubleCid)) {
1793 result_cid = kDoubleCid; 1656 result_cid = kDoubleCid;
1794 } else if (ICDataHasReceiverArgumentClassIds(ic_data, 1657 } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid,
1795 kSmiCid, kSmiCid)) { 1658 kSmiCid)) {
1796 result_cid = kSmiCid; 1659 result_cid = kSmiCid;
1797 } 1660 }
1798 if (result_cid != kIllegalCid) { 1661 if (result_cid != kIllegalCid) {
1799 MathMinMaxInstr* min_max = new(Z) MathMinMaxInstr( 1662 MathMinMaxInstr* min_max = new (Z) MathMinMaxInstr(
1800 recognized_kind, 1663 recognized_kind, new (Z) Value(call->ArgumentAt(0)),
1801 new(Z) Value(call->ArgumentAt(0)), 1664 new (Z) Value(call->ArgumentAt(1)), call->deopt_id(), result_cid);
1802 new(Z) Value(call->ArgumentAt(1)),
1803 call->deopt_id(),
1804 result_cid);
1805 const ICData& unary_checks = 1665 const ICData& unary_checks =
1806 ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks()); 1666 ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks());
1807 AddCheckClass(min_max->left()->definition(), 1667 AddCheckClass(min_max->left()->definition(), unary_checks,
1808 unary_checks, 1668 call->deopt_id(), call->env(), call);
1809 call->deopt_id(), 1669 AddCheckClass(min_max->right()->definition(), unary_checks,
1810 call->env(), 1670 call->deopt_id(), call->env(), call);
1811 call);
1812 AddCheckClass(min_max->right()->definition(),
1813 unary_checks,
1814 call->deopt_id(),
1815 call->env(),
1816 call);
1817 ReplaceCall(call, min_max); 1671 ReplaceCall(call, min_max);
1818 } 1672 }
1819 } 1673 }
1820 break; 1674 break;
1821 } 1675 }
1822 1676
1823 case MethodRecognizer::kDoubleFromInteger: { 1677 case MethodRecognizer::kDoubleFromInteger: {
1824 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) { 1678 if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
1825 const ICData& ic_data = *call->ic_data(); 1679 const ICData& ic_data = *call->ic_data();
1826 if (CanUnboxDouble()) { 1680 if (CanUnboxDouble()) {
1827 if (ArgIsAlways(kSmiCid, ic_data, 1)) { 1681 if (ArgIsAlways(kSmiCid, ic_data, 1)) {
1828 Definition* arg = call->ArgumentAt(1); 1682 Definition* arg = call->ArgumentAt(1);
1829 AddCheckSmi(arg, call->deopt_id(), call->env(), call); 1683 AddCheckSmi(arg, call->deopt_id(), call->env(), call);
1830 ReplaceCall(call, 1684 ReplaceCall(call, new (Z) SmiToDoubleInstr(new (Z) Value(arg),
1831 new(Z) SmiToDoubleInstr(new(Z) Value(arg), 1685 call->token_pos()));
1832 call->token_pos()));
1833 } else if (ArgIsAlways(kMintCid, ic_data, 1) && 1686 } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
1834 CanConvertUnboxedMintToDouble()) { 1687 CanConvertUnboxedMintToDouble()) {
1835 Definition* arg = call->ArgumentAt(1); 1688 Definition* arg = call->ArgumentAt(1);
1836 ReplaceCall(call, 1689 ReplaceCall(call, new (Z) MintToDoubleInstr(new (Z) Value(arg),
1837 new(Z) MintToDoubleInstr(new(Z) Value(arg), 1690 call->deopt_id()));
1838 call->deopt_id()));
1839 } 1691 }
1840 } 1692 }
1841 } 1693 }
1842 break; 1694 break;
1843 } 1695 }
1844 default: 1696 default:
1845 break; 1697 break;
1846 } 1698 }
1847 } 1699 }
1848 1700
1849 1701
1850 void JitOptimizer::VisitStoreInstanceField( 1702 void JitOptimizer::VisitStoreInstanceField(StoreInstanceFieldInstr* instr) {
1851 StoreInstanceFieldInstr* instr) {
1852 if (instr->IsUnboxedStore()) { 1703 if (instr->IsUnboxedStore()) {
1853 // Determine if this field should be unboxed based on the usage of getter 1704 // Determine if this field should be unboxed based on the usage of getter
1854 // and setter functions: The heuristic requires that the setter has a 1705 // and setter functions: The heuristic requires that the setter has a
1855 // usage count of at least 1/kGetterSetterRatio of the getter usage count. 1706 // usage count of at least 1/kGetterSetterRatio of the getter usage count.
1856 // This is to avoid unboxing fields where the setter is never or rarely 1707 // This is to avoid unboxing fields where the setter is never or rarely
1857 // executed. 1708 // executed.
1858 const Field& field = instr->field(); 1709 const Field& field = instr->field();
1859 const String& field_name = String::Handle(Z, field.name()); 1710 const String& field_name = String::Handle(Z, field.name());
1860 const Class& owner = Class::Handle(Z, field.Owner()); 1711 const Class& owner = Class::Handle(Z, field.Owner());
1861 const Function& getter = 1712 const Function& getter =
1862 Function::Handle(Z, owner.LookupGetterFunction(field_name)); 1713 Function::Handle(Z, owner.LookupGetterFunction(field_name));
1863 const Function& setter = 1714 const Function& setter =
1864 Function::Handle(Z, owner.LookupSetterFunction(field_name)); 1715 Function::Handle(Z, owner.LookupSetterFunction(field_name));
1865 bool unboxed_field = false; 1716 bool unboxed_field = false;
1866 if (!getter.IsNull() && !setter.IsNull()) { 1717 if (!getter.IsNull() && !setter.IsNull()) {
1867 if (field.is_double_initialized()) { 1718 if (field.is_double_initialized()) {
1868 unboxed_field = true; 1719 unboxed_field = true;
1869 } else if ((setter.usage_counter() > 0) && 1720 } else if ((setter.usage_counter() > 0) &&
1870 ((FLAG_getter_setter_ratio * setter.usage_counter()) >= 1721 ((FLAG_getter_setter_ratio * setter.usage_counter()) >=
1871 getter.usage_counter())) { 1722 getter.usage_counter())) {
1872 unboxed_field = true; 1723 unboxed_field = true;
1873 } 1724 }
1874 } 1725 }
1875 if (!unboxed_field) { 1726 if (!unboxed_field) {
1876 // TODO(srdjan): Instead of aborting pass this field to the mutator thread 1727 // TODO(srdjan): Instead of aborting pass this field to the mutator thread
1877 // so that it can: 1728 // so that it can:
1878 // - set it to unboxed 1729 // - set it to unboxed
1879 // - deoptimize dependent code. 1730 // - deoptimize dependent code.
1880 if (Compiler::IsBackgroundCompilation()) { 1731 if (Compiler::IsBackgroundCompilation()) {
1881 isolate()->AddDeoptimizingBoxedField(field); 1732 isolate()->AddDeoptimizingBoxedField(field);
1882 Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId, 1733 Compiler::AbortBackgroundCompilation(
1883 "Unboxing instance field while compiling"); 1734 Thread::kNoDeoptId, "Unboxing instance field while compiling");
1884 UNREACHABLE(); 1735 UNREACHABLE();
1885 } 1736 }
1886 if (FLAG_trace_optimization || FLAG_trace_field_guards) { 1737 if (FLAG_trace_optimization || FLAG_trace_field_guards) {
1887 THR_Print("Disabling unboxing of %s\n", field.ToCString()); 1738 THR_Print("Disabling unboxing of %s\n", field.ToCString());
1888 if (!setter.IsNull()) { 1739 if (!setter.IsNull()) {
1889 OS::Print(" setter usage count: %" Pd "\n", setter.usage_counter()); 1740 OS::Print(" setter usage count: %" Pd "\n", setter.usage_counter());
1890 } 1741 }
1891 if (!getter.IsNull()) { 1742 if (!getter.IsNull()) {
1892 OS::Print(" getter usage count: %" Pd "\n", getter.usage_counter()); 1743 OS::Print(" getter usage count: %" Pd "\n", getter.usage_counter());
1893 } 1744 }
1894 } 1745 }
1895 ASSERT(field.IsOriginal()); 1746 ASSERT(field.IsOriginal());
1896 field.set_is_unboxing_candidate(false); 1747 field.set_is_unboxing_candidate(false);
1897 field.DeoptimizeDependentCode(); 1748 field.DeoptimizeDependentCode();
1898 } else { 1749 } else {
1899 flow_graph()->parsed_function().AddToGuardedFields(&field); 1750 flow_graph()->parsed_function().AddToGuardedFields(&field);
1900 } 1751 }
1901 } 1752 }
1902 } 1753 }
1903 1754
1904 1755
1905 void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { 1756 void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
1906 // Replace generic allocation with a sequence of inlined allocation and 1757 // Replace generic allocation with a sequence of inlined allocation and
1907 // explicit initalizing stores. 1758 // explicit initalizing stores.
1908 AllocateUninitializedContextInstr* replacement = 1759 AllocateUninitializedContextInstr* replacement =
1909 new AllocateUninitializedContextInstr(instr->token_pos(), 1760 new AllocateUninitializedContextInstr(instr->token_pos(),
1910 instr->num_context_variables()); 1761 instr->num_context_variables());
1911 instr->ReplaceWith(replacement, current_iterator()); 1762 instr->ReplaceWith(replacement, current_iterator());
1912 1763
1913 StoreInstanceFieldInstr* store = 1764 StoreInstanceFieldInstr* store = new (Z)
1914 new(Z) StoreInstanceFieldInstr(Context::parent_offset(), 1765 StoreInstanceFieldInstr(Context::parent_offset(), new Value(replacement),
1915 new Value(replacement), 1766 new Value(flow_graph_->constant_null()),
1916 new Value(flow_graph_->constant_null()), 1767 kNoStoreBarrier, instr->token_pos());
1917 kNoStoreBarrier,
1918 instr->token_pos());
1919 // Storing into uninitialized memory; remember to prevent dead store 1768 // Storing into uninitialized memory; remember to prevent dead store
1920 // elimination and ensure proper GC barrier. 1769 // elimination and ensure proper GC barrier.
1921 store->set_is_initialization(true); 1770 store->set_is_initialization(true);
1922 flow_graph_->InsertAfter(replacement, store, NULL, FlowGraph::kEffect); 1771 flow_graph_->InsertAfter(replacement, store, NULL, FlowGraph::kEffect);
1923 Definition* cursor = store; 1772 Definition* cursor = store;
1924 for (intptr_t i = 0; i < instr->num_context_variables(); ++i) { 1773 for (intptr_t i = 0; i < instr->num_context_variables(); ++i) {
1925 store = 1774 store = new (Z) StoreInstanceFieldInstr(
1926 new(Z) StoreInstanceFieldInstr(Context::variable_offset(i), 1775 Context::variable_offset(i), new Value(replacement),
1927 new Value(replacement), 1776 new Value(flow_graph_->constant_null()), kNoStoreBarrier,
1928 new Value(flow_graph_->constant_null()), 1777 instr->token_pos());
1929 kNoStoreBarrier,
1930 instr->token_pos());
1931 // Storing into uninitialized memory; remember to prevent dead store 1778 // Storing into uninitialized memory; remember to prevent dead store
1932 // elimination and ensure proper GC barrier. 1779 // elimination and ensure proper GC barrier.
1933 store->set_is_initialization(true); 1780 store->set_is_initialization(true);
1934 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); 1781 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect);
1935 cursor = store; 1782 cursor = store;
1936 } 1783 }
1937 } 1784 }
1938 1785
1939 1786
1940 void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { 1787 void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) {
1941 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. 1788 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized.
1942 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) 1789 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM)
1943 if (!instr->can_pack_into_smi()) 1790 if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedMint);
1944 instr->set_representation(kUnboxedMint);
1945 #endif 1791 #endif
1946 } 1792 }
1947 1793
1948 1794
1949 bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, 1795 bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
1950 const ICData& unary_ic_data) { 1796 const ICData& unary_ic_data) {
1951 ASSERT((unary_ic_data.NumberOfChecks() > 0) && 1797 ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
1952 (unary_ic_data.NumArgsTested() == 1)); 1798 (unary_ic_data.NumArgsTested() == 1));
1953 if (I->type_checks()) { 1799 if (I->type_checks()) {
1954 // Checked mode setters are inlined like normal methods by conventional 1800 // Checked mode setters are inlined like normal methods by conventional
1955 // inlining. 1801 // inlining.
1956 return false; 1802 return false;
1957 } 1803 }
1958 1804
1959 ASSERT(instr->HasICData()); 1805 ASSERT(instr->HasICData());
1960 if (unary_ic_data.NumberOfChecks() == 0) { 1806 if (unary_ic_data.NumberOfChecks() == 0) {
1961 // No type feedback collected. 1807 // No type feedback collected.
1962 return false; 1808 return false;
1963 } 1809 }
1964 if (!unary_ic_data.HasOneTarget()) { 1810 if (!unary_ic_data.HasOneTarget()) {
1965 // Polymorphic sites are inlined like normal method calls by conventional 1811 // Polymorphic sites are inlined like normal method calls by conventional
1966 // inlining. 1812 // inlining.
1967 return false; 1813 return false;
1968 } 1814 }
1969 Function& target = Function::Handle(Z); 1815 Function& target = Function::Handle(Z);
1970 intptr_t class_id; 1816 intptr_t class_id;
1971 unary_ic_data.GetOneClassCheckAt(0, &class_id, &target); 1817 unary_ic_data.GetOneClassCheckAt(0, &class_id, &target);
1972 if (target.kind() != RawFunction::kImplicitSetter) { 1818 if (target.kind() != RawFunction::kImplicitSetter) {
1973 // Non-implicit setter are inlined like normal method calls. 1819 // Non-implicit setter are inlined like normal method calls.
1974 return false; 1820 return false;
1975 } 1821 }
1976 // Inline implicit instance setter. 1822 // Inline implicit instance setter.
1977 const String& field_name = 1823 const String& field_name =
1978 String::Handle(Z, Field::NameFromSetter(instr->function_name())); 1824 String::Handle(Z, Field::NameFromSetter(instr->function_name()));
1979 const Field& field = 1825 const Field& field = Field::ZoneHandle(Z, GetField(class_id, field_name));
1980 Field::ZoneHandle(Z, GetField(class_id, field_name));
1981 ASSERT(!field.IsNull()); 1826 ASSERT(!field.IsNull());
1982 1827
1983 if (flow_graph()->InstanceCallNeedsClassCheck( 1828 if (flow_graph()->InstanceCallNeedsClassCheck(instr,
1984 instr, RawFunction::kImplicitSetter)) { 1829 RawFunction::kImplicitSetter)) {
1985 AddReceiverCheck(instr); 1830 AddReceiverCheck(instr);
1986 } 1831 }
1987 if (field.guarded_cid() != kDynamicCid) { 1832 if (field.guarded_cid() != kDynamicCid) {
1988 ASSERT(FLAG_use_field_guards); 1833 ASSERT(FLAG_use_field_guards);
1989 InsertBefore(instr, 1834 InsertBefore(
1990 new(Z) GuardFieldClassInstr( 1835 instr, new (Z) GuardFieldClassInstr(new (Z) Value(instr->ArgumentAt(1)),
1991 new(Z) Value(instr->ArgumentAt(1)), 1836 field, instr->deopt_id()),
1992 field, 1837 instr->env(), FlowGraph::kEffect);
1993 instr->deopt_id()),
1994 instr->env(),
1995 FlowGraph::kEffect);
1996 } 1838 }
1997 1839
1998 if (field.needs_length_check()) { 1840 if (field.needs_length_check()) {
1999 ASSERT(FLAG_use_field_guards); 1841 ASSERT(FLAG_use_field_guards);
2000 InsertBefore(instr, 1842 InsertBefore(instr, new (Z) GuardFieldLengthInstr(
2001 new(Z) GuardFieldLengthInstr( 1843 new (Z) Value(instr->ArgumentAt(1)), field,
2002 new(Z) Value(instr->ArgumentAt(1)), 1844 instr->deopt_id()),
2003 field, 1845 instr->env(), FlowGraph::kEffect);
2004 instr->deopt_id()),
2005 instr->env(),
2006 FlowGraph::kEffect);
2007 } 1846 }
2008 1847
2009 // Field guard was detached. 1848 // Field guard was detached.
2010 StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr( 1849 StoreInstanceFieldInstr* store = new (Z)
2011 field, 1850 StoreInstanceFieldInstr(field, new (Z) Value(instr->ArgumentAt(0)),
2012 new(Z) Value(instr->ArgumentAt(0)), 1851 new (Z) Value(instr->ArgumentAt(1)),
2013 new(Z) Value(instr->ArgumentAt(1)), 1852 kEmitStoreBarrier, instr->token_pos());
2014 kEmitStoreBarrier,
2015 instr->token_pos());
2016 1853
2017 if (store->IsUnboxedStore()) { 1854 if (store->IsUnboxedStore()) {
2018 flow_graph()->parsed_function().AddToGuardedFields(&field); 1855 flow_graph()->parsed_function().AddToGuardedFields(&field);
2019 } 1856 }
2020 1857
2021 // Discard the environment from the original instruction because the store 1858 // Discard the environment from the original instruction because the store
2022 // can't deoptimize. 1859 // can't deoptimize.
2023 instr->RemoveEnvironment(); 1860 instr->RemoveEnvironment();
2024 ReplaceCall(instr, store); 1861 ReplaceCall(instr, store);
2025 return true; 1862 return true;
2026 } 1863 }
2027 1864
2028 1865
2029 } // namespace dart 1866 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/jit_optimizer.h ('k') | runtime/vm/json_stream.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698