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