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 #ifndef DART_PRECOMPILED_RUNTIME | 4 #ifndef DART_PRECOMPILED_RUNTIME |
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 18 matching lines...) Expand all Loading... |
29 namespace dart { | 29 namespace dart { |
30 | 30 |
31 // Quick access to the current isolate and zone. | 31 // Quick access to the current isolate and zone. |
32 #define I (isolate()) | 32 #define I (isolate()) |
33 #define Z (zone()) | 33 #define Z (zone()) |
34 | 34 |
35 static bool ShouldInlineSimd() { | 35 static bool ShouldInlineSimd() { |
36 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 36 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
37 } | 37 } |
38 | 38 |
39 | |
40 static bool CanUnboxDouble() { | 39 static bool CanUnboxDouble() { |
41 return FlowGraphCompiler::SupportsUnboxedDoubles(); | 40 return FlowGraphCompiler::SupportsUnboxedDoubles(); |
42 } | 41 } |
43 | 42 |
44 | |
45 static bool CanConvertUnboxedMintToDouble() { | 43 static bool CanConvertUnboxedMintToDouble() { |
46 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); | 44 return FlowGraphCompiler::CanConvertUnboxedMintToDouble(); |
47 } | 45 } |
48 | 46 |
49 | |
50 // Optimize instance calls using ICData. | 47 // Optimize instance calls using ICData. |
51 void JitOptimizer::ApplyICData() { | 48 void JitOptimizer::ApplyICData() { |
52 VisitBlocks(); | 49 VisitBlocks(); |
53 } | 50 } |
54 | 51 |
55 | |
56 // Optimize instance calls using cid. This is called after optimizer | 52 // Optimize instance calls using cid. This is called after optimizer |
57 // converted instance calls to instructions. Any remaining | 53 // converted instance calls to instructions. Any remaining |
58 // instance calls are either megamorphic calls, cannot be optimized or | 54 // instance calls are either megamorphic calls, cannot be optimized or |
59 // have no runtime type feedback collected. | 55 // have no runtime type feedback collected. |
60 // Attempts to convert an instance call (IC call) using propagated class-ids, | 56 // Attempts to convert an instance call (IC call) using propagated class-ids, |
61 // e.g., receiver class id, guarded-cid, or by guessing cid-s. | 57 // e.g., receiver class id, guarded-cid, or by guessing cid-s. |
62 void JitOptimizer::ApplyClassIds() { | 58 void JitOptimizer::ApplyClassIds() { |
63 ASSERT(current_iterator_ == NULL); | 59 ASSERT(current_iterator_ == NULL); |
64 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); | 60 for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator(); |
65 !block_it.Done(); block_it.Advance()) { | 61 !block_it.Done(); block_it.Advance()) { |
(...skipping 10 matching lines...) Expand all Loading... |
76 } | 72 } |
77 } | 73 } |
78 } else if (instr->IsPolymorphicInstanceCall()) { | 74 } else if (instr->IsPolymorphicInstanceCall()) { |
79 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall()); | 75 SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall()); |
80 } | 76 } |
81 } | 77 } |
82 current_iterator_ = NULL; | 78 current_iterator_ = NULL; |
83 } | 79 } |
84 } | 80 } |
85 | 81 |
86 | |
87 // TODO(srdjan): Test/support other number types as well. | 82 // TODO(srdjan): Test/support other number types as well. |
88 static bool IsNumberCid(intptr_t cid) { | 83 static bool IsNumberCid(intptr_t cid) { |
89 return (cid == kSmiCid) || (cid == kDoubleCid); | 84 return (cid == kSmiCid) || (cid == kDoubleCid); |
90 } | 85 } |
91 | 86 |
92 | |
93 bool JitOptimizer::TryCreateICData(InstanceCallInstr* call) { | 87 bool JitOptimizer::TryCreateICData(InstanceCallInstr* call) { |
94 ASSERT(call->HasICData()); | 88 ASSERT(call->HasICData()); |
95 if (call->ic_data()->NumberOfUsedChecks() > 0) { | 89 if (call->ic_data()->NumberOfUsedChecks() > 0) { |
96 // This occurs when an instance call has too many checks, will be converted | 90 // This occurs when an instance call has too many checks, will be converted |
97 // to megamorphic call. | 91 // to megamorphic call. |
98 return false; | 92 return false; |
99 } | 93 } |
100 | 94 |
101 const intptr_t receiver_index = call->FirstParamIndex(); | 95 const intptr_t receiver_index = call->FirstParamIndex(); |
102 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); | 96 GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested()); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 ic_data.AddReceiverCheck(owner_class.id(), function); | 183 ic_data.AddReceiverCheck(owner_class.id(), function); |
190 call->set_ic_data(&ic_data); | 184 call->set_ic_data(&ic_data); |
191 return true; | 185 return true; |
192 } | 186 } |
193 } | 187 } |
194 } | 188 } |
195 | 189 |
196 return false; | 190 return false; |
197 } | 191 } |
198 | 192 |
199 | |
200 void JitOptimizer::SpecializePolymorphicInstanceCall( | 193 void JitOptimizer::SpecializePolymorphicInstanceCall( |
201 PolymorphicInstanceCallInstr* call) { | 194 PolymorphicInstanceCallInstr* call) { |
202 if (!FLAG_polymorphic_with_deopt) { | 195 if (!FLAG_polymorphic_with_deopt) { |
203 // Specialization adds receiver checks which can lead to deoptimization. | 196 // Specialization adds receiver checks which can lead to deoptimization. |
204 return; | 197 return; |
205 } | 198 } |
206 | 199 |
207 const intptr_t receiver_cid = | 200 const intptr_t receiver_cid = |
208 call->PushArgumentAt(0)->value()->Type()->ToCid(); | 201 call->PushArgumentAt(0)->value()->Type()->ToCid(); |
209 if (receiver_cid == kDynamicCid) { | 202 if (receiver_cid == kDynamicCid) { |
(...skipping 10 matching lines...) Expand all Loading... |
220 // No specialization. | 213 // No specialization. |
221 return; | 214 return; |
222 } | 215 } |
223 | 216 |
224 ASSERT(targets->HasSingleTarget()); | 217 ASSERT(targets->HasSingleTarget()); |
225 const Function& target = targets->FirstTarget(); | 218 const Function& target = targets->FirstTarget(); |
226 StaticCallInstr* specialized = StaticCallInstr::FromCall(Z, call, target); | 219 StaticCallInstr* specialized = StaticCallInstr::FromCall(Z, call, target); |
227 call->ReplaceWith(specialized, current_iterator()); | 220 call->ReplaceWith(specialized, current_iterator()); |
228 } | 221 } |
229 | 222 |
230 | |
231 static bool ClassIdIsOneOf(intptr_t class_id, | 223 static bool ClassIdIsOneOf(intptr_t class_id, |
232 const GrowableArray<intptr_t>& class_ids) { | 224 const GrowableArray<intptr_t>& class_ids) { |
233 for (intptr_t i = 0; i < class_ids.length(); i++) { | 225 for (intptr_t i = 0; i < class_ids.length(); i++) { |
234 ASSERT(class_ids[i] != kIllegalCid); | 226 ASSERT(class_ids[i] != kIllegalCid); |
235 if (class_ids[i] == class_id) { | 227 if (class_ids[i] == class_id) { |
236 return true; | 228 return true; |
237 } | 229 } |
238 } | 230 } |
239 return false; | 231 return false; |
240 } | 232 } |
241 | 233 |
242 | |
243 // Returns true if ICData tests two arguments and all ICData cids are in the | 234 // Returns true if ICData tests two arguments and all ICData cids are in the |
244 // required sets 'receiver_class_ids' or 'argument_class_ids', respectively. | 235 // required sets 'receiver_class_ids' or 'argument_class_ids', respectively. |
245 static bool ICDataHasOnlyReceiverArgumentClassIds( | 236 static bool ICDataHasOnlyReceiverArgumentClassIds( |
246 const ICData& ic_data, | 237 const ICData& ic_data, |
247 const GrowableArray<intptr_t>& receiver_class_ids, | 238 const GrowableArray<intptr_t>& receiver_class_ids, |
248 const GrowableArray<intptr_t>& argument_class_ids) { | 239 const GrowableArray<intptr_t>& argument_class_ids) { |
249 if (ic_data.NumArgsTested() != 2) { | 240 if (ic_data.NumArgsTested() != 2) { |
250 return false; | 241 return false; |
251 } | 242 } |
252 const intptr_t len = ic_data.NumberOfChecks(); | 243 const intptr_t len = ic_data.NumberOfChecks(); |
253 GrowableArray<intptr_t> class_ids; | 244 GrowableArray<intptr_t> class_ids; |
254 for (intptr_t i = 0; i < len; i++) { | 245 for (intptr_t i = 0; i < len; i++) { |
255 if (ic_data.IsUsedAt(i)) { | 246 if (ic_data.IsUsedAt(i)) { |
256 ic_data.GetClassIdsAt(i, &class_ids); | 247 ic_data.GetClassIdsAt(i, &class_ids); |
257 ASSERT(class_ids.length() == 2); | 248 ASSERT(class_ids.length() == 2); |
258 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || | 249 if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) || |
259 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { | 250 !ClassIdIsOneOf(class_ids[1], argument_class_ids)) { |
260 return false; | 251 return false; |
261 } | 252 } |
262 } | 253 } |
263 } | 254 } |
264 return true; | 255 return true; |
265 } | 256 } |
266 | 257 |
267 | |
268 static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data, | 258 static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data, |
269 intptr_t receiver_class_id, | 259 intptr_t receiver_class_id, |
270 intptr_t argument_class_id) { | 260 intptr_t argument_class_id) { |
271 if (ic_data.NumArgsTested() != 2) { | 261 if (ic_data.NumArgsTested() != 2) { |
272 return false; | 262 return false; |
273 } | 263 } |
274 const intptr_t len = ic_data.NumberOfChecks(); | 264 const intptr_t len = ic_data.NumberOfChecks(); |
275 for (intptr_t i = 0; i < len; i++) { | 265 for (intptr_t i = 0; i < len; i++) { |
276 if (ic_data.IsUsedAt(i)) { | 266 if (ic_data.IsUsedAt(i)) { |
277 GrowableArray<intptr_t> class_ids; | 267 GrowableArray<intptr_t> class_ids; |
278 ic_data.GetClassIdsAt(i, &class_ids); | 268 ic_data.GetClassIdsAt(i, &class_ids); |
279 ASSERT(class_ids.length() == 2); | 269 ASSERT(class_ids.length() == 2); |
280 if ((class_ids[0] == receiver_class_id) && | 270 if ((class_ids[0] == receiver_class_id) && |
281 (class_ids[1] == argument_class_id)) { | 271 (class_ids[1] == argument_class_id)) { |
282 return true; | 272 return true; |
283 } | 273 } |
284 } | 274 } |
285 } | 275 } |
286 return false; | 276 return false; |
287 } | 277 } |
288 | 278 |
289 | |
290 static bool HasOnlyOneSmi(const ICData& ic_data) { | 279 static bool HasOnlyOneSmi(const ICData& ic_data) { |
291 return (ic_data.NumberOfUsedChecks() == 1) && | 280 return (ic_data.NumberOfUsedChecks() == 1) && |
292 ic_data.HasReceiverClassId(kSmiCid); | 281 ic_data.HasReceiverClassId(kSmiCid); |
293 } | 282 } |
294 | 283 |
295 | |
296 static bool HasOnlySmiOrMint(const ICData& ic_data) { | 284 static bool HasOnlySmiOrMint(const ICData& ic_data) { |
297 if (ic_data.NumberOfUsedChecks() == 1) { | 285 if (ic_data.NumberOfUsedChecks() == 1) { |
298 return ic_data.HasReceiverClassId(kSmiCid) || | 286 return ic_data.HasReceiverClassId(kSmiCid) || |
299 ic_data.HasReceiverClassId(kMintCid); | 287 ic_data.HasReceiverClassId(kMintCid); |
300 } | 288 } |
301 return (ic_data.NumberOfUsedChecks() == 2) && | 289 return (ic_data.NumberOfUsedChecks() == 2) && |
302 ic_data.HasReceiverClassId(kSmiCid) && | 290 ic_data.HasReceiverClassId(kSmiCid) && |
303 ic_data.HasReceiverClassId(kMintCid); | 291 ic_data.HasReceiverClassId(kMintCid); |
304 } | 292 } |
305 | 293 |
306 | |
307 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) { | 294 static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) { |
308 if (ic_data.NumberOfUsedChecks() != 1) { | 295 if (ic_data.NumberOfUsedChecks() != 1) { |
309 return false; | 296 return false; |
310 } | 297 } |
311 GrowableArray<intptr_t> first; | 298 GrowableArray<intptr_t> first; |
312 GrowableArray<intptr_t> second; | 299 GrowableArray<intptr_t> second; |
313 ic_data.GetUsedCidsForTwoArgs(&first, &second); | 300 ic_data.GetUsedCidsForTwoArgs(&first, &second); |
314 return (first[0] == cid) && (second[0] == cid); | 301 return (first[0] == cid) && (second[0] == cid); |
315 } | 302 } |
316 | 303 |
317 // Returns false if the ICData contains anything other than the 4 combinations | 304 // Returns false if the ICData contains anything other than the 4 combinations |
318 // of Mint and Smi for the receiver and argument classes. | 305 // of Mint and Smi for the receiver and argument classes. |
319 static bool HasTwoMintOrSmi(const ICData& ic_data) { | 306 static bool HasTwoMintOrSmi(const ICData& ic_data) { |
320 GrowableArray<intptr_t> first; | 307 GrowableArray<intptr_t> first; |
321 GrowableArray<intptr_t> second; | 308 GrowableArray<intptr_t> second; |
322 ic_data.GetUsedCidsForTwoArgs(&first, &second); | 309 ic_data.GetUsedCidsForTwoArgs(&first, &second); |
323 for (intptr_t i = 0; i < first.length(); i++) { | 310 for (intptr_t i = 0; i < first.length(); i++) { |
324 if ((first[i] != kSmiCid) && (first[i] != kMintCid)) { | 311 if ((first[i] != kSmiCid) && (first[i] != kMintCid)) { |
325 return false; | 312 return false; |
326 } | 313 } |
327 if ((second[i] != kSmiCid) && (second[i] != kMintCid)) { | 314 if ((second[i] != kSmiCid) && (second[i] != kMintCid)) { |
328 return false; | 315 return false; |
329 } | 316 } |
330 } | 317 } |
331 return true; | 318 return true; |
332 } | 319 } |
333 | 320 |
334 | |
335 // Returns false if the ICData contains anything other than the 4 combinations | 321 // Returns false if the ICData contains anything other than the 4 combinations |
336 // of Double and Smi for the receiver and argument classes. | 322 // of Double and Smi for the receiver and argument classes. |
337 static bool HasTwoDoubleOrSmi(const ICData& ic_data) { | 323 static bool HasTwoDoubleOrSmi(const ICData& ic_data) { |
338 GrowableArray<intptr_t> class_ids(2); | 324 GrowableArray<intptr_t> class_ids(2); |
339 class_ids.Add(kSmiCid); | 325 class_ids.Add(kSmiCid); |
340 class_ids.Add(kDoubleCid); | 326 class_ids.Add(kDoubleCid); |
341 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); | 327 return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids); |
342 } | 328 } |
343 | 329 |
344 | |
345 static bool HasOnlyOneDouble(const ICData& ic_data) { | 330 static bool HasOnlyOneDouble(const ICData& ic_data) { |
346 return (ic_data.NumberOfUsedChecks() == 1) && | 331 return (ic_data.NumberOfUsedChecks() == 1) && |
347 ic_data.HasReceiverClassId(kDoubleCid); | 332 ic_data.HasReceiverClassId(kDoubleCid); |
348 } | 333 } |
349 | 334 |
350 | |
351 static bool ShouldSpecializeForDouble(const ICData& ic_data) { | 335 static bool ShouldSpecializeForDouble(const ICData& ic_data) { |
352 // Don't specialize for double if we can't unbox them. | 336 // Don't specialize for double if we can't unbox them. |
353 if (!CanUnboxDouble()) { | 337 if (!CanUnboxDouble()) { |
354 return false; | 338 return false; |
355 } | 339 } |
356 | 340 |
357 // Unboxed double operation can't handle case of two smis. | 341 // Unboxed double operation can't handle case of two smis. |
358 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | 342 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
359 return false; | 343 return false; |
360 } | 344 } |
361 | 345 |
362 // Check that it have seen only smis and doubles. | 346 // Check that it have seen only smis and doubles. |
363 return HasTwoDoubleOrSmi(ic_data); | 347 return HasTwoDoubleOrSmi(ic_data); |
364 } | 348 } |
365 | 349 |
366 | |
367 void JitOptimizer::ReplaceCall(Definition* call, Definition* replacement) { | 350 void JitOptimizer::ReplaceCall(Definition* call, Definition* replacement) { |
368 // Remove the original push arguments. | 351 // Remove the original push arguments. |
369 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 352 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
370 PushArgumentInstr* push = call->PushArgumentAt(i); | 353 PushArgumentInstr* push = call->PushArgumentAt(i); |
371 push->ReplaceUsesWith(push->value()->definition()); | 354 push->ReplaceUsesWith(push->value()->definition()); |
372 push->RemoveFromGraph(); | 355 push->RemoveFromGraph(); |
373 } | 356 } |
374 call->ReplaceWith(replacement, current_iterator()); | 357 call->ReplaceWith(replacement, current_iterator()); |
375 } | 358 } |
376 | 359 |
377 | |
378 void JitOptimizer::AddCheckSmi(Definition* to_check, | 360 void JitOptimizer::AddCheckSmi(Definition* to_check, |
379 intptr_t deopt_id, | 361 intptr_t deopt_id, |
380 Environment* deopt_environment, | 362 Environment* deopt_environment, |
381 Instruction* insert_before) { | 363 Instruction* insert_before) { |
382 if (to_check->Type()->ToCid() != kSmiCid) { | 364 if (to_check->Type()->ToCid() != kSmiCid) { |
383 InsertBefore(insert_before, | 365 InsertBefore(insert_before, |
384 new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, | 366 new (Z) CheckSmiInstr(new (Z) Value(to_check), deopt_id, |
385 insert_before->token_pos()), | 367 insert_before->token_pos()), |
386 deopt_environment, FlowGraph::kEffect); | 368 deopt_environment, FlowGraph::kEffect); |
387 } | 369 } |
388 } | 370 } |
389 | 371 |
390 | |
391 void JitOptimizer::AddCheckClass(Definition* to_check, | 372 void JitOptimizer::AddCheckClass(Definition* to_check, |
392 const Cids& cids, | 373 const Cids& cids, |
393 intptr_t deopt_id, | 374 intptr_t deopt_id, |
394 Environment* deopt_environment, | 375 Environment* deopt_environment, |
395 Instruction* insert_before) { | 376 Instruction* insert_before) { |
396 // Type propagation has not run yet, we cannot eliminate the check. | 377 // Type propagation has not run yet, we cannot eliminate the check. |
397 Instruction* check = flow_graph_->CreateCheckClass( | 378 Instruction* check = flow_graph_->CreateCheckClass( |
398 to_check, cids, deopt_id, insert_before->token_pos()); | 379 to_check, cids, deopt_id, insert_before->token_pos()); |
399 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); | 380 InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect); |
400 } | 381 } |
401 | 382 |
402 | |
403 void JitOptimizer::AddChecksForArgNr(InstanceCallInstr* call, | 383 void JitOptimizer::AddChecksForArgNr(InstanceCallInstr* call, |
404 Definition* instr, | 384 Definition* instr, |
405 int argument_number) { | 385 int argument_number) { |
406 const Cids* cids = Cids::Create(Z, *call->ic_data(), argument_number); | 386 const Cids* cids = Cids::Create(Z, *call->ic_data(), argument_number); |
407 AddCheckClass(instr, *cids, call->deopt_id(), call->env(), call); | 387 AddCheckClass(instr, *cids, call->deopt_id(), call->env(), call); |
408 } | 388 } |
409 | 389 |
410 | |
411 static bool ArgIsAlways(intptr_t cid, | 390 static bool ArgIsAlways(intptr_t cid, |
412 const ICData& ic_data, | 391 const ICData& ic_data, |
413 intptr_t arg_number) { | 392 intptr_t arg_number) { |
414 ASSERT(ic_data.NumArgsTested() > arg_number); | 393 ASSERT(ic_data.NumArgsTested() > arg_number); |
415 if (ic_data.NumberOfUsedChecks() == 0) { | 394 if (ic_data.NumberOfUsedChecks() == 0) { |
416 return false; | 395 return false; |
417 } | 396 } |
418 const intptr_t num_checks = ic_data.NumberOfChecks(); | 397 const intptr_t num_checks = ic_data.NumberOfChecks(); |
419 for (intptr_t i = 0; i < num_checks; i++) { | 398 for (intptr_t i = 0; i < num_checks; i++) { |
420 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { | 399 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { |
421 return false; | 400 return false; |
422 } | 401 } |
423 } | 402 } |
424 return true; | 403 return true; |
425 } | 404 } |
426 | 405 |
427 | |
428 bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { | 406 bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { |
429 // Check for monomorphic IC data. | 407 // Check for monomorphic IC data. |
430 if (!call->HasICData()) return false; | 408 if (!call->HasICData()) return false; |
431 const ICData& ic_data = | 409 const ICData& ic_data = |
432 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); | 410 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); |
433 if (!ic_data.NumberOfChecksIs(1)) { | 411 if (!ic_data.NumberOfChecksIs(1)) { |
434 return false; | 412 return false; |
435 } | 413 } |
436 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | 414 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
437 flow_graph_, current_iterator(), call); | 415 flow_graph_, current_iterator(), call); |
438 } | 416 } |
439 | 417 |
440 | |
441 // Return true if d is a string of length one (a constant or result from | 418 // Return true if d is a string of length one (a constant or result from |
442 // from string-from-char-code instruction. | 419 // from string-from-char-code instruction. |
443 static bool IsLengthOneString(Definition* d) { | 420 static bool IsLengthOneString(Definition* d) { |
444 if (d->IsConstant()) { | 421 if (d->IsConstant()) { |
445 const Object& obj = d->AsConstant()->value(); | 422 const Object& obj = d->AsConstant()->value(); |
446 if (obj.IsString()) { | 423 if (obj.IsString()) { |
447 return String::Cast(obj).Length() == 1; | 424 return String::Cast(obj).Length() == 1; |
448 } else { | 425 } else { |
449 return false; | 426 return false; |
450 } | 427 } |
451 } else { | 428 } else { |
452 return d->IsOneByteStringFromCharCode(); | 429 return d->IsOneByteStringFromCharCode(); |
453 } | 430 } |
454 } | 431 } |
455 | 432 |
456 | |
457 // Returns true if the string comparison was converted into char-code | 433 // Returns true if the string comparison was converted into char-code |
458 // comparison. Conversion is only possible for strings of length one. | 434 // comparison. Conversion is only possible for strings of length one. |
459 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. | 435 // E.g., detect str[x] == "x"; and use an integer comparison of char-codes. |
460 // TODO(srdjan): Expand for two-byte and external strings. | 436 // TODO(srdjan): Expand for two-byte and external strings. |
461 bool JitOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, | 437 bool JitOptimizer::TryStringLengthOneEquality(InstanceCallInstr* call, |
462 Token::Kind op_kind) { | 438 Token::Kind op_kind) { |
463 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); | 439 ASSERT(HasOnlyTwoOf(*call->ic_data(), kOneByteStringCid)); |
464 // Check that left and right are length one strings (either string constants | 440 // Check that left and right are length one strings (either string constants |
465 // or results of string-from-char-code. | 441 // or results of string-from-char-code. |
466 Definition* left = call->ArgumentAt(0); | 442 Definition* left = call->ArgumentAt(0); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 if ((to_remove_right != NULL) && | 503 if ((to_remove_right != NULL) && |
528 (to_remove_right->input_use_list() == NULL)) { | 504 (to_remove_right->input_use_list() == NULL)) { |
529 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null()); | 505 to_remove_right->ReplaceUsesWith(flow_graph()->constant_null()); |
530 to_remove_right->RemoveFromGraph(); | 506 to_remove_right->RemoveFromGraph(); |
531 } | 507 } |
532 return true; | 508 return true; |
533 } | 509 } |
534 return false; | 510 return false; |
535 } | 511 } |
536 | 512 |
537 | |
538 static bool SmiFitsInDouble() { | 513 static bool SmiFitsInDouble() { |
539 return kSmiBits < 53; | 514 return kSmiBits < 53; |
540 } | 515 } |
541 | 516 |
542 bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, | 517 bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call, |
543 Token::Kind op_kind) { | 518 Token::Kind op_kind) { |
544 const ICData& ic_data = *call->ic_data(); | 519 const ICData& ic_data = *call->ic_data(); |
545 ASSERT(ic_data.NumArgsTested() == 2); | 520 ASSERT(ic_data.NumArgsTested() == 2); |
546 | 521 |
547 ASSERT(call->ArgumentCount() == 2); | 522 ASSERT(call->ArgumentCount() == 2); |
(...skipping 23 matching lines...) Expand all Loading... |
571 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { | 546 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { |
572 // Use double comparison. | 547 // Use double comparison. |
573 if (SmiFitsInDouble()) { | 548 if (SmiFitsInDouble()) { |
574 cid = kDoubleCid; | 549 cid = kDoubleCid; |
575 } else { | 550 } else { |
576 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | 551 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
577 // We cannot use double comparison on two smis. Need polymorphic | 552 // We cannot use double comparison on two smis. Need polymorphic |
578 // call. | 553 // call. |
579 return false; | 554 return false; |
580 } else { | 555 } else { |
581 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left), | 556 InsertBefore( |
582 new (Z) Value(right), | 557 call, |
583 call->deopt_id()), | 558 new (Z) CheckEitherNonSmiInstr( |
584 call->env(), FlowGraph::kEffect); | 559 new (Z) Value(left), new (Z) Value(right), call->deopt_id()), |
| 560 call->env(), FlowGraph::kEffect); |
585 cid = kDoubleCid; | 561 cid = kDoubleCid; |
586 } | 562 } |
587 } | 563 } |
588 } else { | 564 } else { |
589 // Check if ICDData contains checks with Smi/Null combinations. In that case | 565 // Check if ICDData contains checks with Smi/Null combinations. In that case |
590 // we can still emit the optimized Smi equality operation but need to add | 566 // we can still emit the optimized Smi equality operation but need to add |
591 // checks for null or Smi. | 567 // checks for null or Smi. |
592 GrowableArray<intptr_t> smi_or_null(2); | 568 GrowableArray<intptr_t> smi_or_null(2); |
593 smi_or_null.Add(kSmiCid); | 569 smi_or_null.Add(kSmiCid); |
594 smi_or_null.Add(kNullCid); | 570 smi_or_null.Add(kNullCid); |
(...skipping 19 matching lines...) Expand all Loading... |
614 } | 590 } |
615 } | 591 } |
616 ASSERT(cid != kIllegalCid); | 592 ASSERT(cid != kIllegalCid); |
617 EqualityCompareInstr* comp = new (Z) | 593 EqualityCompareInstr* comp = new (Z) |
618 EqualityCompareInstr(call->token_pos(), op_kind, new (Z) Value(left), | 594 EqualityCompareInstr(call->token_pos(), op_kind, new (Z) Value(left), |
619 new (Z) Value(right), cid, call->deopt_id()); | 595 new (Z) Value(right), cid, call->deopt_id()); |
620 ReplaceCall(call, comp); | 596 ReplaceCall(call, comp); |
621 return true; | 597 return true; |
622 } | 598 } |
623 | 599 |
624 | |
625 bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 600 bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
626 Token::Kind op_kind) { | 601 Token::Kind op_kind) { |
627 const ICData& ic_data = *call->ic_data(); | 602 const ICData& ic_data = *call->ic_data(); |
628 ASSERT(ic_data.NumArgsTested() == 2); | 603 ASSERT(ic_data.NumArgsTested() == 2); |
629 | 604 |
630 ASSERT(call->ArgumentCount() == 2); | 605 ASSERT(call->ArgumentCount() == 2); |
631 Definition* left = call->ArgumentAt(0); | 606 Definition* left = call->ArgumentAt(0); |
632 Definition* right = call->ArgumentAt(1); | 607 Definition* right = call->ArgumentAt(1); |
633 | 608 |
634 intptr_t cid = kIllegalCid; | 609 intptr_t cid = kIllegalCid; |
(...skipping 13 matching lines...) Expand all Loading... |
648 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { | 623 } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) { |
649 // Use double comparison. | 624 // Use double comparison. |
650 if (SmiFitsInDouble()) { | 625 if (SmiFitsInDouble()) { |
651 cid = kDoubleCid; | 626 cid = kDoubleCid; |
652 } else { | 627 } else { |
653 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { | 628 if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) { |
654 // We cannot use double comparison on two smis. Need polymorphic | 629 // We cannot use double comparison on two smis. Need polymorphic |
655 // call. | 630 // call. |
656 return false; | 631 return false; |
657 } else { | 632 } else { |
658 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left), | 633 InsertBefore( |
659 new (Z) Value(right), | 634 call, |
660 call->deopt_id()), | 635 new (Z) CheckEitherNonSmiInstr( |
661 call->env(), FlowGraph::kEffect); | 636 new (Z) Value(left), new (Z) Value(right), call->deopt_id()), |
| 637 call->env(), FlowGraph::kEffect); |
662 cid = kDoubleCid; | 638 cid = kDoubleCid; |
663 } | 639 } |
664 } | 640 } |
665 } else { | 641 } else { |
666 return false; | 642 return false; |
667 } | 643 } |
668 ASSERT(cid != kIllegalCid); | 644 ASSERT(cid != kIllegalCid); |
669 RelationalOpInstr* comp = | 645 RelationalOpInstr* comp = |
670 new (Z) RelationalOpInstr(call->token_pos(), op_kind, new (Z) Value(left), | 646 new (Z) RelationalOpInstr(call->token_pos(), op_kind, new (Z) Value(left), |
671 new (Z) Value(right), cid, call->deopt_id()); | 647 new (Z) Value(right), cid, call->deopt_id()); |
672 ReplaceCall(call, comp); | 648 ReplaceCall(call, comp); |
673 return true; | 649 return true; |
674 } | 650 } |
675 | 651 |
676 | |
677 bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, | 652 bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call, |
678 Token::Kind op_kind) { | 653 Token::Kind op_kind) { |
679 intptr_t operands_type = kIllegalCid; | 654 intptr_t operands_type = kIllegalCid; |
680 ASSERT(call->HasICData()); | 655 ASSERT(call->HasICData()); |
681 const ICData& ic_data = *call->ic_data(); | 656 const ICData& ic_data = *call->ic_data(); |
682 switch (op_kind) { | 657 switch (op_kind) { |
683 case Token::kADD: | 658 case Token::kADD: |
684 case Token::kSUB: | 659 case Token::kSUB: |
685 case Token::kMUL: | 660 case Token::kMUL: |
686 if (HasOnlyTwoOf(ic_data, kSmiCid)) { | 661 if (HasOnlyTwoOf(ic_data, kSmiCid)) { |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
780 Definition* left = call->ArgumentAt(0); | 755 Definition* left = call->ArgumentAt(0); |
781 Definition* right = call->ArgumentAt(1); | 756 Definition* right = call->ArgumentAt(1); |
782 if (operands_type == kDoubleCid) { | 757 if (operands_type == kDoubleCid) { |
783 if (!CanUnboxDouble()) { | 758 if (!CanUnboxDouble()) { |
784 return false; | 759 return false; |
785 } | 760 } |
786 // Check that either left or right are not a smi. Result of a | 761 // Check that either left or right are not a smi. Result of a |
787 // binary operation with two smis is a smi not a double, except '/' which | 762 // binary operation with two smis is a smi not a double, except '/' which |
788 // returns a double for two smis. | 763 // returns a double for two smis. |
789 if (op_kind != Token::kDIV) { | 764 if (op_kind != Token::kDIV) { |
790 InsertBefore(call, new (Z) CheckEitherNonSmiInstr(new (Z) Value(left), | 765 InsertBefore( |
791 new (Z) Value(right), | 766 call, |
792 call->deopt_id()), | 767 new (Z) CheckEitherNonSmiInstr( |
793 call->env(), FlowGraph::kEffect); | 768 new (Z) Value(left), new (Z) Value(right), call->deopt_id()), |
| 769 call->env(), FlowGraph::kEffect); |
794 } | 770 } |
795 | 771 |
796 BinaryDoubleOpInstr* double_bin_op = new (Z) | 772 BinaryDoubleOpInstr* double_bin_op = new (Z) |
797 BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right), | 773 BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right), |
798 call->deopt_id(), call->token_pos()); | 774 call->deopt_id(), call->token_pos()); |
799 ReplaceCall(call, double_bin_op); | 775 ReplaceCall(call, double_bin_op); |
800 } else if (operands_type == kMintCid) { | 776 } else if (operands_type == kMintCid) { |
801 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; | 777 if (!FlowGraphCompiler::SupportsUnboxedMints()) return false; |
802 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { | 778 if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) { |
803 ShiftMintOpInstr* shift_op = new (Z) ShiftMintOpInstr( | 779 ShiftMintOpInstr* shift_op = new (Z) ShiftMintOpInstr( |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
854 left = right; | 830 left = right; |
855 right = temp; | 831 right = temp; |
856 } | 832 } |
857 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr( | 833 BinarySmiOpInstr* bin_op = new (Z) BinarySmiOpInstr( |
858 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 834 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
859 ReplaceCall(call, bin_op); | 835 ReplaceCall(call, bin_op); |
860 } | 836 } |
861 return true; | 837 return true; |
862 } | 838 } |
863 | 839 |
864 | |
865 bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, | 840 bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call, |
866 Token::Kind op_kind) { | 841 Token::Kind op_kind) { |
867 ASSERT(call->ArgumentCount() == 1); | 842 ASSERT(call->ArgumentCount() == 1); |
868 Definition* input = call->ArgumentAt(0); | 843 Definition* input = call->ArgumentAt(0); |
869 Definition* unary_op = NULL; | 844 Definition* unary_op = NULL; |
870 if (HasOnlyOneSmi(*call->ic_data())) { | 845 if (HasOnlyOneSmi(*call->ic_data())) { |
871 InsertBefore(call, | 846 InsertBefore(call, |
872 new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(), | 847 new (Z) CheckSmiInstr(new (Z) Value(input), call->deopt_id(), |
873 call->token_pos()), | 848 call->token_pos()), |
874 call->env(), FlowGraph::kEffect); | 849 call->env(), FlowGraph::kEffect); |
(...skipping 10 matching lines...) Expand all Loading... |
885 unary_op = new (Z) UnaryDoubleOpInstr(Token::kNEGATE, new (Z) Value(input), | 860 unary_op = new (Z) UnaryDoubleOpInstr(Token::kNEGATE, new (Z) Value(input), |
886 call->deopt_id()); | 861 call->deopt_id()); |
887 } else { | 862 } else { |
888 return false; | 863 return false; |
889 } | 864 } |
890 ASSERT(unary_op != NULL); | 865 ASSERT(unary_op != NULL); |
891 ReplaceCall(call, unary_op); | 866 ReplaceCall(call, unary_op); |
892 return true; | 867 return true; |
893 } | 868 } |
894 | 869 |
895 | |
896 // Using field class. | 870 // Using field class. |
897 RawField* JitOptimizer::GetField(intptr_t class_id, const String& field_name) { | 871 RawField* JitOptimizer::GetField(intptr_t class_id, const String& field_name) { |
898 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); | 872 Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id)); |
899 Field& field = Field::Handle(Z); | 873 Field& field = Field::Handle(Z); |
900 while (!cls.IsNull()) { | 874 while (!cls.IsNull()) { |
901 field = cls.LookupInstanceField(field_name); | 875 field = cls.LookupInstanceField(field_name); |
902 if (!field.IsNull()) { | 876 if (!field.IsNull()) { |
903 if (Compiler::IsBackgroundCompilation() || | 877 if (Compiler::IsBackgroundCompilation() || |
904 FLAG_force_clone_compiler_objects) { | 878 FLAG_force_clone_compiler_objects) { |
905 return field.CloneFromOriginal(); | 879 return field.CloneFromOriginal(); |
906 } else { | 880 } else { |
907 return field.raw(); | 881 return field.raw(); |
908 } | 882 } |
909 } | 883 } |
910 cls = cls.SuperClass(); | 884 cls = cls.SuperClass(); |
911 } | 885 } |
912 return Field::null(); | 886 return Field::null(); |
913 } | 887 } |
914 | 888 |
915 | |
916 bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { | 889 bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) { |
917 ASSERT(call->HasICData()); | 890 ASSERT(call->HasICData()); |
918 const ICData& ic_data = *call->ic_data(); | 891 const ICData& ic_data = *call->ic_data(); |
919 ASSERT(ic_data.HasOneTarget()); | 892 ASSERT(ic_data.HasOneTarget()); |
920 GrowableArray<intptr_t> class_ids; | 893 GrowableArray<intptr_t> class_ids; |
921 ic_data.GetClassIdsAt(0, &class_ids); | 894 ic_data.GetClassIdsAt(0, &class_ids); |
922 ASSERT(class_ids.length() == 1); | 895 ASSERT(class_ids.length() == 1); |
923 // Inline implicit instance getter. | 896 // Inline implicit instance getter. |
924 const String& field_name = | 897 const String& field_name = |
925 String::Handle(Z, Field::NameFromGetter(call->function_name())); | 898 String::Handle(Z, Field::NameFromGetter(call->function_name())); |
(...skipping 17 matching lines...) Expand all Loading... |
943 | 916 |
944 if (load->result_cid() != kDynamicCid) { | 917 if (load->result_cid() != kDynamicCid) { |
945 // Reset value types if guarded_cid was used. | 918 // Reset value types if guarded_cid was used. |
946 for (Value::Iterator it(load->input_use_list()); !it.Done(); it.Advance()) { | 919 for (Value::Iterator it(load->input_use_list()); !it.Done(); it.Advance()) { |
947 it.Current()->SetReachingType(NULL); | 920 it.Current()->SetReachingType(NULL); |
948 } | 921 } |
949 } | 922 } |
950 return true; | 923 return true; |
951 } | 924 } |
952 | 925 |
953 | |
954 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, | 926 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call, |
955 Token::Kind op_kind) { | 927 Token::Kind op_kind) { |
956 if (!ShouldInlineSimd()) { | 928 if (!ShouldInlineSimd()) { |
957 return false; | 929 return false; |
958 } | 930 } |
959 ASSERT(call->ArgumentCount() == 2); | 931 ASSERT(call->ArgumentCount() == 2); |
960 Definition* left = call->ArgumentAt(0); | 932 Definition* left = call->ArgumentAt(0); |
961 Definition* right = call->ArgumentAt(1); | 933 Definition* right = call->ArgumentAt(1); |
962 // Type check left and right. | 934 // Type check left and right. |
963 AddChecksForArgNr(call, left, 0); | 935 AddChecksForArgNr(call, left, 0); |
964 AddChecksForArgNr(call, right, 1); | 936 AddChecksForArgNr(call, right, 1); |
965 // Replace call. | 937 // Replace call. |
966 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr( | 938 BinaryFloat32x4OpInstr* float32x4_bin_op = new (Z) BinaryFloat32x4OpInstr( |
967 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 939 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
968 ReplaceCall(call, float32x4_bin_op); | 940 ReplaceCall(call, float32x4_bin_op); |
969 | 941 |
970 return true; | 942 return true; |
971 } | 943 } |
972 | 944 |
973 | |
974 bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, | 945 bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call, |
975 Token::Kind op_kind) { | 946 Token::Kind op_kind) { |
976 if (!ShouldInlineSimd()) { | 947 if (!ShouldInlineSimd()) { |
977 return false; | 948 return false; |
978 } | 949 } |
979 ASSERT(call->ArgumentCount() == 2); | 950 ASSERT(call->ArgumentCount() == 2); |
980 Definition* left = call->ArgumentAt(0); | 951 Definition* left = call->ArgumentAt(0); |
981 Definition* right = call->ArgumentAt(1); | 952 Definition* right = call->ArgumentAt(1); |
982 // Type check left and right. | 953 // Type check left and right. |
983 AddChecksForArgNr(call, left, 0); | 954 AddChecksForArgNr(call, left, 0); |
984 AddChecksForArgNr(call, right, 1); | 955 AddChecksForArgNr(call, right, 1); |
985 // Replace call. | 956 // Replace call. |
986 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr( | 957 BinaryInt32x4OpInstr* int32x4_bin_op = new (Z) BinaryInt32x4OpInstr( |
987 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 958 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
988 ReplaceCall(call, int32x4_bin_op); | 959 ReplaceCall(call, int32x4_bin_op); |
989 return true; | 960 return true; |
990 } | 961 } |
991 | 962 |
992 | |
993 bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, | 963 bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call, |
994 Token::Kind op_kind) { | 964 Token::Kind op_kind) { |
995 if (!ShouldInlineSimd()) { | 965 if (!ShouldInlineSimd()) { |
996 return false; | 966 return false; |
997 } | 967 } |
998 ASSERT(call->ArgumentCount() == 2); | 968 ASSERT(call->ArgumentCount() == 2); |
999 Definition* left = call->ArgumentAt(0); | 969 Definition* left = call->ArgumentAt(0); |
1000 Definition* right = call->ArgumentAt(1); | 970 Definition* right = call->ArgumentAt(1); |
1001 // Type check left and right. | 971 // Type check left and right. |
1002 AddChecksForArgNr(call, left, 0); | 972 AddChecksForArgNr(call, left, 0); |
1003 AddChecksForArgNr(call, right, 1); | 973 AddChecksForArgNr(call, right, 1); |
1004 // Replace call. | 974 // Replace call. |
1005 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr( | 975 BinaryFloat64x2OpInstr* float64x2_bin_op = new (Z) BinaryFloat64x2OpInstr( |
1006 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); | 976 op_kind, new (Z) Value(left), new (Z) Value(right), call->deopt_id()); |
1007 ReplaceCall(call, float64x2_bin_op); | 977 ReplaceCall(call, float64x2_bin_op); |
1008 return true; | 978 return true; |
1009 } | 979 } |
1010 | 980 |
1011 | |
1012 // Only unique implicit instance getters can be currently handled. | 981 // Only unique implicit instance getters can be currently handled. |
1013 bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { | 982 bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) { |
1014 ASSERT(call->HasICData()); | 983 ASSERT(call->HasICData()); |
1015 const ICData& ic_data = *call->ic_data(); | 984 const ICData& ic_data = *call->ic_data(); |
1016 if (ic_data.NumberOfUsedChecks() == 0) { | 985 if (ic_data.NumberOfUsedChecks() == 0) { |
1017 // No type feedback collected. | 986 // No type feedback collected. |
1018 return false; | 987 return false; |
1019 } | 988 } |
1020 | 989 |
1021 if (!ic_data.HasOneTarget()) { | 990 if (!ic_data.HasOneTarget()) { |
1022 // Polymorphic sites are inlined like normal methods by conventional | 991 // Polymorphic sites are inlined like normal methods by conventional |
1023 // inlining in FlowGraphInliner. | 992 // inlining in FlowGraphInliner. |
1024 return false; | 993 return false; |
1025 } | 994 } |
1026 | 995 |
1027 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); | 996 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); |
1028 if (target.kind() != RawFunction::kImplicitGetter) { | 997 if (target.kind() != RawFunction::kImplicitGetter) { |
1029 // Non-implicit getters are inlined like normal methods by conventional | 998 // Non-implicit getters are inlined like normal methods by conventional |
1030 // inlining in FlowGraphInliner. | 999 // inlining in FlowGraphInliner. |
1031 return false; | 1000 return false; |
1032 } | 1001 } |
1033 return InlineImplicitInstanceGetter(call); | 1002 return InlineImplicitInstanceGetter(call); |
1034 } | 1003 } |
1035 | 1004 |
1036 | |
1037 void JitOptimizer::ReplaceWithMathCFunction( | 1005 void JitOptimizer::ReplaceWithMathCFunction( |
1038 InstanceCallInstr* call, | 1006 InstanceCallInstr* call, |
1039 MethodRecognizer::Kind recognized_kind) { | 1007 MethodRecognizer::Kind recognized_kind) { |
1040 AddReceiverCheck(call); | 1008 AddReceiverCheck(call); |
1041 ZoneGrowableArray<Value*>* args = | 1009 ZoneGrowableArray<Value*>* args = |
1042 new (Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 1010 new (Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
1043 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 1011 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
1044 args->Add(new (Z) Value(call->ArgumentAt(i))); | 1012 args->Add(new (Z) Value(call->ArgumentAt(i))); |
1045 } | 1013 } |
1046 InvokeMathCFunctionInstr* invoke = new (Z) InvokeMathCFunctionInstr( | 1014 InvokeMathCFunctionInstr* invoke = new (Z) InvokeMathCFunctionInstr( |
1047 args, call->deopt_id(), recognized_kind, call->token_pos()); | 1015 args, call->deopt_id(), recognized_kind, call->token_pos()); |
1048 ReplaceCall(call, invoke); | 1016 ReplaceCall(call, invoke); |
1049 } | 1017 } |
1050 | 1018 |
1051 | |
1052 // Inline only simple, frequently called core library methods. | 1019 // Inline only simple, frequently called core library methods. |
1053 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | 1020 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { |
1054 ASSERT(call->HasICData()); | 1021 ASSERT(call->HasICData()); |
1055 const ICData& ic_data = *call->ic_data(); | 1022 const ICData& ic_data = *call->ic_data(); |
1056 if (ic_data.NumberOfUsedChecks() != 1) { | 1023 if (ic_data.NumberOfUsedChecks() != 1) { |
1057 // No type feedback collected or multiple targets found. | 1024 // No type feedback collected or multiple targets found. |
1058 return false; | 1025 return false; |
1059 } | 1026 } |
1060 | 1027 |
1061 Function& target = Function::Handle(Z); | 1028 Function& target = Function::Handle(Z); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1122 return true; | 1089 return true; |
1123 default: | 1090 default: |
1124 break; | 1091 break; |
1125 } | 1092 } |
1126 } | 1093 } |
1127 | 1094 |
1128 return FlowGraphInliner::TryReplaceInstanceCallWithInline( | 1095 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
1129 flow_graph_, current_iterator(), call); | 1096 flow_graph_, current_iterator(), call); |
1130 } | 1097 } |
1131 | 1098 |
1132 | |
1133 // If type tests specified by 'ic_data' do not depend on type arguments, | 1099 // If type tests specified by 'ic_data' do not depend on type arguments, |
1134 // return mapping cid->result in 'results' (i : cid; i + 1: result). | 1100 // return mapping cid->result in 'results' (i : cid; i + 1: result). |
1135 // If all tests yield the same result, return it otherwise return Bool::null. | 1101 // If all tests yield the same result, return it otherwise return Bool::null. |
1136 // If no mapping is possible, 'results' is empty. | 1102 // If no mapping is possible, 'results' is empty. |
1137 // An instance-of test returning all same results can be converted to a class | 1103 // An instance-of test returning all same results can be converted to a class |
1138 // check. | 1104 // check. |
1139 RawBool* JitOptimizer::InstanceOfAsBool( | 1105 RawBool* JitOptimizer::InstanceOfAsBool( |
1140 const ICData& ic_data, | 1106 const ICData& ic_data, |
1141 const AbstractType& type, | 1107 const AbstractType& type, |
1142 ZoneGrowableArray<intptr_t>* results) const { | 1108 ZoneGrowableArray<intptr_t>* results) const { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1190 prev = Bool::Get(is_subtype).raw(); | 1156 prev = Bool::Get(is_subtype).raw(); |
1191 } else { | 1157 } else { |
1192 if (is_subtype != prev.value()) { | 1158 if (is_subtype != prev.value()) { |
1193 results_differ = true; | 1159 results_differ = true; |
1194 } | 1160 } |
1195 } | 1161 } |
1196 } | 1162 } |
1197 return results_differ ? Bool::null() : prev.raw(); | 1163 return results_differ ? Bool::null() : prev.raw(); |
1198 } | 1164 } |
1199 | 1165 |
1200 | |
1201 // Returns true if checking against this type is a direct class id comparison. | 1166 // Returns true if checking against this type is a direct class id comparison. |
1202 bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { | 1167 bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) { |
1203 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 1168 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
1204 // Requires CHA. | 1169 // Requires CHA. |
1205 if (!type.IsInstantiated()) return false; | 1170 if (!type.IsInstantiated()) return false; |
1206 // Function types have different type checking rules. | 1171 // Function types have different type checking rules. |
1207 if (type.IsFunctionType()) return false; | 1172 if (type.IsFunctionType()) return false; |
1208 const Class& type_class = Class::Handle(type.type_class()); | 1173 const Class& type_class = Class::Handle(type.type_class()); |
1209 // Could be an interface check? | 1174 // Could be an interface check? |
1210 if (CHA::IsImplemented(type_class)) return false; | 1175 if (CHA::IsImplemented(type_class)) return false; |
(...skipping 26 matching lines...) Expand all Loading... |
1237 const intptr_t from_index = num_type_args - num_type_params; | 1202 const intptr_t from_index = num_type_args - num_type_params; |
1238 const TypeArguments& type_arguments = | 1203 const TypeArguments& type_arguments = |
1239 TypeArguments::Handle(type.arguments()); | 1204 TypeArguments::Handle(type.arguments()); |
1240 const bool is_raw_type = type_arguments.IsNull() || | 1205 const bool is_raw_type = type_arguments.IsNull() || |
1241 type_arguments.IsRaw(from_index, num_type_params); | 1206 type_arguments.IsRaw(from_index, num_type_params); |
1242 return is_raw_type; | 1207 return is_raw_type; |
1243 } | 1208 } |
1244 return true; | 1209 return true; |
1245 } | 1210 } |
1246 | 1211 |
1247 | |
1248 // TODO(srdjan): Use ICData to check if always true or false. | 1212 // TODO(srdjan): Use ICData to check if always true or false. |
1249 void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { | 1213 void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) { |
1250 ASSERT(Token::IsTypeTestOperator(call->token_kind())); | 1214 ASSERT(Token::IsTypeTestOperator(call->token_kind())); |
1251 Definition* left = call->ArgumentAt(0); | 1215 Definition* left = call->ArgumentAt(0); |
1252 Definition* instantiator_type_args = NULL; | 1216 Definition* instantiator_type_args = NULL; |
1253 Definition* function_type_args = NULL; | 1217 Definition* function_type_args = NULL; |
1254 AbstractType& type = AbstractType::ZoneHandle(Z); | 1218 AbstractType& type = AbstractType::ZoneHandle(Z); |
1255 if (call->ArgumentCount() == 2) { | 1219 if (call->ArgumentCount() == 2) { |
1256 instantiator_type_args = flow_graph()->constant_null(); | 1220 instantiator_type_args = flow_graph()->constant_null(); |
1257 function_type_args = flow_graph()->constant_null(); | 1221 function_type_args = flow_graph()->constant_null(); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1314 } | 1278 } |
1315 } | 1279 } |
1316 | 1280 |
1317 InstanceOfInstr* instance_of = new (Z) InstanceOfInstr( | 1281 InstanceOfInstr* instance_of = new (Z) InstanceOfInstr( |
1318 call->token_pos(), new (Z) Value(left), | 1282 call->token_pos(), new (Z) Value(left), |
1319 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), | 1283 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), |
1320 type, call->deopt_id()); | 1284 type, call->deopt_id()); |
1321 ReplaceCall(call, instance_of); | 1285 ReplaceCall(call, instance_of); |
1322 } | 1286 } |
1323 | 1287 |
1324 | |
1325 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). | 1288 // TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids). |
1326 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { | 1289 void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) { |
1327 ASSERT(Token::IsTypeCastOperator(call->token_kind())); | 1290 ASSERT(Token::IsTypeCastOperator(call->token_kind())); |
1328 Definition* left = call->ArgumentAt(0); | 1291 Definition* left = call->ArgumentAt(0); |
1329 Definition* instantiator_type_args = call->ArgumentAt(1); | 1292 Definition* instantiator_type_args = call->ArgumentAt(1); |
1330 Definition* function_type_args = call->ArgumentAt(2); | 1293 Definition* function_type_args = call->ArgumentAt(2); |
1331 const AbstractType& type = | 1294 const AbstractType& type = |
1332 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); | 1295 AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()); |
1333 ASSERT(!type.IsMalformedOrMalbounded()); | 1296 ASSERT(!type.IsMalformedOrMalbounded()); |
1334 const ICData& unary_checks = | 1297 const ICData& unary_checks = |
(...skipping 20 matching lines...) Expand all Loading... |
1355 return; | 1318 return; |
1356 } | 1319 } |
1357 } | 1320 } |
1358 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr( | 1321 AssertAssignableInstr* assert_as = new (Z) AssertAssignableInstr( |
1359 call->token_pos(), new (Z) Value(left), | 1322 call->token_pos(), new (Z) Value(left), |
1360 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), | 1323 new (Z) Value(instantiator_type_args), new (Z) Value(function_type_args), |
1361 type, Symbols::InTypeCast(), call->deopt_id()); | 1324 type, Symbols::InTypeCast(), call->deopt_id()); |
1362 ReplaceCall(call, assert_as); | 1325 ReplaceCall(call, assert_as); |
1363 } | 1326 } |
1364 | 1327 |
1365 | |
1366 // Tries to optimize instance call by replacing it with a faster instruction | 1328 // Tries to optimize instance call by replacing it with a faster instruction |
1367 // (e.g, binary op, field load, ..). | 1329 // (e.g, binary op, field load, ..). |
1368 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 1330 void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
1369 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { | 1331 if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) { |
1370 return; | 1332 return; |
1371 } | 1333 } |
1372 const Token::Kind op_kind = instr->token_kind(); | 1334 const Token::Kind op_kind = instr->token_kind(); |
1373 | 1335 |
1374 // Type test is special as it always gets converted into inlined code. | 1336 // Type test is special as it always gets converted into inlined code. |
1375 if (Token::IsTypeTestOperator(op_kind)) { | 1337 if (Token::IsTypeTestOperator(op_kind)) { |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1472 StaticCallInstr* call = StaticCallInstr::FromCall(Z, instr, target); | 1434 StaticCallInstr* call = StaticCallInstr::FromCall(Z, instr, target); |
1473 instr->ReplaceWith(call, current_iterator()); | 1435 instr->ReplaceWith(call, current_iterator()); |
1474 } else { | 1436 } else { |
1475 PolymorphicInstanceCallInstr* call = | 1437 PolymorphicInstanceCallInstr* call = |
1476 new (Z) PolymorphicInstanceCallInstr(instr, targets, | 1438 new (Z) PolymorphicInstanceCallInstr(instr, targets, |
1477 /* complete = */ false); | 1439 /* complete = */ false); |
1478 instr->ReplaceWith(call, current_iterator()); | 1440 instr->ReplaceWith(call, current_iterator()); |
1479 } | 1441 } |
1480 } | 1442 } |
1481 | 1443 |
1482 | |
1483 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { | 1444 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) { |
1484 MethodRecognizer::Kind recognized_kind = | 1445 MethodRecognizer::Kind recognized_kind = |
1485 MethodRecognizer::RecognizeKind(call->function()); | 1446 MethodRecognizer::RecognizeKind(call->function()); |
1486 switch (recognized_kind) { | 1447 switch (recognized_kind) { |
1487 case MethodRecognizer::kObjectConstructor: | 1448 case MethodRecognizer::kObjectConstructor: |
1488 case MethodRecognizer::kObjectArrayAllocate: | 1449 case MethodRecognizer::kObjectArrayAllocate: |
1489 case MethodRecognizer::kFloat32x4Zero: | 1450 case MethodRecognizer::kFloat32x4Zero: |
1490 case MethodRecognizer::kFloat32x4Splat: | 1451 case MethodRecognizer::kFloat32x4Splat: |
1491 case MethodRecognizer::kFloat32x4Constructor: | 1452 case MethodRecognizer::kFloat32x4Constructor: |
1492 case MethodRecognizer::kFloat32x4FromFloat64x2: | 1453 case MethodRecognizer::kFloat32x4FromFloat64x2: |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1555 } | 1516 } |
1556 } | 1517 } |
1557 } | 1518 } |
1558 break; | 1519 break; |
1559 } | 1520 } |
1560 default: | 1521 default: |
1561 break; | 1522 break; |
1562 } | 1523 } |
1563 } | 1524 } |
1564 | 1525 |
1565 | |
1566 void JitOptimizer::VisitStoreInstanceField(StoreInstanceFieldInstr* instr) { | 1526 void JitOptimizer::VisitStoreInstanceField(StoreInstanceFieldInstr* instr) { |
1567 if (instr->IsUnboxedStore()) { | 1527 if (instr->IsUnboxedStore()) { |
1568 // Determine if this field should be unboxed based on the usage of getter | 1528 // Determine if this field should be unboxed based on the usage of getter |
1569 // and setter functions: The heuristic requires that the setter has a | 1529 // and setter functions: The heuristic requires that the setter has a |
1570 // usage count of at least 1/kGetterSetterRatio of the getter usage count. | 1530 // usage count of at least 1/kGetterSetterRatio of the getter usage count. |
1571 // This is to avoid unboxing fields where the setter is never or rarely | 1531 // This is to avoid unboxing fields where the setter is never or rarely |
1572 // executed. | 1532 // executed. |
1573 const Field& field = instr->field(); | 1533 const Field& field = instr->field(); |
1574 const String& field_name = String::Handle(Z, field.name()); | 1534 const String& field_name = String::Handle(Z, field.name()); |
1575 const Class& owner = Class::Handle(Z, field.Owner()); | 1535 const Class& owner = Class::Handle(Z, field.Owner()); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1609 } | 1569 } |
1610 ASSERT(field.IsOriginal()); | 1570 ASSERT(field.IsOriginal()); |
1611 field.set_is_unboxing_candidate(false); | 1571 field.set_is_unboxing_candidate(false); |
1612 field.DeoptimizeDependentCode(); | 1572 field.DeoptimizeDependentCode(); |
1613 } else { | 1573 } else { |
1614 flow_graph()->parsed_function().AddToGuardedFields(&field); | 1574 flow_graph()->parsed_function().AddToGuardedFields(&field); |
1615 } | 1575 } |
1616 } | 1576 } |
1617 } | 1577 } |
1618 | 1578 |
1619 | |
1620 void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { | 1579 void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) { |
1621 // Replace generic allocation with a sequence of inlined allocation and | 1580 // Replace generic allocation with a sequence of inlined allocation and |
1622 // explicit initializing stores. | 1581 // explicit initializing stores. |
1623 AllocateUninitializedContextInstr* replacement = | 1582 AllocateUninitializedContextInstr* replacement = |
1624 new AllocateUninitializedContextInstr(instr->token_pos(), | 1583 new AllocateUninitializedContextInstr(instr->token_pos(), |
1625 instr->num_context_variables()); | 1584 instr->num_context_variables()); |
1626 instr->ReplaceWith(replacement, current_iterator()); | 1585 instr->ReplaceWith(replacement, current_iterator()); |
1627 | 1586 |
1628 StoreInstanceFieldInstr* store = new (Z) | 1587 StoreInstanceFieldInstr* store = new (Z) |
1629 StoreInstanceFieldInstr(Context::parent_offset(), new Value(replacement), | 1588 StoreInstanceFieldInstr(Context::parent_offset(), new Value(replacement), |
(...skipping 10 matching lines...) Expand all Loading... |
1640 new Value(flow_graph_->constant_null()), kNoStoreBarrier, | 1599 new Value(flow_graph_->constant_null()), kNoStoreBarrier, |
1641 instr->token_pos()); | 1600 instr->token_pos()); |
1642 // Storing into uninitialized memory; remember to prevent dead store | 1601 // Storing into uninitialized memory; remember to prevent dead store |
1643 // elimination and ensure proper GC barrier. | 1602 // elimination and ensure proper GC barrier. |
1644 store->set_is_initialization(true); | 1603 store->set_is_initialization(true); |
1645 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); | 1604 flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect); |
1646 cursor = store; | 1605 cursor = store; |
1647 } | 1606 } |
1648 } | 1607 } |
1649 | 1608 |
1650 | |
1651 void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { | 1609 void JitOptimizer::VisitLoadCodeUnits(LoadCodeUnitsInstr* instr) { |
1652 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. | 1610 // TODO(zerny): Use kUnboxedUint32 once it is fully supported/optimized. |
1653 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) | 1611 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) |
1654 if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedMint); | 1612 if (!instr->can_pack_into_smi()) instr->set_representation(kUnboxedMint); |
1655 #endif | 1613 #endif |
1656 } | 1614 } |
1657 | 1615 |
1658 | |
1659 bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, | 1616 bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr, |
1660 const ICData& unary_ic_data) { | 1617 const ICData& unary_ic_data) { |
1661 ASSERT(!unary_ic_data.NumberOfChecksIs(0) && | 1618 ASSERT(!unary_ic_data.NumberOfChecksIs(0) && |
1662 (unary_ic_data.NumArgsTested() == 1)); | 1619 (unary_ic_data.NumArgsTested() == 1)); |
1663 if (I->type_checks()) { | 1620 if (I->type_checks()) { |
1664 // Checked mode setters are inlined like normal methods by conventional | 1621 // Checked mode setters are inlined like normal methods by conventional |
1665 // inlining. | 1622 // inlining. |
1666 return false; | 1623 return false; |
1667 } | 1624 } |
1668 | 1625 |
(...skipping 19 matching lines...) Expand all Loading... |
1688 String::Handle(Z, Field::NameFromSetter(instr->function_name())); | 1645 String::Handle(Z, Field::NameFromSetter(instr->function_name())); |
1689 const Field& field = Field::ZoneHandle(Z, GetField(class_id, field_name)); | 1646 const Field& field = Field::ZoneHandle(Z, GetField(class_id, field_name)); |
1690 ASSERT(!field.IsNull()); | 1647 ASSERT(!field.IsNull()); |
1691 | 1648 |
1692 if (flow_graph()->InstanceCallNeedsClassCheck(instr, | 1649 if (flow_graph()->InstanceCallNeedsClassCheck(instr, |
1693 RawFunction::kImplicitSetter)) { | 1650 RawFunction::kImplicitSetter)) { |
1694 AddReceiverCheck(instr); | 1651 AddReceiverCheck(instr); |
1695 } | 1652 } |
1696 if (field.guarded_cid() != kDynamicCid) { | 1653 if (field.guarded_cid() != kDynamicCid) { |
1697 ASSERT(I->use_field_guards()); | 1654 ASSERT(I->use_field_guards()); |
1698 InsertBefore( | 1655 InsertBefore(instr, |
1699 instr, new (Z) GuardFieldClassInstr(new (Z) Value(instr->ArgumentAt(1)), | 1656 new (Z) |
1700 field, instr->deopt_id()), | 1657 GuardFieldClassInstr(new (Z) Value(instr->ArgumentAt(1)), |
1701 instr->env(), FlowGraph::kEffect); | 1658 field, instr->deopt_id()), |
| 1659 instr->env(), FlowGraph::kEffect); |
1702 } | 1660 } |
1703 | 1661 |
1704 if (field.needs_length_check()) { | 1662 if (field.needs_length_check()) { |
1705 ASSERT(I->use_field_guards()); | 1663 ASSERT(I->use_field_guards()); |
1706 InsertBefore(instr, new (Z) GuardFieldLengthInstr( | 1664 InsertBefore(instr, |
1707 new (Z) Value(instr->ArgumentAt(1)), field, | 1665 new (Z) |
1708 instr->deopt_id()), | 1666 GuardFieldLengthInstr(new (Z) Value(instr->ArgumentAt(1)), |
| 1667 field, instr->deopt_id()), |
1709 instr->env(), FlowGraph::kEffect); | 1668 instr->env(), FlowGraph::kEffect); |
1710 } | 1669 } |
1711 | 1670 |
1712 // Field guard was detached. | 1671 // Field guard was detached. |
1713 StoreInstanceFieldInstr* store = new (Z) | 1672 StoreInstanceFieldInstr* store = new (Z) |
1714 StoreInstanceFieldInstr(field, new (Z) Value(instr->ArgumentAt(0)), | 1673 StoreInstanceFieldInstr(field, new (Z) Value(instr->ArgumentAt(0)), |
1715 new (Z) Value(instr->ArgumentAt(1)), | 1674 new (Z) Value(instr->ArgumentAt(1)), |
1716 kEmitStoreBarrier, instr->token_pos()); | 1675 kEmitStoreBarrier, instr->token_pos()); |
1717 | 1676 |
1718 if (store->IsUnboxedStore()) { | 1677 if (store->IsUnboxedStore()) { |
1719 flow_graph()->parsed_function().AddToGuardedFields(&field); | 1678 flow_graph()->parsed_function().AddToGuardedFields(&field); |
1720 } | 1679 } |
1721 | 1680 |
1722 // Discard the environment from the original instruction because the store | 1681 // Discard the environment from the original instruction because the store |
1723 // can't deoptimize. | 1682 // can't deoptimize. |
1724 instr->RemoveEnvironment(); | 1683 instr->RemoveEnvironment(); |
1725 ReplaceCall(instr, store); | 1684 ReplaceCall(instr, store); |
1726 return true; | 1685 return true; |
1727 } | 1686 } |
1728 | 1687 |
1729 | |
1730 } // namespace dart | 1688 } // namespace dart |
1731 #endif // DART_PRECOMPILED_RUNTIME | 1689 #endif // DART_PRECOMPILED_RUNTIME |
OLD | NEW |