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/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
6 | 6 |
7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
8 #include "vm/bootstrap.h" | 8 #include "vm/bootstrap.h" |
9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
10 #include "vm/constant_propagator.h" | 10 #include "vm/constant_propagator.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "vm/regexp_assembler_ir.h" | 22 #include "vm/regexp_assembler_ir.h" |
23 #include "vm/resolver.h" | 23 #include "vm/resolver.h" |
24 #include "vm/scopes.h" | 24 #include "vm/scopes.h" |
25 #include "vm/stub_code.h" | 25 #include "vm/stub_code.h" |
26 #include "vm/symbols.h" | 26 #include "vm/symbols.h" |
27 | 27 |
28 #include "vm/il_printer.h" | 28 #include "vm/il_printer.h" |
29 | 29 |
30 namespace dart { | 30 namespace dart { |
31 | 31 |
32 DEFINE_FLAG(bool, propagate_ic_data, true, | 32 DEFINE_FLAG(bool, |
33 "Propagate IC data from unoptimized to optimized IC calls."); | 33 propagate_ic_data, |
34 DEFINE_FLAG(bool, two_args_smi_icd, true, | 34 true, |
35 "Generate special IC stubs for two args Smi operations"); | 35 "Propagate IC data from unoptimized to optimized IC calls."); |
36 DEFINE_FLAG(bool, unbox_numeric_fields, !USING_DBC, | 36 DEFINE_FLAG(bool, |
37 "Support unboxed double and float32x4 fields."); | 37 two_args_smi_icd, |
| 38 true, |
| 39 "Generate special IC stubs for two args Smi operations"); |
| 40 DEFINE_FLAG(bool, |
| 41 unbox_numeric_fields, |
| 42 !USING_DBC, |
| 43 "Support unboxed double and float32x4 fields."); |
38 DECLARE_FLAG(bool, eliminate_type_checks); | 44 DECLARE_FLAG(bool, eliminate_type_checks); |
39 DECLARE_FLAG(bool, support_externalizable_strings); | 45 DECLARE_FLAG(bool, support_externalizable_strings); |
40 | 46 |
41 | 47 |
42 #if defined(DEBUG) | 48 #if defined(DEBUG) |
43 void Instruction::CheckField(const Field& field) const { | 49 void Instruction::CheckField(const Field& field) const { |
44 ASSERT(field.IsZoneHandle()); | 50 ASSERT(field.IsZoneHandle()); |
45 ASSERT(!Compiler::IsBackgroundCompilation() || !field.IsOriginal()); | 51 ASSERT(!Compiler::IsBackgroundCompilation() || !field.IsOriginal()); |
46 } | 52 } |
47 #endif // DEBUG | 53 #endif // DEBUG |
48 | 54 |
49 | 55 |
50 Definition::Definition(intptr_t deopt_id) | 56 Definition::Definition(intptr_t deopt_id) |
51 : Instruction(deopt_id), | 57 : Instruction(deopt_id), |
52 range_(NULL), | 58 range_(NULL), |
53 type_(NULL), | 59 type_(NULL), |
54 temp_index_(-1), | 60 temp_index_(-1), |
55 ssa_temp_index_(-1), | 61 ssa_temp_index_(-1), |
56 input_use_list_(NULL), | 62 input_use_list_(NULL), |
57 env_use_list_(NULL), | 63 env_use_list_(NULL), |
58 constant_value_(NULL) { | 64 constant_value_(NULL) {} |
59 } | |
60 | 65 |
61 | 66 |
62 // A value in the constant propagation lattice. | 67 // A value in the constant propagation lattice. |
63 // - non-constant sentinel | 68 // - non-constant sentinel |
64 // - a constant (any non-sentinel value) | 69 // - a constant (any non-sentinel value) |
65 // - unknown sentinel | 70 // - unknown sentinel |
66 Object& Definition::constant_value() { | 71 Object& Definition::constant_value() { |
67 if (constant_value_ == NULL) { | 72 if (constant_value_ == NULL) { |
68 constant_value_ = &Object::ZoneHandle(ConstantPropagator::Unknown()); | 73 constant_value_ = &Object::ZoneHandle(ConstantPropagator::Unknown()); |
69 } | 74 } |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 } | 188 } |
184 } | 189 } |
185 return true; | 190 return true; |
186 } | 191 } |
187 | 192 |
188 | 193 |
189 static bool AreAllChecksImmutable(const ICData& checks) { | 194 static bool AreAllChecksImmutable(const ICData& checks) { |
190 const intptr_t len = checks.NumberOfChecks(); | 195 const intptr_t len = checks.NumberOfChecks(); |
191 for (intptr_t i = 0; i < len; i++) { | 196 for (intptr_t i = 0; i < len; i++) { |
192 if (checks.IsUsedAt(i)) { | 197 if (checks.IsUsedAt(i)) { |
193 if (Field::IsExternalizableCid( | 198 if (Field::IsExternalizableCid(checks.GetReceiverClassIdAt(i))) { |
194 checks.GetReceiverClassIdAt(i))) { | |
195 return false; | 199 return false; |
196 } | 200 } |
197 } | 201 } |
198 } | 202 } |
199 return true; | 203 return true; |
200 } | 204 } |
201 | 205 |
202 | 206 |
203 EffectSet CheckClassInstr::Dependencies() const { | 207 EffectSet CheckClassInstr::Dependencies() const { |
204 // Externalization of strings via the API can change the class-id. | 208 // Externalization of strings via the API can change the class-id. |
205 return !AreAllChecksImmutable(unary_checks()) ? | 209 return !AreAllChecksImmutable(unary_checks()) ? EffectSet::Externalization() |
206 EffectSet::Externalization() : EffectSet::None(); | 210 : EffectSet::None(); |
207 } | 211 } |
208 | 212 |
209 | 213 |
210 EffectSet CheckClassIdInstr::Dependencies() const { | 214 EffectSet CheckClassIdInstr::Dependencies() const { |
211 // Externalization of strings via the API can change the class-id. | 215 // Externalization of strings via the API can change the class-id. |
212 return Field::IsExternalizableCid(cid_) ? | 216 return Field::IsExternalizableCid(cid_) ? EffectSet::Externalization() |
213 EffectSet::Externalization() : EffectSet::None(); | 217 : EffectSet::None(); |
214 } | 218 } |
215 | 219 |
216 | 220 |
217 bool CheckClassInstr::DeoptIfNull() const { | 221 bool CheckClassInstr::DeoptIfNull() const { |
218 if (unary_checks().NumberOfChecks() != 1) { | 222 if (unary_checks().NumberOfChecks() != 1) { |
219 return false; | 223 return false; |
220 } | 224 } |
221 CompileType* in_type = value()->Type(); | 225 CompileType* in_type = value()->Type(); |
222 const intptr_t cid = unary_checks().GetCidAt(0); | 226 const intptr_t cid = unary_checks().GetCidAt(0); |
223 // Performance check: use CheckSmiInstr instead. | 227 // Performance check: use CheckSmiInstr instead. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 | 274 |
271 | 275 |
272 bool CheckClassInstr::IsDenseMask(intptr_t mask) { | 276 bool CheckClassInstr::IsDenseMask(intptr_t mask) { |
273 // Returns true if the mask is a continuos sequence of ones in its binary | 277 // Returns true if the mask is a continuos sequence of ones in its binary |
274 // representation (i.e. no holes) | 278 // representation (i.e. no holes) |
275 return mask == -1 || Utils::IsPowerOfTwo(mask + 1); | 279 return mask == -1 || Utils::IsPowerOfTwo(mask + 1); |
276 } | 280 } |
277 | 281 |
278 | 282 |
279 bool LoadFieldInstr::IsUnboxedLoad() const { | 283 bool LoadFieldInstr::IsUnboxedLoad() const { |
280 return FLAG_unbox_numeric_fields | 284 return FLAG_unbox_numeric_fields && (field() != NULL) && |
281 && (field() != NULL) | 285 FlowGraphCompiler::IsUnboxedField(*field()); |
282 && FlowGraphCompiler::IsUnboxedField(*field()); | |
283 } | 286 } |
284 | 287 |
285 | 288 |
286 bool LoadFieldInstr::IsPotentialUnboxedLoad() const { | 289 bool LoadFieldInstr::IsPotentialUnboxedLoad() const { |
287 return FLAG_unbox_numeric_fields | 290 return FLAG_unbox_numeric_fields && (field() != NULL) && |
288 && (field() != NULL) | 291 FlowGraphCompiler::IsPotentialUnboxedField(*field()); |
289 && FlowGraphCompiler::IsPotentialUnboxedField(*field()); | |
290 } | 292 } |
291 | 293 |
292 | 294 |
293 Representation LoadFieldInstr::representation() const { | 295 Representation LoadFieldInstr::representation() const { |
294 if (IsUnboxedLoad()) { | 296 if (IsUnboxedLoad()) { |
295 const intptr_t cid = field()->UnboxedFieldCid(); | 297 const intptr_t cid = field()->UnboxedFieldCid(); |
296 switch (cid) { | 298 switch (cid) { |
297 case kDoubleCid: | 299 case kDoubleCid: |
298 return kUnboxedDouble; | 300 return kUnboxedDouble; |
299 case kFloat32x4Cid: | 301 case kFloat32x4Cid: |
300 return kUnboxedFloat32x4; | 302 return kUnboxedFloat32x4; |
301 case kFloat64x2Cid: | 303 case kFloat64x2Cid: |
302 return kUnboxedFloat64x2; | 304 return kUnboxedFloat64x2; |
303 default: | 305 default: |
304 UNREACHABLE(); | 306 UNREACHABLE(); |
305 } | 307 } |
306 } | 308 } |
307 return kTagged; | 309 return kTagged; |
308 } | 310 } |
309 | 311 |
310 | 312 |
311 bool StoreInstanceFieldInstr::IsUnboxedStore() const { | 313 bool StoreInstanceFieldInstr::IsUnboxedStore() const { |
312 return FLAG_unbox_numeric_fields | 314 return FLAG_unbox_numeric_fields && !field().IsNull() && |
313 && !field().IsNull() | 315 FlowGraphCompiler::IsUnboxedField(field()); |
314 && FlowGraphCompiler::IsUnboxedField(field()); | |
315 } | 316 } |
316 | 317 |
317 | 318 |
318 bool StoreInstanceFieldInstr::IsPotentialUnboxedStore() const { | 319 bool StoreInstanceFieldInstr::IsPotentialUnboxedStore() const { |
319 return FLAG_unbox_numeric_fields | 320 return FLAG_unbox_numeric_fields && !field().IsNull() && |
320 && !field().IsNull() | 321 FlowGraphCompiler::IsPotentialUnboxedField(field()); |
321 && FlowGraphCompiler::IsPotentialUnboxedField(field()); | |
322 } | 322 } |
323 | 323 |
324 | 324 |
325 Representation StoreInstanceFieldInstr::RequiredInputRepresentation( | 325 Representation StoreInstanceFieldInstr::RequiredInputRepresentation( |
326 intptr_t index) const { | 326 intptr_t index) const { |
327 ASSERT((index == 0) || (index == 1)); | 327 ASSERT((index == 0) || (index == 1)); |
328 if ((index == 1) && IsUnboxedStore()) { | 328 if ((index == 1) && IsUnboxedStore()) { |
329 const intptr_t cid = field().UnboxedFieldCid(); | 329 const intptr_t cid = field().UnboxedFieldCid(); |
330 switch (cid) { | 330 switch (cid) { |
331 case kDoubleCid: | 331 case kDoubleCid: |
332 return kUnboxedDouble; | 332 return kUnboxedDouble; |
333 case kFloat32x4Cid: | 333 case kFloat32x4Cid: |
334 return kUnboxedFloat32x4; | 334 return kUnboxedFloat32x4; |
335 case kFloat64x2Cid: | 335 case kFloat64x2Cid: |
336 return kUnboxedFloat64x2; | 336 return kUnboxedFloat64x2; |
(...skipping 21 matching lines...) Expand all Loading... |
358 // This predicate has to be commutative for DominatorBasedCSE to work. | 358 // This predicate has to be commutative for DominatorBasedCSE to work. |
359 // TODO(fschneider): Eliminate more asserts with subtype relation. | 359 // TODO(fschneider): Eliminate more asserts with subtype relation. |
360 return dst_type().raw() == other_assert->dst_type().raw(); | 360 return dst_type().raw() == other_assert->dst_type().raw(); |
361 } | 361 } |
362 | 362 |
363 | 363 |
364 bool StrictCompareInstr::AttributesEqual(Instruction* other) const { | 364 bool StrictCompareInstr::AttributesEqual(Instruction* other) const { |
365 StrictCompareInstr* other_op = other->AsStrictCompare(); | 365 StrictCompareInstr* other_op = other->AsStrictCompare(); |
366 ASSERT(other_op != NULL); | 366 ASSERT(other_op != NULL); |
367 return ComparisonInstr::AttributesEqual(other) && | 367 return ComparisonInstr::AttributesEqual(other) && |
368 (needs_number_check() == other_op->needs_number_check()); | 368 (needs_number_check() == other_op->needs_number_check()); |
369 } | 369 } |
370 | 370 |
371 | 371 |
372 bool MathMinMaxInstr::AttributesEqual(Instruction* other) const { | 372 bool MathMinMaxInstr::AttributesEqual(Instruction* other) const { |
373 MathMinMaxInstr* other_op = other->AsMathMinMax(); | 373 MathMinMaxInstr* other_op = other->AsMathMinMax(); |
374 ASSERT(other_op != NULL); | 374 ASSERT(other_op != NULL); |
375 return (op_kind() == other_op->op_kind()) && | 375 return (op_kind() == other_op->op_kind()) && |
376 (result_cid() == other_op->result_cid()); | 376 (result_cid() == other_op->result_cid()); |
377 } | 377 } |
378 | 378 |
379 | 379 |
380 bool BinaryIntegerOpInstr::AttributesEqual(Instruction* other) const { | 380 bool BinaryIntegerOpInstr::AttributesEqual(Instruction* other) const { |
381 ASSERT(other->tag() == tag()); | 381 ASSERT(other->tag() == tag()); |
382 BinaryIntegerOpInstr* other_op = other->AsBinaryIntegerOp(); | 382 BinaryIntegerOpInstr* other_op = other->AsBinaryIntegerOp(); |
383 return (op_kind() == other_op->op_kind()) && | 383 return (op_kind() == other_op->op_kind()) && |
384 (can_overflow() == other_op->can_overflow()) && | 384 (can_overflow() == other_op->can_overflow()) && |
385 (is_truncating() == other_op->is_truncating()); | 385 (is_truncating() == other_op->is_truncating()); |
386 } | 386 } |
387 | 387 |
388 | 388 |
389 EffectSet LoadFieldInstr::Dependencies() const { | 389 EffectSet LoadFieldInstr::Dependencies() const { |
390 return immutable_ ? EffectSet::None() : EffectSet::All(); | 390 return immutable_ ? EffectSet::None() : EffectSet::All(); |
391 } | 391 } |
392 | 392 |
393 | 393 |
394 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { | 394 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { |
395 LoadFieldInstr* other_load = other->AsLoadField(); | 395 LoadFieldInstr* other_load = other->AsLoadField(); |
396 ASSERT(other_load != NULL); | 396 ASSERT(other_load != NULL); |
397 if (field() != NULL) { | 397 if (field() != NULL) { |
398 return (other_load->field() != NULL) && | 398 return (other_load->field() != NULL) && |
399 (field()->raw() == other_load->field()->raw()); | 399 (field()->raw() == other_load->field()->raw()); |
400 } | 400 } |
401 return (other_load->field() == NULL) && | 401 return (other_load->field() == NULL) && |
402 (offset_in_bytes() == other_load->offset_in_bytes()); | 402 (offset_in_bytes() == other_load->offset_in_bytes()); |
403 } | 403 } |
404 | 404 |
405 | 405 |
406 Instruction* InitStaticFieldInstr::Canonicalize(FlowGraph* flow_graph) { | 406 Instruction* InitStaticFieldInstr::Canonicalize(FlowGraph* flow_graph) { |
407 const bool is_initialized = | 407 const bool is_initialized = |
408 (field_.StaticValue() != Object::sentinel().raw()) && | 408 (field_.StaticValue() != Object::sentinel().raw()) && |
409 (field_.StaticValue() != Object::transition_sentinel().raw()); | 409 (field_.StaticValue() != Object::transition_sentinel().raw()); |
410 // When precompiling, the fact that a field is currently initialized does not | 410 // When precompiling, the fact that a field is currently initialized does not |
411 // make it safe to omit code that checks if the field needs initialization | 411 // make it safe to omit code that checks if the field needs initialization |
412 // because the field will be reset so it starts uninitialized in the process | 412 // because the field will be reset so it starts uninitialized in the process |
413 // running the precompiled code. We must be prepared to reinitialize fields. | 413 // running the precompiled code. We must be prepared to reinitialize fields. |
414 return is_initialized && !FLAG_fields_may_be_reset ? NULL : this; | 414 return is_initialized && !FLAG_fields_may_be_reset ? NULL : this; |
415 } | 415 } |
416 | 416 |
417 | 417 |
418 EffectSet LoadStaticFieldInstr::Dependencies() const { | 418 EffectSet LoadStaticFieldInstr::Dependencies() const { |
419 return (StaticField().is_final() && !FLAG_fields_may_be_reset) | 419 return (StaticField().is_final() && !FLAG_fields_may_be_reset) |
420 ? EffectSet::None() : EffectSet::All(); | 420 ? EffectSet::None() |
| 421 : EffectSet::All(); |
421 } | 422 } |
422 | 423 |
423 | 424 |
424 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { | 425 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { |
425 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); | 426 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); |
426 ASSERT(other_load != NULL); | 427 ASSERT(other_load != NULL); |
427 // Assert that the field is initialized. | 428 // Assert that the field is initialized. |
428 ASSERT(StaticField().StaticValue() != Object::sentinel().raw()); | 429 ASSERT(StaticField().StaticValue() != Object::sentinel().raw()); |
429 ASSERT(StaticField().StaticValue() != Object::transition_sentinel().raw()); | 430 ASSERT(StaticField().StaticValue() != Object::transition_sentinel().raw()); |
430 return StaticField().raw() == other_load->StaticField().raw(); | 431 return StaticField().raw() == other_load->StaticField().raw(); |
431 } | 432 } |
432 | 433 |
433 | 434 |
434 const Field& LoadStaticFieldInstr::StaticField() const { | 435 const Field& LoadStaticFieldInstr::StaticField() const { |
435 Field& field = Field::ZoneHandle(); | 436 Field& field = Field::ZoneHandle(); |
436 field ^= field_value()->BoundConstant().raw(); | 437 field ^= field_value()->BoundConstant().raw(); |
437 return field; | 438 return field; |
438 } | 439 } |
439 | 440 |
440 | 441 |
441 ConstantInstr::ConstantInstr(const Object& value, TokenPosition token_pos) | 442 ConstantInstr::ConstantInstr(const Object& value, TokenPosition token_pos) |
442 : value_(value), | 443 : value_(value), token_pos_(token_pos) { |
443 token_pos_(token_pos) { | |
444 // Check that the value is not an incorrect Integer representation. | 444 // Check that the value is not an incorrect Integer representation. |
445 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoSmi()); | 445 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoSmi()); |
446 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoInt64()); | 446 ASSERT(!value.IsBigint() || !Bigint::Cast(value).FitsIntoInt64()); |
447 ASSERT(!value.IsMint() || !Smi::IsValid(Mint::Cast(value).AsInt64Value())); | 447 ASSERT(!value.IsMint() || !Smi::IsValid(Mint::Cast(value).AsInt64Value())); |
448 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); | 448 ASSERT(!value.IsField() || Field::Cast(value).IsOriginal()); |
449 } | 449 } |
450 | 450 |
451 | 451 |
452 bool ConstantInstr::AttributesEqual(Instruction* other) const { | 452 bool ConstantInstr::AttributesEqual(Instruction* other) const { |
453 ConstantInstr* other_constant = other->AsConstant(); | 453 ConstantInstr* other_constant = other->AsConstant(); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 intptr_t osr_id) | 495 intptr_t osr_id) |
496 : BlockEntryInstr(0, CatchClauseNode::kInvalidTryIndex), | 496 : BlockEntryInstr(0, CatchClauseNode::kInvalidTryIndex), |
497 parsed_function_(parsed_function), | 497 parsed_function_(parsed_function), |
498 normal_entry_(normal_entry), | 498 normal_entry_(normal_entry), |
499 catch_entries_(), | 499 catch_entries_(), |
500 indirect_entries_(), | 500 indirect_entries_(), |
501 initial_definitions_(), | 501 initial_definitions_(), |
502 osr_id_(osr_id), | 502 osr_id_(osr_id), |
503 entry_count_(0), | 503 entry_count_(0), |
504 spill_slot_count_(0), | 504 spill_slot_count_(0), |
505 fixed_slot_count_(0) { | 505 fixed_slot_count_(0) {} |
506 } | |
507 | 506 |
508 | 507 |
509 ConstantInstr* GraphEntryInstr::constant_null() { | 508 ConstantInstr* GraphEntryInstr::constant_null() { |
510 ASSERT(initial_definitions_.length() > 0); | 509 ASSERT(initial_definitions_.length() > 0); |
511 for (intptr_t i = 0; i < initial_definitions_.length(); ++i) { | 510 for (intptr_t i = 0; i < initial_definitions_.length(); ++i) { |
512 ConstantInstr* defn = initial_definitions_[i]->AsConstant(); | 511 ConstantInstr* defn = initial_definitions_[i]->AsConstant(); |
513 if (defn != NULL && defn->value().IsNull()) return defn; | 512 if (defn != NULL && defn->value().IsNull()) return defn; |
514 } | 513 } |
515 UNREACHABLE(); | 514 UNREACHABLE(); |
516 return NULL; | 515 return NULL; |
(...skipping 11 matching lines...) Expand all Loading... |
528 | 527 |
529 | 528 |
530 bool GraphEntryInstr::IsCompiledForOsr() const { | 529 bool GraphEntryInstr::IsCompiledForOsr() const { |
531 return osr_id_ != Compiler::kNoOSRDeoptId; | 530 return osr_id_ != Compiler::kNoOSRDeoptId; |
532 } | 531 } |
533 | 532 |
534 | 533 |
535 // ==== Support for visiting flow graphs. | 534 // ==== Support for visiting flow graphs. |
536 | 535 |
537 #define DEFINE_ACCEPT(ShortName) \ | 536 #define DEFINE_ACCEPT(ShortName) \ |
538 void ShortName##Instr::Accept(FlowGraphVisitor* visitor) { \ | 537 void ShortName##Instr::Accept(FlowGraphVisitor* visitor) { \ |
539 visitor->Visit##ShortName(this); \ | 538 visitor->Visit##ShortName(this); \ |
540 } | 539 } |
541 | 540 |
542 FOR_EACH_INSTRUCTION(DEFINE_ACCEPT) | 541 FOR_EACH_INSTRUCTION(DEFINE_ACCEPT) |
543 | 542 |
544 #undef DEFINE_ACCEPT | 543 #undef DEFINE_ACCEPT |
545 | 544 |
546 | 545 |
547 void Instruction::SetEnvironment(Environment* deopt_env) { | 546 void Instruction::SetEnvironment(Environment* deopt_env) { |
548 intptr_t use_index = 0; | 547 intptr_t use_index = 0; |
549 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { | 548 for (Environment::DeepIterator it(deopt_env); !it.Done(); it.Advance()) { |
550 Value* use = it.CurrentValue(); | 549 Value* use = it.CurrentValue(); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
615 } | 614 } |
616 return tail; | 615 return tail; |
617 } | 616 } |
618 | 617 |
619 | 618 |
620 BlockEntryInstr* Instruction::GetBlock() { | 619 BlockEntryInstr* Instruction::GetBlock() { |
621 // TODO(fschneider): Implement a faster way to get the block of an | 620 // TODO(fschneider): Implement a faster way to get the block of an |
622 // instruction. | 621 // instruction. |
623 ASSERT(previous() != NULL); | 622 ASSERT(previous() != NULL); |
624 Instruction* result = previous(); | 623 Instruction* result = previous(); |
625 while (!result->IsBlockEntry()) result = result->previous(); | 624 while (!result->IsBlockEntry()) |
| 625 result = result->previous(); |
626 return result->AsBlockEntry(); | 626 return result->AsBlockEntry(); |
627 } | 627 } |
628 | 628 |
629 | 629 |
630 void ForwardInstructionIterator::RemoveCurrentFromGraph() { | 630 void ForwardInstructionIterator::RemoveCurrentFromGraph() { |
631 current_ = current_->RemoveFromGraph(true); // Set current_ to previous. | 631 current_ = current_->RemoveFromGraph(true); // Set current_ to previous. |
632 } | 632 } |
633 | 633 |
634 | 634 |
635 void BackwardInstructionIterator::RemoveCurrentFromGraph() { | 635 void BackwardInstructionIterator::RemoveCurrentFromGraph() { |
(...skipping 11 matching lines...) Expand all Loading... |
647 current_iterator_ = ⁢ | 647 current_iterator_ = ⁢ |
648 for (; !it.Done(); it.Advance()) { | 648 for (; !it.Done(); it.Advance()) { |
649 it.Current()->Accept(this); | 649 it.Current()->Accept(this); |
650 } | 650 } |
651 current_iterator_ = NULL; | 651 current_iterator_ = NULL; |
652 } | 652 } |
653 } | 653 } |
654 | 654 |
655 | 655 |
656 bool Value::NeedsStoreBuffer() { | 656 bool Value::NeedsStoreBuffer() { |
657 if (Type()->IsNull() || | 657 if (Type()->IsNull() || (Type()->ToNullableCid() == kSmiCid) || |
658 (Type()->ToNullableCid() == kSmiCid) || | |
659 (Type()->ToNullableCid() == kBoolCid)) { | 658 (Type()->ToNullableCid() == kBoolCid)) { |
660 return false; | 659 return false; |
661 } | 660 } |
662 | 661 |
663 return !BindsToConstant(); | 662 return !BindsToConstant(); |
664 } | 663 } |
665 | 664 |
666 | 665 |
667 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) { | 666 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) { |
668 // Require the predecessors to be sorted by block_id to make managing | 667 // Require the predecessors to be sorted by block_id to make managing |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
787 it.CurrentValue()->RemoveFromUseList(); | 786 it.CurrentValue()->RemoveFromUseList(); |
788 } | 787 } |
789 } | 788 } |
790 | 789 |
791 | 790 |
792 void Instruction::InheritDeoptTargetAfter(FlowGraph* flow_graph, | 791 void Instruction::InheritDeoptTargetAfter(FlowGraph* flow_graph, |
793 Definition* call, | 792 Definition* call, |
794 Definition* result) { | 793 Definition* result) { |
795 ASSERT(call->env() != NULL); | 794 ASSERT(call->env() != NULL); |
796 deopt_id_ = Thread::ToDeoptAfter(call->deopt_id_); | 795 deopt_id_ = Thread::ToDeoptAfter(call->deopt_id_); |
797 call->env()->DeepCopyAfterTo(flow_graph->zone(), | 796 call->env()->DeepCopyAfterTo( |
798 this, | 797 flow_graph->zone(), this, call->ArgumentCount(), |
799 call->ArgumentCount(), | 798 flow_graph->constant_dead(), |
800 flow_graph->constant_dead(), | 799 result != NULL ? result : flow_graph->constant_dead()); |
801 result != NULL ? result | |
802 : flow_graph->constant_dead()); | |
803 env()->set_deopt_id(deopt_id_); | 800 env()->set_deopt_id(deopt_id_); |
804 } | 801 } |
805 | 802 |
806 | 803 |
807 void Instruction::InheritDeoptTarget(Zone* zone, Instruction* other) { | 804 void Instruction::InheritDeoptTarget(Zone* zone, Instruction* other) { |
808 ASSERT(other->env() != NULL); | 805 ASSERT(other->env() != NULL); |
809 CopyDeoptIdFrom(*other); | 806 CopyDeoptIdFrom(*other); |
810 other->env()->DeepCopyTo(zone, this); | 807 other->env()->DeepCopyTo(zone, this); |
811 env()->set_deopt_id(deopt_id_); | 808 env()->set_deopt_id(deopt_id_); |
812 } | 809 } |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
916 // Detect that a block has been visited as part of the current | 913 // Detect that a block has been visited as part of the current |
917 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block | 914 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block |
918 // will be 'marked' by (1) having a preorder number in the range of the | 915 // will be 'marked' by (1) having a preorder number in the range of the |
919 // preorder array and (2) being in the preorder array at that index. | 916 // preorder array and (2) being in the preorder array at that index. |
920 intptr_t i = block->preorder_number(); | 917 intptr_t i = block->preorder_number(); |
921 return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block); | 918 return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block); |
922 } | 919 } |
923 | 920 |
924 | 921 |
925 // Base class implementation used for JoinEntry and TargetEntry. | 922 // Base class implementation used for JoinEntry and TargetEntry. |
926 bool BlockEntryInstr::DiscoverBlock( | 923 bool BlockEntryInstr::DiscoverBlock(BlockEntryInstr* predecessor, |
927 BlockEntryInstr* predecessor, | 924 GrowableArray<BlockEntryInstr*>* preorder, |
928 GrowableArray<BlockEntryInstr*>* preorder, | 925 GrowableArray<intptr_t>* parent) { |
929 GrowableArray<intptr_t>* parent) { | |
930 // If this block has a predecessor (i.e., is not the graph entry) we can | 926 // If this block has a predecessor (i.e., is not the graph entry) we can |
931 // assume the preorder array is non-empty. | 927 // assume the preorder array is non-empty. |
932 ASSERT((predecessor == NULL) || !preorder->is_empty()); | 928 ASSERT((predecessor == NULL) || !preorder->is_empty()); |
933 // Blocks with a single predecessor cannot have been reached before. | 929 // Blocks with a single predecessor cannot have been reached before. |
934 ASSERT(IsJoinEntry() || !IsMarked(this, preorder)); | 930 ASSERT(IsJoinEntry() || !IsMarked(this, preorder)); |
935 | 931 |
936 // 1. If the block has already been reached, add current_block as a | 932 // 1. If the block has already been reached, add current_block as a |
937 // basic-block predecessor and we are done. | 933 // basic-block predecessor and we are done. |
938 if (IsMarked(this, preorder)) { | 934 if (IsMarked(this, preorder)) { |
939 ASSERT(predecessor != NULL); | 935 ASSERT(predecessor != NULL); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1004 | 1000 |
1005 GotoInstr* goto_join = new GotoInstr(AsJoinEntry()); | 1001 GotoInstr* goto_join = new GotoInstr(AsJoinEntry()); |
1006 goto_join->CopyDeoptIdFrom(*parent); | 1002 goto_join->CopyDeoptIdFrom(*parent); |
1007 graph_entry->normal_entry()->LinkTo(goto_join); | 1003 graph_entry->normal_entry()->LinkTo(goto_join); |
1008 return true; | 1004 return true; |
1009 } | 1005 } |
1010 } | 1006 } |
1011 | 1007 |
1012 // Recursively search the successors. | 1008 // Recursively search the successors. |
1013 for (intptr_t i = instr->SuccessorCount() - 1; i >= 0; --i) { | 1009 for (intptr_t i = instr->SuccessorCount() - 1; i >= 0; --i) { |
1014 if (instr->SuccessorAt(i)->PruneUnreachable(graph_entry, | 1010 if (instr->SuccessorAt(i)->PruneUnreachable(graph_entry, instr, osr_id, |
1015 instr, | |
1016 osr_id, | |
1017 block_marks)) { | 1011 block_marks)) { |
1018 return true; | 1012 return true; |
1019 } | 1013 } |
1020 } | 1014 } |
1021 return false; | 1015 return false; |
1022 } | 1016 } |
1023 | 1017 |
1024 | 1018 |
1025 bool BlockEntryInstr::Dominates(BlockEntryInstr* other) const { | 1019 bool BlockEntryInstr::Dominates(BlockEntryInstr* other) const { |
1026 // TODO(fschneider): Make this faster by e.g. storing dominators for each | 1020 // TODO(fschneider): Make this faster by e.g. storing dominators for each |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1089 if ((join->phis() == NULL) || (old_index == new_index)) return; | 1083 if ((join->phis() == NULL) || (old_index == new_index)) return; |
1090 // Otherwise, reorder the predecessor uses in each phi. | 1084 // Otherwise, reorder the predecessor uses in each phi. |
1091 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 1085 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
1092 PhiInstr* phi = it.Current(); | 1086 PhiInstr* phi = it.Current(); |
1093 ASSERT(phi != NULL); | 1087 ASSERT(phi != NULL); |
1094 ASSERT(pred_count == phi->InputCount()); | 1088 ASSERT(pred_count == phi->InputCount()); |
1095 // Save the predecessor use. | 1089 // Save the predecessor use. |
1096 Value* pred_use = phi->InputAt(old_index); | 1090 Value* pred_use = phi->InputAt(old_index); |
1097 // Move uses between old and new. | 1091 // Move uses between old and new. |
1098 intptr_t step = (old_index < new_index) ? 1 : -1; | 1092 intptr_t step = (old_index < new_index) ? 1 : -1; |
1099 for (intptr_t use_idx = old_index; | 1093 for (intptr_t use_idx = old_index; use_idx != new_index; |
1100 use_idx != new_index; | |
1101 use_idx += step) { | 1094 use_idx += step) { |
1102 phi->SetInputAt(use_idx, phi->InputAt(use_idx + step)); | 1095 phi->SetInputAt(use_idx, phi->InputAt(use_idx + step)); |
1103 } | 1096 } |
1104 // Write the predecessor use. | 1097 // Write the predecessor use. |
1105 phi->SetInputAt(new_index, pred_use); | 1098 phi->SetInputAt(new_index, pred_use); |
1106 } | 1099 } |
1107 } | 1100 } |
1108 } | 1101 } |
1109 | 1102 |
1110 | 1103 |
1111 void BlockEntryInstr::ClearAllInstructions() { | 1104 void BlockEntryInstr::ClearAllInstructions() { |
1112 JoinEntryInstr* join = this->AsJoinEntry(); | 1105 JoinEntryInstr* join = this->AsJoinEntry(); |
1113 if (join != NULL) { | 1106 if (join != NULL) { |
1114 for (PhiIterator it(join); !it.Done(); it.Advance()) { | 1107 for (PhiIterator it(join); !it.Done(); it.Advance()) { |
1115 it.Current()->UnuseAllInputs(); | 1108 it.Current()->UnuseAllInputs(); |
1116 } | 1109 } |
1117 } | 1110 } |
1118 UnuseAllInputs(); | 1111 UnuseAllInputs(); |
1119 for (ForwardInstructionIterator it(this); | 1112 for (ForwardInstructionIterator it(this); !it.Done(); it.Advance()) { |
1120 !it.Done(); | |
1121 it.Advance()) { | |
1122 it.Current()->UnuseAllInputs(); | 1113 it.Current()->UnuseAllInputs(); |
1123 } | 1114 } |
1124 } | 1115 } |
1125 | 1116 |
1126 | 1117 |
1127 PhiInstr* JoinEntryInstr::InsertPhi(intptr_t var_index, intptr_t var_count) { | 1118 PhiInstr* JoinEntryInstr::InsertPhi(intptr_t var_index, intptr_t var_count) { |
1128 // Lazily initialize the array of phis. | 1119 // Lazily initialize the array of phis. |
1129 // Currently, phis are stored in a sparse array that holds the phi | 1120 // Currently, phis are stored in a sparse array that holds the phi |
1130 // for variable with index i at position i. | 1121 // for variable with index i at position i. |
1131 // TODO(fschneider): Store phis in a more compact way. | 1122 // TODO(fschneider): Store phis in a more compact way. |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1232 return successor(); | 1223 return successor(); |
1233 } | 1224 } |
1234 | 1225 |
1235 | 1226 |
1236 void Instruction::Goto(JoinEntryInstr* entry) { | 1227 void Instruction::Goto(JoinEntryInstr* entry) { |
1237 LinkTo(new GotoInstr(entry)); | 1228 LinkTo(new GotoInstr(entry)); |
1238 } | 1229 } |
1239 | 1230 |
1240 | 1231 |
1241 bool UnboxedIntConverterInstr::CanDeoptimize() const { | 1232 bool UnboxedIntConverterInstr::CanDeoptimize() const { |
1242 return (to() == kUnboxedInt32) && | 1233 return (to() == kUnboxedInt32) && !is_truncating() && |
1243 !is_truncating() && | 1234 !RangeUtils::Fits(value()->definition()->range(), |
1244 !RangeUtils::Fits(value()->definition()->range(), | 1235 RangeBoundary::kRangeBoundaryInt32); |
1245 RangeBoundary::kRangeBoundaryInt32); | |
1246 } | 1236 } |
1247 | 1237 |
1248 | 1238 |
1249 bool UnboxInt32Instr::CanDeoptimize() const { | 1239 bool UnboxInt32Instr::CanDeoptimize() const { |
1250 const intptr_t value_cid = value()->Type()->ToCid(); | 1240 const intptr_t value_cid = value()->Type()->ToCid(); |
1251 if (value_cid == kSmiCid) { | 1241 if (value_cid == kSmiCid) { |
1252 return (kSmiBits > 32) && | 1242 return (kSmiBits > 32) && !is_truncating() && |
1253 !is_truncating() && | 1243 !RangeUtils::Fits(value()->definition()->range(), |
1254 !RangeUtils::Fits(value()->definition()->range(), | 1244 RangeBoundary::kRangeBoundaryInt32); |
1255 RangeBoundary::kRangeBoundaryInt32); | |
1256 } else if (value_cid == kMintCid) { | 1245 } else if (value_cid == kMintCid) { |
1257 return !is_truncating() && | 1246 return !is_truncating() && |
1258 !RangeUtils::Fits(value()->definition()->range(), | 1247 !RangeUtils::Fits(value()->definition()->range(), |
1259 RangeBoundary::kRangeBoundaryInt32); | 1248 RangeBoundary::kRangeBoundaryInt32); |
1260 } else if (is_truncating() && value()->definition()->IsBoxInteger()) { | 1249 } else if (is_truncating() && value()->definition()->IsBoxInteger()) { |
1261 return false; | 1250 return false; |
1262 } else if ((kSmiBits < 32) && value()->Type()->IsInt()) { | 1251 } else if ((kSmiBits < 32) && value()->Type()->IsInt()) { |
1263 // Note: we don't support truncation of Bigint values. | 1252 // Note: we don't support truncation of Bigint values. |
1264 return !RangeUtils::Fits(value()->definition()->range(), | 1253 return !RangeUtils::Fits(value()->definition()->range(), |
1265 RangeBoundary::kRangeBoundaryInt32); | 1254 RangeBoundary::kRangeBoundaryInt32); |
1266 } else { | 1255 } else { |
1267 return true; | 1256 return true; |
1268 } | 1257 } |
1269 } | 1258 } |
(...skipping 16 matching lines...) Expand all Loading... |
1286 case Token::kBIT_AND: | 1275 case Token::kBIT_AND: |
1287 case Token::kBIT_OR: | 1276 case Token::kBIT_OR: |
1288 case Token::kBIT_XOR: | 1277 case Token::kBIT_XOR: |
1289 return false; | 1278 return false; |
1290 | 1279 |
1291 case Token::kSHR: | 1280 case Token::kSHR: |
1292 return false; | 1281 return false; |
1293 | 1282 |
1294 case Token::kSHL: | 1283 case Token::kSHL: |
1295 return can_overflow() || | 1284 return can_overflow() || |
1296 !RangeUtils::IsPositive(right()->definition()->range()); | 1285 !RangeUtils::IsPositive(right()->definition()->range()); |
1297 | 1286 |
1298 case Token::kMOD: { | 1287 case Token::kMOD: { |
1299 UNREACHABLE(); | 1288 UNREACHABLE(); |
1300 } | 1289 } |
1301 | 1290 |
1302 default: | 1291 default: |
1303 return can_overflow(); | 1292 return can_overflow(); |
1304 } | 1293 } |
1305 } | 1294 } |
1306 | 1295 |
1307 | 1296 |
1308 bool BinarySmiOpInstr::CanDeoptimize() const { | 1297 bool BinarySmiOpInstr::CanDeoptimize() const { |
1309 switch (op_kind()) { | 1298 switch (op_kind()) { |
1310 case Token::kBIT_AND: | 1299 case Token::kBIT_AND: |
1311 case Token::kBIT_OR: | 1300 case Token::kBIT_OR: |
1312 case Token::kBIT_XOR: | 1301 case Token::kBIT_XOR: |
1313 return false; | 1302 return false; |
1314 | 1303 |
1315 case Token::kSHR: | 1304 case Token::kSHR: |
1316 return !RangeUtils::IsPositive(right()->definition()->range()); | 1305 return !RangeUtils::IsPositive(right()->definition()->range()); |
1317 | 1306 |
1318 case Token::kSHL: | 1307 case Token::kSHL: |
1319 return can_overflow() || | 1308 return can_overflow() || |
1320 !RangeUtils::IsPositive(right()->definition()->range()); | 1309 !RangeUtils::IsPositive(right()->definition()->range()); |
1321 | 1310 |
1322 case Token::kMOD: { | 1311 case Token::kMOD: { |
1323 Range* right_range = this->right()->definition()->range(); | 1312 Range* right_range = this->right()->definition()->range(); |
1324 return (right_range == NULL) || right_range->Overlaps(0, 0); | 1313 return (right_range == NULL) || right_range->Overlaps(0, 0); |
1325 } | 1314 } |
1326 default: | 1315 default: |
1327 return can_overflow(); | 1316 return can_overflow(); |
1328 } | 1317 } |
1329 } | 1318 } |
1330 | 1319 |
(...skipping 17 matching lines...) Expand all Loading... |
1348 case kUnboxedMint: | 1337 case kUnboxedMint: |
1349 return 64; | 1338 return 64; |
1350 default: | 1339 default: |
1351 UNREACHABLE(); | 1340 UNREACHABLE(); |
1352 return 0; | 1341 return 0; |
1353 } | 1342 } |
1354 } | 1343 } |
1355 | 1344 |
1356 | 1345 |
1357 static int64_t RepresentationMask(Representation r) { | 1346 static int64_t RepresentationMask(Representation r) { |
1358 return static_cast<int64_t>( | 1347 return static_cast<int64_t>(static_cast<uint64_t>(-1) >> |
1359 static_cast<uint64_t>(-1) >> (64 - RepresentationBits(r))); | 1348 (64 - RepresentationBits(r))); |
1360 } | 1349 } |
1361 | 1350 |
1362 | 1351 |
1363 static bool ToIntegerConstant(Value* value, int64_t* result) { | 1352 static bool ToIntegerConstant(Value* value, int64_t* result) { |
1364 if (!value->BindsToConstant()) { | 1353 if (!value->BindsToConstant()) { |
1365 UnboxInstr* unbox = value->definition()->AsUnbox(); | 1354 UnboxInstr* unbox = value->definition()->AsUnbox(); |
1366 if (unbox != NULL) { | 1355 if (unbox != NULL) { |
1367 switch (unbox->representation()) { | 1356 switch (unbox->representation()) { |
1368 case kUnboxedDouble: | 1357 case kUnboxedDouble: |
1369 case kUnboxedMint: | 1358 case kUnboxedMint: |
(...skipping 26 matching lines...) Expand all Loading... |
1396 return true; | 1385 return true; |
1397 } else if (constant.IsMint()) { | 1386 } else if (constant.IsMint()) { |
1398 *result = Mint::Cast(constant).value(); | 1387 *result = Mint::Cast(constant).value(); |
1399 return true; | 1388 return true; |
1400 } | 1389 } |
1401 | 1390 |
1402 return false; | 1391 return false; |
1403 } | 1392 } |
1404 | 1393 |
1405 | 1394 |
1406 static Definition* CanonicalizeCommutativeDoubleArithmetic( | 1395 static Definition* CanonicalizeCommutativeDoubleArithmetic(Token::Kind op, |
1407 Token::Kind op, | 1396 Value* left, |
1408 Value* left, | 1397 Value* right) { |
1409 Value* right) { | |
1410 int64_t left_value; | 1398 int64_t left_value; |
1411 if (!ToIntegerConstant(left, &left_value)) { | 1399 if (!ToIntegerConstant(left, &left_value)) { |
1412 return NULL; | 1400 return NULL; |
1413 } | 1401 } |
1414 | 1402 |
1415 // Can't apply 0.0 * x -> 0.0 equivalence to double operation because | 1403 // Can't apply 0.0 * x -> 0.0 equivalence to double operation because |
1416 // 0.0 * NaN is NaN not 0.0. | 1404 // 0.0 * NaN is NaN not 0.0. |
1417 // Can't apply 0.0 + x -> x to double because 0.0 + (-0.0) is 0.0 not -0.0. | 1405 // Can't apply 0.0 + x -> x to double because 0.0 + (-0.0) is 0.0 not -0.0. |
1418 switch (op) { | 1406 switch (op) { |
1419 case Token::kMUL: | 1407 case Token::kMUL: |
(...skipping 15 matching lines...) Expand all Loading... |
1435 | 1423 |
1436 return NULL; | 1424 return NULL; |
1437 } | 1425 } |
1438 | 1426 |
1439 | 1427 |
1440 Definition* DoubleToFloatInstr::Canonicalize(FlowGraph* flow_graph) { | 1428 Definition* DoubleToFloatInstr::Canonicalize(FlowGraph* flow_graph) { |
1441 #ifdef DEBUG | 1429 #ifdef DEBUG |
1442 // Must only be used in Float32 StoreIndexedInstr or FloatToDoubleInstr or | 1430 // Must only be used in Float32 StoreIndexedInstr or FloatToDoubleInstr or |
1443 // Phis introduce by load forwarding. | 1431 // Phis introduce by load forwarding. |
1444 ASSERT(env_use_list() == NULL); | 1432 ASSERT(env_use_list() == NULL); |
1445 for (Value* use = input_use_list(); | 1433 for (Value* use = input_use_list(); use != NULL; use = use->next_use()) { |
1446 use != NULL; | |
1447 use = use->next_use()) { | |
1448 ASSERT(use->instruction()->IsPhi() || | 1434 ASSERT(use->instruction()->IsPhi() || |
1449 use->instruction()->IsFloatToDouble() || | 1435 use->instruction()->IsFloatToDouble() || |
1450 (use->instruction()->IsStoreIndexed() && | 1436 (use->instruction()->IsStoreIndexed() && |
1451 (use->instruction()->AsStoreIndexed()->class_id() == | 1437 (use->instruction()->AsStoreIndexed()->class_id() == |
1452 kTypedDataFloat32ArrayCid))); | 1438 kTypedDataFloat32ArrayCid))); |
1453 } | 1439 } |
1454 #endif | 1440 #endif |
1455 if (!HasUses()) return NULL; | 1441 if (!HasUses()) return NULL; |
1456 if (value()->definition()->IsFloatToDouble()) { | 1442 if (value()->definition()->IsFloatToDouble()) { |
1457 // F2D(D2F(v)) == v. | 1443 // F2D(D2F(v)) == v. |
(...skipping 18 matching lines...) Expand all Loading... |
1476 return result; | 1462 return result; |
1477 } | 1463 } |
1478 | 1464 |
1479 result = CanonicalizeCommutativeDoubleArithmetic(op_kind(), right(), left()); | 1465 result = CanonicalizeCommutativeDoubleArithmetic(op_kind(), right(), left()); |
1480 if (result != NULL) { | 1466 if (result != NULL) { |
1481 return result; | 1467 return result; |
1482 } | 1468 } |
1483 | 1469 |
1484 if ((op_kind() == Token::kMUL) && | 1470 if ((op_kind() == Token::kMUL) && |
1485 (left()->definition() == right()->definition())) { | 1471 (left()->definition() == right()->definition())) { |
1486 MathUnaryInstr* math_unary = | 1472 MathUnaryInstr* math_unary = new MathUnaryInstr( |
1487 new MathUnaryInstr(MathUnaryInstr::kDoubleSquare, | 1473 MathUnaryInstr::kDoubleSquare, new Value(left()->definition()), |
1488 new Value(left()->definition()), | 1474 DeoptimizationTarget()); |
1489 DeoptimizationTarget()); | |
1490 flow_graph->InsertBefore(this, math_unary, env(), FlowGraph::kValue); | 1475 flow_graph->InsertBefore(this, math_unary, env(), FlowGraph::kValue); |
1491 return math_unary; | 1476 return math_unary; |
1492 } | 1477 } |
1493 | 1478 |
1494 return this; | 1479 return this; |
1495 } | 1480 } |
1496 | 1481 |
1497 | 1482 |
1498 Definition* DoubleTestOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1483 Definition* DoubleTestOpInstr::Canonicalize(FlowGraph* flow_graph) { |
1499 return HasUses() ? this : NULL; | 1484 return HasUses() ? this : NULL; |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1625 } | 1610 } |
1626 | 1611 |
1627 | 1612 |
1628 RawInteger* UnaryIntegerOpInstr::Evaluate(const Integer& value) const { | 1613 RawInteger* UnaryIntegerOpInstr::Evaluate(const Integer& value) const { |
1629 Thread* thread = Thread::Current(); | 1614 Thread* thread = Thread::Current(); |
1630 Zone* zone = thread->zone(); | 1615 Zone* zone = thread->zone(); |
1631 Integer& result = Integer::Handle(zone); | 1616 Integer& result = Integer::Handle(zone); |
1632 | 1617 |
1633 switch (op_kind()) { | 1618 switch (op_kind()) { |
1634 case Token::kNEGATE: | 1619 case Token::kNEGATE: |
1635 result = value.ArithmeticOp(Token::kMUL, | 1620 result = value.ArithmeticOp(Token::kMUL, Smi::Handle(zone, Smi::New(-1)), |
1636 Smi::Handle(zone, Smi::New(-1)), | |
1637 Heap::kOld); | 1621 Heap::kOld); |
1638 break; | 1622 break; |
1639 | 1623 |
1640 case Token::kBIT_NOT: | 1624 case Token::kBIT_NOT: |
1641 if (value.IsSmi()) { | 1625 if (value.IsSmi()) { |
1642 result = Integer::New(~Smi::Cast(value).Value()); | 1626 result = Integer::New(~Smi::Cast(value).Value()); |
1643 } else if (value.IsMint()) { | 1627 } else if (value.IsMint()) { |
1644 result = Integer::New(~Mint::Cast(value).value()); | 1628 result = Integer::New(~Mint::Cast(value).value()); |
1645 } | 1629 } |
1646 break; | 1630 break; |
(...skipping 23 matching lines...) Expand all Loading... |
1670 Zone* zone = thread->zone(); | 1654 Zone* zone = thread->zone(); |
1671 Integer& result = Integer::Handle(zone); | 1655 Integer& result = Integer::Handle(zone); |
1672 | 1656 |
1673 switch (op_kind()) { | 1657 switch (op_kind()) { |
1674 case Token::kTRUNCDIV: | 1658 case Token::kTRUNCDIV: |
1675 case Token::kMOD: | 1659 case Token::kMOD: |
1676 // Check right value for zero. | 1660 // Check right value for zero. |
1677 if (right.IsSmi() && right.AsInt64Value() == 0) { | 1661 if (right.IsSmi() && right.AsInt64Value() == 0) { |
1678 break; // Will throw. | 1662 break; // Will throw. |
1679 } | 1663 } |
1680 // Fall through. | 1664 // Fall through. |
1681 case Token::kADD: | 1665 case Token::kADD: |
1682 case Token::kSUB: | 1666 case Token::kSUB: |
1683 case Token::kMUL: { | 1667 case Token::kMUL: { |
1684 result = left.ArithmeticOp(op_kind(), right, Heap::kOld); | 1668 result = left.ArithmeticOp(op_kind(), right, Heap::kOld); |
1685 break; | 1669 break; |
1686 } | 1670 } |
1687 case Token::kSHL: | 1671 case Token::kSHL: |
1688 case Token::kSHR: | 1672 case Token::kSHR: |
1689 if (left.IsSmi() && right.IsSmi() && (Smi::Cast(right).Value() >= 0)) { | 1673 if (left.IsSmi() && right.IsSmi() && (Smi::Cast(right).Value() >= 0)) { |
1690 result = Smi::Cast(left).ShiftOp(op_kind(), | 1674 result = |
1691 Smi::Cast(right), | 1675 Smi::Cast(left).ShiftOp(op_kind(), Smi::Cast(right), Heap::kOld); |
1692 Heap::kOld); | |
1693 } | 1676 } |
1694 break; | 1677 break; |
1695 case Token::kBIT_AND: | 1678 case Token::kBIT_AND: |
1696 case Token::kBIT_OR: | 1679 case Token::kBIT_OR: |
1697 case Token::kBIT_XOR: { | 1680 case Token::kBIT_XOR: { |
1698 result = left.BitOp(op_kind(), right, Heap::kOld); | 1681 result = left.BitOp(op_kind(), right, Heap::kOld); |
1699 break; | 1682 break; |
1700 } | 1683 } |
1701 case Token::kDIV: | 1684 case Token::kDIV: |
1702 break; | 1685 break; |
(...skipping 18 matching lines...) Expand all Loading... |
1721 } | 1704 } |
1722 | 1705 |
1723 return result.raw(); | 1706 return result.raw(); |
1724 } | 1707 } |
1725 | 1708 |
1726 | 1709 |
1727 Definition* BinaryIntegerOpInstr::CreateConstantResult(FlowGraph* flow_graph, | 1710 Definition* BinaryIntegerOpInstr::CreateConstantResult(FlowGraph* flow_graph, |
1728 const Integer& result) { | 1711 const Integer& result) { |
1729 Definition* result_defn = flow_graph->GetConstant(result); | 1712 Definition* result_defn = flow_graph->GetConstant(result); |
1730 if (representation() != kTagged) { | 1713 if (representation() != kTagged) { |
1731 result_defn = UnboxInstr::Create(representation(), | 1714 result_defn = UnboxInstr::Create(representation(), new Value(result_defn), |
1732 new Value(result_defn), | |
1733 GetDeoptId()); | 1715 GetDeoptId()); |
1734 flow_graph->InsertBefore(this, result_defn, env(), FlowGraph::kValue); | 1716 flow_graph->InsertBefore(this, result_defn, env(), FlowGraph::kValue); |
1735 } | 1717 } |
1736 return result_defn; | 1718 return result_defn; |
1737 } | 1719 } |
1738 | 1720 |
1739 | 1721 |
1740 Definition* CheckedSmiOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1722 Definition* CheckedSmiOpInstr::Canonicalize(FlowGraph* flow_graph) { |
1741 if ((left()->Type()->ToCid() == kSmiCid) && | 1723 if ((left()->Type()->ToCid() == kSmiCid) && |
1742 (right()->Type()->ToCid() == kSmiCid)) { | 1724 (right()->Type()->ToCid() == kSmiCid)) { |
1743 Definition* replacement = NULL; | 1725 Definition* replacement = NULL; |
1744 // Operations that can't deoptimize are specialized here: These include | 1726 // Operations that can't deoptimize are specialized here: These include |
1745 // bit-wise operators and comparisons. Other arithmetic operations can | 1727 // bit-wise operators and comparisons. Other arithmetic operations can |
1746 // overflow or divide by 0 and can't be specialized unless we have extra | 1728 // overflow or divide by 0 and can't be specialized unless we have extra |
1747 // range information. | 1729 // range information. |
1748 switch (op_kind()) { | 1730 switch (op_kind()) { |
1749 case Token::kBIT_AND: | 1731 case Token::kBIT_AND: |
1750 case Token::kBIT_OR: | 1732 case Token::kBIT_OR: |
1751 case Token::kBIT_XOR: | 1733 case Token::kBIT_XOR: |
1752 replacement = | 1734 replacement = new BinarySmiOpInstr( |
1753 new BinarySmiOpInstr(op_kind(), | 1735 op_kind(), new Value(left()->definition()), |
1754 new Value(left()->definition()), | 1736 new Value(right()->definition()), Thread::kNoDeoptId); |
1755 new Value(right()->definition()), | |
1756 Thread::kNoDeoptId); | |
1757 default: | 1737 default: |
1758 break; | 1738 break; |
1759 } | 1739 } |
1760 if (replacement != NULL) { | 1740 if (replacement != NULL) { |
1761 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); | 1741 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); |
1762 return replacement; | 1742 return replacement; |
1763 } | 1743 } |
1764 } | 1744 } |
1765 return this; | 1745 return this; |
1766 } | 1746 } |
1767 | 1747 |
1768 | 1748 |
1769 ComparisonInstr* CheckedSmiComparisonInstr::CopyWithNewOperands( | 1749 ComparisonInstr* CheckedSmiComparisonInstr::CopyWithNewOperands(Value* left, |
1770 Value* left, Value* right) { | 1750 Value* right) { |
1771 UNREACHABLE(); | 1751 UNREACHABLE(); |
1772 return NULL; | 1752 return NULL; |
1773 } | 1753 } |
1774 | 1754 |
1775 | 1755 |
1776 Definition* CheckedSmiComparisonInstr::Canonicalize(FlowGraph* flow_graph) { | 1756 Definition* CheckedSmiComparisonInstr::Canonicalize(FlowGraph* flow_graph) { |
1777 if ((left()->Type()->ToCid() == kSmiCid) && | 1757 if ((left()->Type()->ToCid() == kSmiCid) && |
1778 (right()->Type()->ToCid() == kSmiCid)) { | 1758 (right()->Type()->ToCid() == kSmiCid)) { |
1779 Definition* replacement = NULL; | 1759 Definition* replacement = NULL; |
1780 if (Token::IsRelationalOperator(kind())) { | 1760 if (Token::IsRelationalOperator(kind())) { |
1781 replacement = new RelationalOpInstr(token_pos(), kind(), | 1761 replacement = new RelationalOpInstr( |
1782 new Value(left()->definition()), | 1762 token_pos(), kind(), new Value(left()->definition()), |
1783 new Value(right()->definition()), | 1763 new Value(right()->definition()), kSmiCid, Thread::kNoDeoptId); |
1784 kSmiCid, | |
1785 Thread::kNoDeoptId); | |
1786 } else if (Token::IsEqualityOperator(kind())) { | 1764 } else if (Token::IsEqualityOperator(kind())) { |
1787 replacement = new EqualityCompareInstr(token_pos(), kind(), | 1765 replacement = new EqualityCompareInstr( |
1788 new Value(left()->definition()), | 1766 token_pos(), kind(), new Value(left()->definition()), |
1789 new Value(right()->definition()), | 1767 new Value(right()->definition()), kSmiCid, Thread::kNoDeoptId); |
1790 kSmiCid, | |
1791 Thread::kNoDeoptId); | |
1792 } | 1768 } |
1793 if (replacement != NULL) { | 1769 if (replacement != NULL) { |
1794 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); | 1770 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); |
1795 return replacement; | 1771 return replacement; |
1796 } | 1772 } |
1797 } | 1773 } |
1798 return this; | 1774 return this; |
1799 } | 1775 } |
1800 | 1776 |
1801 | 1777 |
1802 Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) { | 1778 Definition* BinaryIntegerOpInstr::Canonicalize(FlowGraph* flow_graph) { |
1803 // If both operands are constants evaluate this expression. Might | 1779 // If both operands are constants evaluate this expression. Might |
1804 // occur due to load forwarding after constant propagation pass | 1780 // occur due to load forwarding after constant propagation pass |
1805 // have already been run. | 1781 // have already been run. |
1806 if (left()->BindsToConstant() && | 1782 if (left()->BindsToConstant() && left()->BoundConstant().IsInteger() && |
1807 left()->BoundConstant().IsInteger() && | 1783 right()->BindsToConstant() && right()->BoundConstant().IsInteger()) { |
1808 right()->BindsToConstant() && | 1784 const Integer& result = |
1809 right()->BoundConstant().IsInteger()) { | 1785 Integer::Handle(Evaluate(Integer::Cast(left()->BoundConstant()), |
1810 const Integer& result = Integer::Handle( | 1786 Integer::Cast(right()->BoundConstant()))); |
1811 Evaluate(Integer::Cast(left()->BoundConstant()), | |
1812 Integer::Cast(right()->BoundConstant()))); | |
1813 if (!result.IsNull()) { | 1787 if (!result.IsNull()) { |
1814 return CreateConstantResult(flow_graph, result); | 1788 return CreateConstantResult(flow_graph, result); |
1815 } | 1789 } |
1816 } | 1790 } |
1817 | 1791 |
1818 if (left()->BindsToConstant() && | 1792 if (left()->BindsToConstant() && !right()->BindsToConstant() && |
1819 !right()->BindsToConstant() && | |
1820 IsCommutative(op_kind())) { | 1793 IsCommutative(op_kind())) { |
1821 Value* l = left(); | 1794 Value* l = left(); |
1822 Value* r = right(); | 1795 Value* r = right(); |
1823 SetInputAt(0, r); | 1796 SetInputAt(0, r); |
1824 SetInputAt(1, l); | 1797 SetInputAt(1, l); |
1825 } | 1798 } |
1826 | 1799 |
1827 int64_t rhs; | 1800 int64_t rhs; |
1828 if (!ToIntegerConstant(right(), &rhs)) { | 1801 if (!ToIntegerConstant(right(), &rhs)) { |
1829 return this; | 1802 return this; |
(...skipping 17 matching lines...) Expand all Loading... |
1847 | 1820 |
1848 switch (op_kind()) { | 1821 switch (op_kind()) { |
1849 case Token::kMUL: | 1822 case Token::kMUL: |
1850 if (rhs == 1) { | 1823 if (rhs == 1) { |
1851 return left()->definition(); | 1824 return left()->definition(); |
1852 } else if (rhs == 0) { | 1825 } else if (rhs == 0) { |
1853 return right()->definition(); | 1826 return right()->definition(); |
1854 } else if (rhs == 2) { | 1827 } else if (rhs == 2) { |
1855 ConstantInstr* constant_1 = | 1828 ConstantInstr* constant_1 = |
1856 flow_graph->GetConstant(Smi::Handle(Smi::New(1))); | 1829 flow_graph->GetConstant(Smi::Handle(Smi::New(1))); |
1857 BinaryIntegerOpInstr* shift = | 1830 BinaryIntegerOpInstr* shift = BinaryIntegerOpInstr::Make( |
1858 BinaryIntegerOpInstr::Make(representation(), | 1831 representation(), Token::kSHL, left()->CopyWithType(), |
1859 Token::kSHL, | 1832 new Value(constant_1), GetDeoptId(), can_overflow(), |
1860 left()->CopyWithType(), | 1833 is_truncating(), range()); |
1861 new Value(constant_1), | |
1862 GetDeoptId(), | |
1863 can_overflow(), | |
1864 is_truncating(), | |
1865 range()); | |
1866 if (shift != NULL) { | 1834 if (shift != NULL) { |
1867 flow_graph->InsertBefore(this, shift, env(), FlowGraph::kValue); | 1835 flow_graph->InsertBefore(this, shift, env(), FlowGraph::kValue); |
1868 return shift; | 1836 return shift; |
1869 } | 1837 } |
1870 } | 1838 } |
1871 | 1839 |
1872 break; | 1840 break; |
1873 case Token::kADD: | 1841 case Token::kADD: |
1874 if (rhs == 0) { | 1842 if (rhs == 0) { |
1875 return left()->definition(); | 1843 return left()->definition(); |
(...skipping 10 matching lines...) Expand all Loading... |
1886 if (rhs == 0) { | 1854 if (rhs == 0) { |
1887 return left()->definition(); | 1855 return left()->definition(); |
1888 } else if (rhs == range_mask) { | 1856 } else if (rhs == range_mask) { |
1889 return right()->definition(); | 1857 return right()->definition(); |
1890 } | 1858 } |
1891 break; | 1859 break; |
1892 case Token::kBIT_XOR: | 1860 case Token::kBIT_XOR: |
1893 if (rhs == 0) { | 1861 if (rhs == 0) { |
1894 return left()->definition(); | 1862 return left()->definition(); |
1895 } else if (rhs == range_mask) { | 1863 } else if (rhs == range_mask) { |
1896 UnaryIntegerOpInstr* bit_not = | 1864 UnaryIntegerOpInstr* bit_not = UnaryIntegerOpInstr::Make( |
1897 UnaryIntegerOpInstr::Make(representation(), | 1865 representation(), Token::kBIT_NOT, left()->CopyWithType(), |
1898 Token::kBIT_NOT, | 1866 GetDeoptId(), range()); |
1899 left()->CopyWithType(), | |
1900 GetDeoptId(), | |
1901 range()); | |
1902 if (bit_not != NULL) { | 1867 if (bit_not != NULL) { |
1903 flow_graph->InsertBefore(this, bit_not, env(), FlowGraph::kValue); | 1868 flow_graph->InsertBefore(this, bit_not, env(), FlowGraph::kValue); |
1904 return bit_not; | 1869 return bit_not; |
1905 } | 1870 } |
1906 } | 1871 } |
1907 break; | 1872 break; |
1908 | 1873 |
1909 case Token::kSUB: | 1874 case Token::kSUB: |
1910 if (rhs == 0) { | 1875 if (rhs == 0) { |
1911 return left()->definition(); | 1876 return left()->definition(); |
1912 } | 1877 } |
1913 break; | 1878 break; |
1914 | 1879 |
1915 case Token::kTRUNCDIV: | 1880 case Token::kTRUNCDIV: |
1916 if (rhs == 1) { | 1881 if (rhs == 1) { |
1917 return left()->definition(); | 1882 return left()->definition(); |
1918 } else if (rhs == -1) { | 1883 } else if (rhs == -1) { |
1919 UnaryIntegerOpInstr* negation = | 1884 UnaryIntegerOpInstr* negation = UnaryIntegerOpInstr::Make( |
1920 UnaryIntegerOpInstr::Make(representation(), | 1885 representation(), Token::kNEGATE, left()->CopyWithType(), |
1921 Token::kNEGATE, | 1886 GetDeoptId(), range()); |
1922 left()->CopyWithType(), | |
1923 GetDeoptId(), | |
1924 range()); | |
1925 if (negation != NULL) { | 1887 if (negation != NULL) { |
1926 flow_graph->InsertBefore(this, negation, env(), FlowGraph::kValue); | 1888 flow_graph->InsertBefore(this, negation, env(), FlowGraph::kValue); |
1927 return negation; | 1889 return negation; |
1928 } | 1890 } |
1929 } | 1891 } |
1930 break; | 1892 break; |
1931 | 1893 |
1932 case Token::kSHR: | 1894 case Token::kSHR: |
1933 if (rhs == 0) { | 1895 if (rhs == 0) { |
1934 return left()->definition(); | 1896 return left()->definition(); |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2088 value()->Type()->IsAssignableTo(dst_type())) { | 2050 value()->Type()->IsAssignableTo(dst_type())) { |
2089 return value()->definition(); | 2051 return value()->definition(); |
2090 } | 2052 } |
2091 | 2053 |
2092 // For uninstantiated target types: If the instantiator type arguments | 2054 // For uninstantiated target types: If the instantiator type arguments |
2093 // are constant, instantiate the target type here. | 2055 // are constant, instantiate the target type here. |
2094 if (dst_type().IsInstantiated()) return this; | 2056 if (dst_type().IsInstantiated()) return this; |
2095 | 2057 |
2096 ConstantInstr* constant_type_args = | 2058 ConstantInstr* constant_type_args = |
2097 instantiator_type_arguments()->definition()->AsConstant(); | 2059 instantiator_type_arguments()->definition()->AsConstant(); |
2098 if (constant_type_args != NULL && | 2060 if (constant_type_args != NULL && !constant_type_args->value().IsNull() && |
2099 !constant_type_args->value().IsNull() && | |
2100 constant_type_args->value().IsTypeArguments()) { | 2061 constant_type_args->value().IsTypeArguments()) { |
2101 const TypeArguments& instantiator_type_args = | 2062 const TypeArguments& instantiator_type_args = |
2102 TypeArguments::Cast(constant_type_args->value()); | 2063 TypeArguments::Cast(constant_type_args->value()); |
2103 Error& bound_error = Error::Handle(); | 2064 Error& bound_error = Error::Handle(); |
2104 AbstractType& new_dst_type = AbstractType::Handle( | 2065 AbstractType& new_dst_type = |
2105 dst_type().InstantiateFrom( | 2066 AbstractType::Handle(dst_type().InstantiateFrom( |
2106 instantiator_type_args, &bound_error, NULL, NULL, Heap::kOld)); | 2067 instantiator_type_args, &bound_error, NULL, NULL, Heap::kOld)); |
2107 if (new_dst_type.IsMalformedOrMalbounded() || !bound_error.IsNull()) { | 2068 if (new_dst_type.IsMalformedOrMalbounded() || !bound_error.IsNull()) { |
2108 return this; | 2069 return this; |
2109 } | 2070 } |
2110 if (new_dst_type.IsTypeRef()) { | 2071 if (new_dst_type.IsTypeRef()) { |
2111 new_dst_type = TypeRef::Cast(new_dst_type).type(); | 2072 new_dst_type = TypeRef::Cast(new_dst_type).type(); |
2112 } | 2073 } |
2113 new_dst_type = new_dst_type.Canonicalize(); | 2074 new_dst_type = new_dst_type.Canonicalize(); |
2114 set_dst_type(new_dst_type); | 2075 set_dst_type(new_dst_type); |
2115 | 2076 |
2116 if (new_dst_type.IsDynamicType() || | 2077 if (new_dst_type.IsDynamicType() || new_dst_type.IsObjectType() || |
2117 new_dst_type.IsObjectType() || | |
2118 (FLAG_eliminate_type_checks && | 2078 (FLAG_eliminate_type_checks && |
2119 value()->Type()->IsAssignableTo(new_dst_type))) { | 2079 value()->Type()->IsAssignableTo(new_dst_type))) { |
2120 return value()->definition(); | 2080 return value()->definition(); |
2121 } | 2081 } |
2122 | 2082 |
2123 ConstantInstr* null_constant = flow_graph->constant_null(); | 2083 ConstantInstr* null_constant = flow_graph->constant_null(); |
2124 instantiator_type_arguments()->BindTo(null_constant); | 2084 instantiator_type_arguments()->BindTo(null_constant); |
2125 } | 2085 } |
2126 return this; | 2086 return this; |
2127 } | 2087 } |
2128 | 2088 |
2129 | 2089 |
2130 Definition* InstantiateTypeArgumentsInstr::Canonicalize(FlowGraph* flow_graph) { | 2090 Definition* InstantiateTypeArgumentsInstr::Canonicalize(FlowGraph* flow_graph) { |
2131 return (Isolate::Current()->type_checks() || HasUses()) ? this : NULL; | 2091 return (Isolate::Current()->type_checks() || HasUses()) ? this : NULL; |
2132 } | 2092 } |
2133 | 2093 |
2134 | 2094 |
2135 LocationSummary* DebugStepCheckInstr::MakeLocationSummary(Zone* zone, | 2095 LocationSummary* DebugStepCheckInstr::MakeLocationSummary(Zone* zone, |
2136 bool opt) const { | 2096 bool opt) const { |
2137 const intptr_t kNumInputs = 0; | 2097 const intptr_t kNumInputs = 0; |
2138 const intptr_t kNumTemps = 0; | 2098 const intptr_t kNumTemps = 0; |
2139 LocationSummary* locs = new(zone) LocationSummary( | 2099 LocationSummary* locs = new (zone) |
2140 zone, kNumInputs, kNumTemps, LocationSummary::kCall); | 2100 LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kCall); |
2141 return locs; | 2101 return locs; |
2142 } | 2102 } |
2143 | 2103 |
2144 | 2104 |
2145 Instruction* DebugStepCheckInstr::Canonicalize(FlowGraph* flow_graph) { | 2105 Instruction* DebugStepCheckInstr::Canonicalize(FlowGraph* flow_graph) { |
2146 return NULL; | 2106 return NULL; |
2147 } | 2107 } |
2148 | 2108 |
2149 | 2109 |
2150 static bool HasTryBlockUse(Value* use_list) { | 2110 static bool HasTryBlockUse(Value* use_list) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2211 break; | 2171 break; |
2212 case kUnboxedUint32: | 2172 case kUnboxedUint32: |
2213 replacement = new BoxUint32Instr(conv->value()->CopyWithType()); | 2173 replacement = new BoxUint32Instr(conv->value()->CopyWithType()); |
2214 break; | 2174 break; |
2215 default: | 2175 default: |
2216 UNREACHABLE(); | 2176 UNREACHABLE(); |
2217 break; | 2177 break; |
2218 } | 2178 } |
2219 | 2179 |
2220 if (replacement != this) { | 2180 if (replacement != this) { |
2221 flow_graph->InsertBefore(this, | 2181 flow_graph->InsertBefore(this, replacement, NULL, FlowGraph::kValue); |
2222 replacement, | |
2223 NULL, | |
2224 FlowGraph::kValue); | |
2225 } | 2182 } |
2226 | 2183 |
2227 return replacement; | 2184 return replacement; |
2228 } | 2185 } |
2229 | 2186 |
2230 return this; | 2187 return this; |
2231 } | 2188 } |
2232 | 2189 |
2233 | 2190 |
2234 Definition* UnboxInstr::Canonicalize(FlowGraph* flow_graph) { | 2191 Definition* UnboxInstr::Canonicalize(FlowGraph* flow_graph) { |
2235 if (!HasUses() && !CanDeoptimize()) return NULL; | 2192 if (!HasUses() && !CanDeoptimize()) return NULL; |
2236 | 2193 |
2237 // Fold away Unbox<rep>(Box<rep>(v)). | 2194 // Fold away Unbox<rep>(Box<rep>(v)). |
2238 BoxInstr* box_defn = value()->definition()->AsBox(); | 2195 BoxInstr* box_defn = value()->definition()->AsBox(); |
2239 if ((box_defn != NULL) && | 2196 if ((box_defn != NULL) && |
2240 (box_defn->from_representation() == representation())) { | 2197 (box_defn->from_representation() == representation())) { |
2241 return box_defn->value()->definition(); | 2198 return box_defn->value()->definition(); |
2242 } | 2199 } |
2243 | 2200 |
2244 if ((representation() == kUnboxedDouble) && value()->BindsToConstant()) { | 2201 if ((representation() == kUnboxedDouble) && value()->BindsToConstant()) { |
2245 UnboxedConstantInstr* uc = NULL; | 2202 UnboxedConstantInstr* uc = NULL; |
2246 | 2203 |
2247 const Object& val = value()->BoundConstant(); | 2204 const Object& val = value()->BoundConstant(); |
2248 if (val.IsSmi()) { | 2205 if (val.IsSmi()) { |
2249 const Double& double_val = Double::ZoneHandle(flow_graph->zone(), | 2206 const Double& double_val = Double::ZoneHandle( |
| 2207 flow_graph->zone(), |
2250 Double::NewCanonical(Smi::Cast(val).AsDoubleValue())); | 2208 Double::NewCanonical(Smi::Cast(val).AsDoubleValue())); |
2251 uc = new UnboxedConstantInstr(double_val, kUnboxedDouble); | 2209 uc = new UnboxedConstantInstr(double_val, kUnboxedDouble); |
2252 } else if (val.IsDouble()) { | 2210 } else if (val.IsDouble()) { |
2253 uc = new UnboxedConstantInstr(val, kUnboxedDouble); | 2211 uc = new UnboxedConstantInstr(val, kUnboxedDouble); |
2254 } | 2212 } |
2255 | 2213 |
2256 if (uc != NULL) { | 2214 if (uc != NULL) { |
2257 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); | 2215 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); |
2258 return uc; | 2216 return uc; |
2259 } | 2217 } |
2260 } | 2218 } |
2261 | 2219 |
2262 return this; | 2220 return this; |
2263 } | 2221 } |
2264 | 2222 |
2265 | 2223 |
2266 Definition* UnboxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { | 2224 Definition* UnboxIntegerInstr::Canonicalize(FlowGraph* flow_graph) { |
2267 if (!HasUses() && !CanDeoptimize()) return NULL; | 2225 if (!HasUses() && !CanDeoptimize()) return NULL; |
2268 | 2226 |
2269 // Fold away UnboxInteger<rep_to>(BoxInteger<rep_from>(v)). | 2227 // Fold away UnboxInteger<rep_to>(BoxInteger<rep_from>(v)). |
2270 BoxIntegerInstr* box_defn = value()->definition()->AsBoxInteger(); | 2228 BoxIntegerInstr* box_defn = value()->definition()->AsBoxInteger(); |
2271 if (box_defn != NULL) { | 2229 if (box_defn != NULL) { |
2272 Representation from_representation = | 2230 Representation from_representation = |
2273 box_defn->value()->definition()->representation(); | 2231 box_defn->value()->definition()->representation(); |
2274 if (from_representation == representation()) { | 2232 if (from_representation == representation()) { |
2275 return box_defn->value()->definition(); | 2233 return box_defn->value()->definition(); |
2276 } else { | 2234 } else { |
2277 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( | 2235 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( |
2278 from_representation, | 2236 from_representation, representation(), |
2279 representation(), | |
2280 box_defn->value()->CopyWithType(), | 2237 box_defn->value()->CopyWithType(), |
2281 (representation() == kUnboxedInt32) ? | 2238 (representation() == kUnboxedInt32) ? GetDeoptId() |
2282 GetDeoptId() : Thread::kNoDeoptId); | 2239 : Thread::kNoDeoptId); |
2283 // TODO(vegorov): marking resulting converter as truncating when | 2240 // TODO(vegorov): marking resulting converter as truncating when |
2284 // unboxing can't deoptimize is a workaround for the missing | 2241 // unboxing can't deoptimize is a workaround for the missing |
2285 // deoptimization environment when we insert converter after | 2242 // deoptimization environment when we insert converter after |
2286 // EliminateEnvironments and there is a mismatch between predicates | 2243 // EliminateEnvironments and there is a mismatch between predicates |
2287 // UnboxIntConverterInstr::CanDeoptimize and UnboxInt32::CanDeoptimize. | 2244 // UnboxIntConverterInstr::CanDeoptimize and UnboxInt32::CanDeoptimize. |
2288 if ((representation() == kUnboxedInt32) && | 2245 if ((representation() == kUnboxedInt32) && |
2289 (is_truncating() || !CanDeoptimize())) { | 2246 (is_truncating() || !CanDeoptimize())) { |
2290 converter->mark_truncating(); | 2247 converter->mark_truncating(); |
2291 } | 2248 } |
2292 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); | 2249 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); |
2293 return converter; | 2250 return converter; |
2294 } | 2251 } |
2295 } | 2252 } |
2296 | 2253 |
2297 return this; | 2254 return this; |
2298 } | 2255 } |
2299 | 2256 |
2300 | 2257 |
2301 Definition* UnboxInt32Instr::Canonicalize(FlowGraph* flow_graph) { | 2258 Definition* UnboxInt32Instr::Canonicalize(FlowGraph* flow_graph) { |
2302 Definition* replacement = UnboxIntegerInstr::Canonicalize(flow_graph); | 2259 Definition* replacement = UnboxIntegerInstr::Canonicalize(flow_graph); |
2303 if (replacement != this) { | 2260 if (replacement != this) { |
2304 return replacement; | 2261 return replacement; |
2305 } | 2262 } |
2306 | 2263 |
2307 ConstantInstr* c = value()->definition()->AsConstant(); | 2264 ConstantInstr* c = value()->definition()->AsConstant(); |
2308 if ((c != NULL) && c->value().IsSmi()) { | 2265 if ((c != NULL) && c->value().IsSmi()) { |
2309 if (!is_truncating() && (kSmiBits > 32)) { | 2266 if (!is_truncating() && (kSmiBits > 32)) { |
2310 // Check that constant fits into 32-bit integer. | 2267 // Check that constant fits into 32-bit integer. |
2311 const int64_t value = | 2268 const int64_t value = static_cast<int64_t>(Smi::Cast(c->value()).Value()); |
2312 static_cast<int64_t>(Smi::Cast(c->value()).Value()); | |
2313 if (!Utils::IsInt(32, value)) { | 2269 if (!Utils::IsInt(32, value)) { |
2314 return this; | 2270 return this; |
2315 } | 2271 } |
2316 } | 2272 } |
2317 | 2273 |
2318 UnboxedConstantInstr* uc = | 2274 UnboxedConstantInstr* uc = |
2319 new UnboxedConstantInstr(c->value(), kUnboxedInt32); | 2275 new UnboxedConstantInstr(c->value(), kUnboxedInt32); |
2320 if (c->range() != NULL) { | 2276 if (c->range() != NULL) { |
2321 uc->set_range(*c->range()); | 2277 uc->set_range(*c->range()); |
2322 } | 2278 } |
2323 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); | 2279 flow_graph->InsertBefore(this, uc, NULL, FlowGraph::kValue); |
2324 return uc; | 2280 return uc; |
2325 } | 2281 } |
2326 | 2282 |
2327 return this; | 2283 return this; |
2328 } | 2284 } |
2329 | 2285 |
2330 | 2286 |
2331 Definition* UnboxedIntConverterInstr::Canonicalize(FlowGraph* flow_graph) { | 2287 Definition* UnboxedIntConverterInstr::Canonicalize(FlowGraph* flow_graph) { |
2332 if (!HasUses()) return NULL; | 2288 if (!HasUses()) return NULL; |
2333 | 2289 |
2334 UnboxedIntConverterInstr* box_defn = | 2290 UnboxedIntConverterInstr* box_defn = |
2335 value()->definition()->AsUnboxedIntConverter(); | 2291 value()->definition()->AsUnboxedIntConverter(); |
2336 if ((box_defn != NULL) && (box_defn->representation() == from())) { | 2292 if ((box_defn != NULL) && (box_defn->representation() == from())) { |
2337 if (box_defn->from() == to()) { | 2293 if (box_defn->from() == to()) { |
2338 return box_defn->value()->definition(); | 2294 return box_defn->value()->definition(); |
2339 } | 2295 } |
2340 | 2296 |
2341 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( | 2297 UnboxedIntConverterInstr* converter = new UnboxedIntConverterInstr( |
2342 box_defn->from(), | 2298 box_defn->from(), representation(), box_defn->value()->CopyWithType(), |
2343 representation(), | |
2344 box_defn->value()->CopyWithType(), | |
2345 (to() == kUnboxedInt32) ? GetDeoptId() : Thread::kNoDeoptId); | 2299 (to() == kUnboxedInt32) ? GetDeoptId() : Thread::kNoDeoptId); |
2346 if ((representation() == kUnboxedInt32) && is_truncating()) { | 2300 if ((representation() == kUnboxedInt32) && is_truncating()) { |
2347 converter->mark_truncating(); | 2301 converter->mark_truncating(); |
2348 } | 2302 } |
2349 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); | 2303 flow_graph->InsertBefore(this, converter, env(), FlowGraph::kValue); |
2350 return converter; | 2304 return converter; |
2351 } | 2305 } |
2352 | 2306 |
2353 UnboxInt64Instr* unbox_defn = value()->definition()->AsUnboxInt64(); | 2307 UnboxInt64Instr* unbox_defn = value()->definition()->AsUnboxInt64(); |
2354 if (unbox_defn != NULL && | 2308 if (unbox_defn != NULL && (from() == kUnboxedMint) && |
2355 (from() == kUnboxedMint) && | 2309 (to() == kUnboxedInt32) && unbox_defn->HasOnlyInputUse(value())) { |
2356 (to() == kUnboxedInt32) && | |
2357 unbox_defn->HasOnlyInputUse(value())) { | |
2358 // TODO(vegorov): there is a duplication of code between UnboxedIntCoverter | 2310 // TODO(vegorov): there is a duplication of code between UnboxedIntCoverter |
2359 // and code path that unboxes Mint into Int32. We should just schedule | 2311 // and code path that unboxes Mint into Int32. We should just schedule |
2360 // these instructions close to each other instead of fusing them. | 2312 // these instructions close to each other instead of fusing them. |
2361 Definition* replacement = | 2313 Definition* replacement = |
2362 new UnboxInt32Instr(is_truncating() ? UnboxInt32Instr::kTruncate | 2314 new UnboxInt32Instr(is_truncating() ? UnboxInt32Instr::kTruncate |
2363 : UnboxInt32Instr::kNoTruncation, | 2315 : UnboxInt32Instr::kNoTruncation, |
2364 unbox_defn->value()->CopyWithType(), | 2316 unbox_defn->value()->CopyWithType(), GetDeoptId()); |
2365 GetDeoptId()); | 2317 flow_graph->InsertBefore(this, replacement, env(), FlowGraph::kValue); |
2366 flow_graph->InsertBefore(this, | |
2367 replacement, | |
2368 env(), | |
2369 FlowGraph::kValue); | |
2370 return replacement; | 2318 return replacement; |
2371 } | 2319 } |
2372 | 2320 |
2373 return this; | 2321 return this; |
2374 } | 2322 } |
2375 | 2323 |
2376 | 2324 |
2377 Definition* BooleanNegateInstr::Canonicalize(FlowGraph* flow_graph) { | 2325 Definition* BooleanNegateInstr::Canonicalize(FlowGraph* flow_graph) { |
2378 Definition* defn = value()->definition(); | 2326 Definition* defn = value()->definition(); |
2379 if (defn->IsComparison() && | 2327 if (defn->IsComparison() && defn->HasOnlyUse(value()) && |
2380 defn->HasOnlyUse(value()) && | |
2381 defn->Type()->ToCid() == kBoolCid) { | 2328 defn->Type()->ToCid() == kBoolCid) { |
2382 defn->AsComparison()->NegateComparison(); | 2329 defn->AsComparison()->NegateComparison(); |
2383 return defn; | 2330 return defn; |
2384 } | 2331 } |
2385 return this; | 2332 return this; |
2386 } | 2333 } |
2387 | 2334 |
2388 | 2335 |
2389 static bool MayBeBoxableNumber(intptr_t cid) { | 2336 static bool MayBeBoxableNumber(intptr_t cid) { |
2390 return (cid == kDynamicCid) || | 2337 return (cid == kDynamicCid) || (cid == kMintCid) || (cid == kBigintCid) || |
2391 (cid == kMintCid) || | |
2392 (cid == kBigintCid) || | |
2393 (cid == kDoubleCid); | 2338 (cid == kDoubleCid); |
2394 } | 2339 } |
2395 | 2340 |
2396 | 2341 |
2397 static bool MaybeNumber(CompileType* type) { | 2342 static bool MaybeNumber(CompileType* type) { |
2398 ASSERT(Type::Handle(Type::Number()).IsMoreSpecificThan( | 2343 ASSERT(Type::Handle(Type::Number()) |
2399 Type::Handle(Type::Number()), NULL, NULL, Heap::kOld)); | 2344 .IsMoreSpecificThan(Type::Handle(Type::Number()), NULL, NULL, |
2400 return type->ToAbstractType()->IsDynamicType() | 2345 Heap::kOld)); |
2401 || type->ToAbstractType()->IsObjectType() | 2346 return type->ToAbstractType()->IsDynamicType() || |
2402 || type->ToAbstractType()->IsTypeParameter() | 2347 type->ToAbstractType()->IsObjectType() || |
2403 || type->IsMoreSpecificThan(Type::Handle(Type::Number())); | 2348 type->ToAbstractType()->IsTypeParameter() || |
| 2349 type->IsMoreSpecificThan(Type::Handle(Type::Number())); |
2404 } | 2350 } |
2405 | 2351 |
2406 | 2352 |
2407 // Returns a replacement for a strict comparison and signals if the result has | 2353 // Returns a replacement for a strict comparison and signals if the result has |
2408 // to be negated. | 2354 // to be negated. |
2409 static Definition* CanonicalizeStrictCompare(StrictCompareInstr* compare, | 2355 static Definition* CanonicalizeStrictCompare(StrictCompareInstr* compare, |
2410 bool* negated, | 2356 bool* negated, |
2411 bool is_branch) { | 2357 bool is_branch) { |
2412 // Use propagated cid and type information to eliminate number checks. | 2358 // Use propagated cid and type information to eliminate number checks. |
2413 // If one of the inputs is not a boxable number (Mint, Double, Bigint), or | 2359 // If one of the inputs is not a boxable number (Mint, Double, Bigint), or |
2414 // is not a subtype of num, no need for number checks. | 2360 // is not a subtype of num, no need for number checks. |
2415 if (compare->needs_number_check()) { | 2361 if (compare->needs_number_check()) { |
2416 if (!MayBeBoxableNumber(compare->left()->Type()->ToCid()) || | 2362 if (!MayBeBoxableNumber(compare->left()->Type()->ToCid()) || |
2417 !MayBeBoxableNumber(compare->right()->Type()->ToCid())) { | 2363 !MayBeBoxableNumber(compare->right()->Type()->ToCid())) { |
2418 compare->set_needs_number_check(false); | 2364 compare->set_needs_number_check(false); |
2419 } else if (!MaybeNumber(compare->left()->Type()) || | 2365 } else if (!MaybeNumber(compare->left()->Type()) || |
2420 !MaybeNumber(compare->right()->Type())) { | 2366 !MaybeNumber(compare->right()->Type())) { |
2421 compare->set_needs_number_check(false); | 2367 compare->set_needs_number_check(false); |
2422 } | 2368 } |
2423 } | 2369 } |
2424 *negated = false; | 2370 *negated = false; |
2425 PassiveObject& constant = PassiveObject::Handle(); | 2371 PassiveObject& constant = PassiveObject::Handle(); |
2426 Value* other = NULL; | 2372 Value* other = NULL; |
2427 if (compare->right()->BindsToConstant()) { | 2373 if (compare->right()->BindsToConstant()) { |
2428 constant = compare->right()->BoundConstant().raw(); | 2374 constant = compare->right()->BoundConstant().raw(); |
2429 other = compare->left(); | 2375 other = compare->left(); |
2430 } else if (compare->left()->BindsToConstant()) { | 2376 } else if (compare->left()->BindsToConstant()) { |
2431 constant = compare->left()->BoundConstant().raw(); | 2377 constant = compare->left()->BoundConstant().raw(); |
2432 other = compare->right(); | 2378 other = compare->right(); |
2433 } else { | 2379 } else { |
2434 return compare; | 2380 return compare; |
2435 } | 2381 } |
2436 | 2382 |
2437 const bool can_merge = is_branch || (other->Type()->ToCid() == kBoolCid); | 2383 const bool can_merge = is_branch || (other->Type()->ToCid() == kBoolCid); |
2438 Definition* other_defn = other->definition(); | 2384 Definition* other_defn = other->definition(); |
2439 Token::Kind kind = compare->kind(); | 2385 Token::Kind kind = compare->kind(); |
2440 // Handle e === true. | 2386 // Handle e === true. |
2441 if ((kind == Token::kEQ_STRICT) && | 2387 if ((kind == Token::kEQ_STRICT) && (constant.raw() == Bool::True().raw()) && |
2442 (constant.raw() == Bool::True().raw()) && | |
2443 can_merge) { | 2388 can_merge) { |
2444 return other_defn; | 2389 return other_defn; |
2445 } | 2390 } |
2446 // Handle e !== false. | 2391 // Handle e !== false. |
2447 if ((kind == Token::kNE_STRICT) && | 2392 if ((kind == Token::kNE_STRICT) && (constant.raw() == Bool::False().raw()) && |
2448 (constant.raw() == Bool::False().raw()) && | |
2449 can_merge) { | 2393 can_merge) { |
2450 return other_defn; | 2394 return other_defn; |
2451 } | 2395 } |
2452 // Handle e !== true. | 2396 // Handle e !== true. |
2453 if ((kind == Token::kNE_STRICT) && | 2397 if ((kind == Token::kNE_STRICT) && (constant.raw() == Bool::True().raw()) && |
2454 (constant.raw() == Bool::True().raw()) && | 2398 other_defn->IsComparison() && can_merge && |
2455 other_defn->IsComparison() && | |
2456 can_merge && | |
2457 other_defn->HasOnlyUse(other)) { | 2399 other_defn->HasOnlyUse(other)) { |
2458 *negated = true; | 2400 *negated = true; |
2459 return other_defn; | 2401 return other_defn; |
2460 } | 2402 } |
2461 // Handle e === false. | 2403 // Handle e === false. |
2462 if ((kind == Token::kEQ_STRICT) && | 2404 if ((kind == Token::kEQ_STRICT) && (constant.raw() == Bool::False().raw()) && |
2463 (constant.raw() == Bool::False().raw()) && | 2405 other_defn->IsComparison() && can_merge && |
2464 other_defn->IsComparison() && | |
2465 can_merge && | |
2466 other_defn->HasOnlyUse(other)) { | 2406 other_defn->HasOnlyUse(other)) { |
2467 *negated = true; | 2407 *negated = true; |
2468 return other_defn; | 2408 return other_defn; |
2469 } | 2409 } |
2470 return compare; | 2410 return compare; |
2471 } | 2411 } |
2472 | 2412 |
2473 | 2413 |
2474 static bool BindsToGivenConstant(Value* v, intptr_t expected) { | 2414 static bool BindsToGivenConstant(Value* v, intptr_t expected) { |
2475 return v->BindsToConstant() && | 2415 return v->BindsToConstant() && v->BoundConstant().IsSmi() && |
2476 v->BoundConstant().IsSmi() && | 2416 (Smi::Cast(v->BoundConstant()).Value() == expected); |
2477 (Smi::Cast(v->BoundConstant()).Value() == expected); | |
2478 } | 2417 } |
2479 | 2418 |
2480 | 2419 |
2481 // Recognize patterns (a & b) == 0 and (a & 2^n) != 2^n. | 2420 // Recognize patterns (a & b) == 0 and (a & 2^n) != 2^n. |
2482 static bool RecognizeTestPattern(Value* left, Value* right, bool* negate) { | 2421 static bool RecognizeTestPattern(Value* left, Value* right, bool* negate) { |
2483 if (!right->BindsToConstant() || !right->BoundConstant().IsSmi()) { | 2422 if (!right->BindsToConstant() || !right->BoundConstant().IsSmi()) { |
2484 return false; | 2423 return false; |
2485 } | 2424 } |
2486 | 2425 |
2487 const intptr_t value = Smi::Cast(right->BoundConstant()).Value(); | 2426 const intptr_t value = Smi::Cast(right->BoundConstant()).Value(); |
2488 if ((value != 0) && !Utils::IsPowerOfTwo(value)) { | 2427 if ((value != 0) && !Utils::IsPowerOfTwo(value)) { |
2489 return false; | 2428 return false; |
2490 } | 2429 } |
2491 | 2430 |
2492 | 2431 |
2493 BinarySmiOpInstr* mask_op = left->definition()->AsBinarySmiOp(); | 2432 BinarySmiOpInstr* mask_op = left->definition()->AsBinarySmiOp(); |
2494 if ((mask_op == NULL) || | 2433 if ((mask_op == NULL) || (mask_op->op_kind() != Token::kBIT_AND) || |
2495 (mask_op->op_kind() != Token::kBIT_AND) || | |
2496 !mask_op->HasOnlyUse(left)) { | 2434 !mask_op->HasOnlyUse(left)) { |
2497 return false; | 2435 return false; |
2498 } | 2436 } |
2499 | 2437 |
2500 if (value == 0) { | 2438 if (value == 0) { |
2501 // Recognized (a & b) == 0 pattern. | 2439 // Recognized (a & b) == 0 pattern. |
2502 *negate = false; | 2440 *negate = false; |
2503 return true; | 2441 return true; |
2504 } | 2442 } |
2505 | 2443 |
2506 // Recognize | 2444 // Recognize |
2507 if (BindsToGivenConstant(mask_op->left(), value) || | 2445 if (BindsToGivenConstant(mask_op->left(), value) || |
2508 BindsToGivenConstant(mask_op->right(), value)) { | 2446 BindsToGivenConstant(mask_op->right(), value)) { |
2509 // Recognized (a & 2^n) == 2^n pattern. It's equivalent to (a & 2^n) != 0 | 2447 // Recognized (a & 2^n) == 2^n pattern. It's equivalent to (a & 2^n) != 0 |
2510 // so we need to negate original comparison. | 2448 // so we need to negate original comparison. |
2511 *negate = true; | 2449 *negate = true; |
2512 return true; | 2450 return true; |
2513 } | 2451 } |
2514 | 2452 |
2515 return false; | 2453 return false; |
2516 } | 2454 } |
2517 | 2455 |
2518 | 2456 |
2519 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { | 2457 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { |
2520 Zone* zone = flow_graph->zone(); | 2458 Zone* zone = flow_graph->zone(); |
2521 // Only handle strict-compares. | 2459 // Only handle strict-compares. |
2522 if (comparison()->IsStrictCompare()) { | 2460 if (comparison()->IsStrictCompare()) { |
2523 bool negated = false; | 2461 bool negated = false; |
2524 Definition* replacement = | 2462 Definition* replacement = CanonicalizeStrictCompare( |
2525 CanonicalizeStrictCompare(comparison()->AsStrictCompare(), | 2463 comparison()->AsStrictCompare(), &negated, /* is_branch = */ true); |
2526 &negated, /* is_branch = */ true); | |
2527 if (replacement == comparison()) { | 2464 if (replacement == comparison()) { |
2528 return this; | 2465 return this; |
2529 } | 2466 } |
2530 ComparisonInstr* comp = replacement->AsComparison(); | 2467 ComparisonInstr* comp = replacement->AsComparison(); |
2531 if ((comp == NULL) || | 2468 if ((comp == NULL) || comp->CanDeoptimize() || |
2532 comp->CanDeoptimize() || | |
2533 comp->HasUnmatchedInputRepresentations()) { | 2469 comp->HasUnmatchedInputRepresentations()) { |
2534 return this; | 2470 return this; |
2535 } | 2471 } |
2536 | 2472 |
2537 // Replace the comparison if the replacement is used at this branch, | 2473 // Replace the comparison if the replacement is used at this branch, |
2538 // and has exactly one use. | 2474 // and has exactly one use. |
2539 Value* use = comp->input_use_list(); | 2475 Value* use = comp->input_use_list(); |
2540 if ((use->instruction() == this) && comp->HasOnlyUse(use)) { | 2476 if ((use->instruction() == this) && comp->HasOnlyUse(use)) { |
2541 if (negated) { | 2477 if (negated) { |
2542 comp->NegateComparison(); | 2478 comp->NegateComparison(); |
(...skipping 12 matching lines...) Expand all Loading... |
2555 // Clear the comparison's temp index and ssa temp index since the | 2491 // Clear the comparison's temp index and ssa temp index since the |
2556 // value of the comparison is not used outside the branch anymore. | 2492 // value of the comparison is not used outside the branch anymore. |
2557 ASSERT(comp->input_use_list() == NULL); | 2493 ASSERT(comp->input_use_list() == NULL); |
2558 comp->ClearSSATempIndex(); | 2494 comp->ClearSSATempIndex(); |
2559 comp->ClearTempIndex(); | 2495 comp->ClearTempIndex(); |
2560 } | 2496 } |
2561 } else if (comparison()->IsEqualityCompare() && | 2497 } else if (comparison()->IsEqualityCompare() && |
2562 comparison()->operation_cid() == kSmiCid) { | 2498 comparison()->operation_cid() == kSmiCid) { |
2563 BinarySmiOpInstr* bit_and = NULL; | 2499 BinarySmiOpInstr* bit_and = NULL; |
2564 bool negate = false; | 2500 bool negate = false; |
2565 if (RecognizeTestPattern(comparison()->left(), | 2501 if (RecognizeTestPattern(comparison()->left(), comparison()->right(), |
2566 comparison()->right(), | |
2567 &negate)) { | 2502 &negate)) { |
2568 bit_and = comparison()->left()->definition()->AsBinarySmiOp(); | 2503 bit_and = comparison()->left()->definition()->AsBinarySmiOp(); |
2569 } else if (RecognizeTestPattern(comparison()->right(), | 2504 } else if (RecognizeTestPattern(comparison()->right(), comparison()->left(), |
2570 comparison()->left(), | |
2571 &negate)) { | 2505 &negate)) { |
2572 bit_and = comparison()->right()->definition()->AsBinarySmiOp(); | 2506 bit_and = comparison()->right()->definition()->AsBinarySmiOp(); |
2573 } | 2507 } |
2574 if (bit_and != NULL) { | 2508 if (bit_and != NULL) { |
2575 if (FLAG_trace_optimization) { | 2509 if (FLAG_trace_optimization) { |
2576 OS::Print("Merging test smi v%" Pd "\n", bit_and->ssa_temp_index()); | 2510 OS::Print("Merging test smi v%" Pd "\n", bit_and->ssa_temp_index()); |
2577 } | 2511 } |
2578 TestSmiInstr* test = new TestSmiInstr( | 2512 TestSmiInstr* test = new TestSmiInstr( |
2579 comparison()->token_pos(), | 2513 comparison()->token_pos(), |
2580 negate ? Token::NegateComparison(comparison()->kind()) | 2514 negate ? Token::NegateComparison(comparison()->kind()) |
2581 : comparison()->kind(), | 2515 : comparison()->kind(), |
2582 bit_and->left()->Copy(zone), | 2516 bit_and->left()->Copy(zone), bit_and->right()->Copy(zone)); |
2583 bit_and->right()->Copy(zone)); | |
2584 ASSERT(!CanDeoptimize()); | 2517 ASSERT(!CanDeoptimize()); |
2585 RemoveEnvironment(); | 2518 RemoveEnvironment(); |
2586 flow_graph->CopyDeoptTarget(this, bit_and); | 2519 flow_graph->CopyDeoptTarget(this, bit_and); |
2587 SetComparison(test); | 2520 SetComparison(test); |
2588 bit_and->RemoveFromGraph(); | 2521 bit_and->RemoveFromGraph(); |
2589 } | 2522 } |
2590 } | 2523 } |
2591 return this; | 2524 return this; |
2592 } | 2525 } |
2593 | 2526 |
(...skipping 17 matching lines...) Expand all Loading... |
2611 return this; | 2544 return this; |
2612 } | 2545 } |
2613 | 2546 |
2614 return unary_checks().HasReceiverClassId(value_cid) ? NULL : this; | 2547 return unary_checks().HasReceiverClassId(value_cid) ? NULL : this; |
2615 } | 2548 } |
2616 | 2549 |
2617 | 2550 |
2618 Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) { | 2551 Instruction* CheckClassIdInstr::Canonicalize(FlowGraph* flow_graph) { |
2619 if (value()->BindsToConstant()) { | 2552 if (value()->BindsToConstant()) { |
2620 const Object& constant_value = value()->BoundConstant(); | 2553 const Object& constant_value = value()->BoundConstant(); |
2621 if (constant_value.IsSmi() && | 2554 if (constant_value.IsSmi() && Smi::Cast(constant_value).Value() == cid_) { |
2622 Smi::Cast(constant_value).Value() == cid_) { | |
2623 return NULL; | 2555 return NULL; |
2624 } | 2556 } |
2625 } | 2557 } |
2626 return this; | 2558 return this; |
2627 } | 2559 } |
2628 | 2560 |
2629 | 2561 |
2630 Definition* TestCidsInstr::Canonicalize(FlowGraph* flow_graph) { | 2562 Definition* TestCidsInstr::Canonicalize(FlowGraph* flow_graph) { |
2631 CompileType* in_type = left()->Type(); | 2563 CompileType* in_type = left()->Type(); |
2632 intptr_t cid = in_type->ToCid(); | 2564 intptr_t cid = in_type->ToCid(); |
2633 if (cid == kDynamicCid) return this; | 2565 if (cid == kDynamicCid) return this; |
2634 | 2566 |
2635 const ZoneGrowableArray<intptr_t>& data = cid_results(); | 2567 const ZoneGrowableArray<intptr_t>& data = cid_results(); |
2636 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; | 2568 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0; |
2637 for (intptr_t i = 0; i < data.length(); i += 2) { | 2569 for (intptr_t i = 0; i < data.length(); i += 2) { |
2638 if (data[i] == cid) { | 2570 if (data[i] == cid) { |
2639 return (data[i + 1] == true_result) | 2571 return (data[i + 1] == true_result) |
2640 ? flow_graph->GetConstant(Bool::True()) | 2572 ? flow_graph->GetConstant(Bool::True()) |
2641 : flow_graph->GetConstant(Bool::False()); | 2573 : flow_graph->GetConstant(Bool::False()); |
2642 } | 2574 } |
2643 } | 2575 } |
2644 | 2576 |
2645 // TODO(sra): Handle misses if the instruction is not deoptimizing. | 2577 // TODO(sra): Handle misses if the instruction is not deoptimizing. |
2646 // TODO(sra): Handle nullable input, possibly canonicalizing to a compare | 2578 // TODO(sra): Handle nullable input, possibly canonicalizing to a compare |
2647 // against `null`. | 2579 // against `null`. |
2648 return this; | 2580 return this; |
2649 } | 2581 } |
2650 | 2582 |
2651 | 2583 |
(...skipping 30 matching lines...) Expand all Loading... |
2682 StaticCallInstr* call = value()->definition()->AsStaticCall(); | 2614 StaticCallInstr* call = value()->definition()->AsStaticCall(); |
2683 if (call == NULL) { | 2615 if (call == NULL) { |
2684 return this; | 2616 return this; |
2685 } | 2617 } |
2686 | 2618 |
2687 ConstantInstr* length = NULL; | 2619 ConstantInstr* length = NULL; |
2688 if (call->is_known_list_constructor() && | 2620 if (call->is_known_list_constructor() && |
2689 LoadFieldInstr::IsFixedLengthArrayCid(call->Type()->ToCid())) { | 2621 LoadFieldInstr::IsFixedLengthArrayCid(call->Type()->ToCid())) { |
2690 length = call->ArgumentAt(1)->AsConstant(); | 2622 length = call->ArgumentAt(1)->AsConstant(); |
2691 } | 2623 } |
2692 if ((length != NULL) && | 2624 if ((length != NULL) && length->value().IsSmi() && |
2693 length->value().IsSmi() && | |
2694 Smi::Cast(length->value()).Value() == expected_length) { | 2625 Smi::Cast(length->value()).Value() == expected_length) { |
2695 return NULL; // Expected length matched. | 2626 return NULL; // Expected length matched. |
2696 } | 2627 } |
2697 | 2628 |
2698 return this; | 2629 return this; |
2699 } | 2630 } |
2700 | 2631 |
2701 | 2632 |
2702 Instruction* CheckSmiInstr::Canonicalize(FlowGraph* flow_graph) { | 2633 Instruction* CheckSmiInstr::Canonicalize(FlowGraph* flow_graph) { |
2703 return (value()->Type()->ToCid() == kSmiCid) ? NULL : this; | 2634 return (value()->Type()->ToCid() == kSmiCid) ? NULL : this; |
2704 } | 2635 } |
2705 | 2636 |
2706 | 2637 |
2707 Instruction* CheckEitherNonSmiInstr::Canonicalize(FlowGraph* flow_graph) { | 2638 Instruction* CheckEitherNonSmiInstr::Canonicalize(FlowGraph* flow_graph) { |
2708 if ((left()->Type()->ToCid() == kDoubleCid) || | 2639 if ((left()->Type()->ToCid() == kDoubleCid) || |
2709 (right()->Type()->ToCid() == kDoubleCid)) { | 2640 (right()->Type()->ToCid() == kDoubleCid)) { |
2710 return NULL; // Remove from the graph. | 2641 return NULL; // Remove from the graph. |
2711 } | 2642 } |
2712 return this; | 2643 return this; |
2713 } | 2644 } |
(...skipping 21 matching lines...) Expand all Loading... |
2735 return NULL; | 2666 return NULL; |
2736 } | 2667 } |
2737 } | 2668 } |
2738 | 2669 |
2739 | 2670 |
2740 UnboxInstr* UnboxInstr::Create(Representation to, | 2671 UnboxInstr* UnboxInstr::Create(Representation to, |
2741 Value* value, | 2672 Value* value, |
2742 intptr_t deopt_id) { | 2673 intptr_t deopt_id) { |
2743 switch (to) { | 2674 switch (to) { |
2744 case kUnboxedInt32: | 2675 case kUnboxedInt32: |
2745 return new UnboxInt32Instr( | 2676 return new UnboxInt32Instr(UnboxInt32Instr::kNoTruncation, value, |
2746 UnboxInt32Instr::kNoTruncation, value, deopt_id); | 2677 deopt_id); |
2747 | 2678 |
2748 case kUnboxedUint32: | 2679 case kUnboxedUint32: |
2749 return new UnboxUint32Instr(value, deopt_id); | 2680 return new UnboxUint32Instr(value, deopt_id); |
2750 | 2681 |
2751 case kUnboxedMint: | 2682 case kUnboxedMint: |
2752 return new UnboxInt64Instr(value, deopt_id); | 2683 return new UnboxInt64Instr(value, deopt_id); |
2753 | 2684 |
2754 case kUnboxedDouble: | 2685 case kUnboxedDouble: |
2755 case kUnboxedFloat32x4: | 2686 case kUnboxedFloat32x4: |
2756 case kUnboxedFloat64x2: | 2687 case kUnboxedFloat64x2: |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2799 LocationSummary* JoinEntryInstr::MakeLocationSummary(Zone* zone, | 2730 LocationSummary* JoinEntryInstr::MakeLocationSummary(Zone* zone, |
2800 bool optimizing) const { | 2731 bool optimizing) const { |
2801 UNREACHABLE(); | 2732 UNREACHABLE(); |
2802 return NULL; | 2733 return NULL; |
2803 } | 2734 } |
2804 | 2735 |
2805 | 2736 |
2806 void JoinEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2737 void JoinEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2807 __ Bind(compiler->GetJumpLabel(this)); | 2738 __ Bind(compiler->GetJumpLabel(this)); |
2808 if (!compiler->is_optimizing()) { | 2739 if (!compiler->is_optimizing()) { |
2809 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 2740 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, GetDeoptId(), |
2810 GetDeoptId(), | |
2811 TokenPosition::kNoSource); | 2741 TokenPosition::kNoSource); |
2812 } | 2742 } |
2813 if (HasParallelMove()) { | 2743 if (HasParallelMove()) { |
2814 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); | 2744 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
2815 } | 2745 } |
2816 } | 2746 } |
2817 | 2747 |
2818 | 2748 |
2819 LocationSummary* TargetEntryInstr::MakeLocationSummary(Zone* zone, | 2749 LocationSummary* TargetEntryInstr::MakeLocationSummary(Zone* zone, |
2820 bool optimizing) const { | 2750 bool optimizing) const { |
2821 UNREACHABLE(); | 2751 UNREACHABLE(); |
2822 return NULL; | 2752 return NULL; |
2823 } | 2753 } |
2824 | 2754 |
2825 | 2755 |
2826 void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2756 void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2827 __ Bind(compiler->GetJumpLabel(this)); | 2757 __ Bind(compiler->GetJumpLabel(this)); |
2828 if (!compiler->is_optimizing()) { | 2758 if (!compiler->is_optimizing()) { |
2829 #if !defined(TARGET_ARCH_DBC) | 2759 #if !defined(TARGET_ARCH_DBC) |
2830 // TODO(vegorov) re-enable edge counters on DBC if we consider them | 2760 // TODO(vegorov) re-enable edge counters on DBC if we consider them |
2831 // beneficial for the quality of the optimized bytecode. | 2761 // beneficial for the quality of the optimized bytecode. |
2832 if (compiler->NeedsEdgeCounter(this)) { | 2762 if (compiler->NeedsEdgeCounter(this)) { |
2833 compiler->EmitEdgeCounter(preorder_number()); | 2763 compiler->EmitEdgeCounter(preorder_number()); |
2834 } | 2764 } |
2835 #endif | 2765 #endif |
2836 | 2766 |
2837 // The deoptimization descriptor points after the edge counter code for | 2767 // The deoptimization descriptor points after the edge counter code for |
2838 // uniformity with ARM and MIPS, where we can reuse pattern matching | 2768 // uniformity with ARM and MIPS, where we can reuse pattern matching |
2839 // code that matches backwards from the end of the pattern. | 2769 // code that matches backwards from the end of the pattern. |
2840 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 2770 compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt, GetDeoptId(), |
2841 GetDeoptId(), | |
2842 TokenPosition::kNoSource); | 2771 TokenPosition::kNoSource); |
2843 } | 2772 } |
2844 if (HasParallelMove()) { | 2773 if (HasParallelMove()) { |
2845 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); | 2774 compiler->parallel_move_resolver()->EmitNativeCode(parallel_move()); |
2846 } | 2775 } |
2847 } | 2776 } |
2848 | 2777 |
2849 | 2778 |
2850 void IndirectGotoInstr::ComputeOffsetTable() { | 2779 void IndirectGotoInstr::ComputeOffsetTable() { |
2851 if (GetBlock()->offset() < 0) { | 2780 if (GetBlock()->offset() < 0) { |
(...skipping 23 matching lines...) Expand all Loading... |
2875 offset = ientry->offset(); | 2804 offset = ientry->offset(); |
2876 } | 2805 } |
2877 | 2806 |
2878 ASSERT(offset > 0); | 2807 ASSERT(offset > 0); |
2879 offsets_.SetInt32(i * element_size, offset); | 2808 offsets_.SetInt32(i * element_size, offset); |
2880 } | 2809 } |
2881 } | 2810 } |
2882 | 2811 |
2883 | 2812 |
2884 LocationSummary* IndirectEntryInstr::MakeLocationSummary( | 2813 LocationSummary* IndirectEntryInstr::MakeLocationSummary( |
2885 Zone* zone, bool optimizing) const { | 2814 Zone* zone, |
| 2815 bool optimizing) const { |
2886 return JoinEntryInstr::MakeLocationSummary(zone, optimizing); | 2816 return JoinEntryInstr::MakeLocationSummary(zone, optimizing); |
2887 } | 2817 } |
2888 | 2818 |
2889 | 2819 |
2890 void IndirectEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2820 void IndirectEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2891 JoinEntryInstr::EmitNativeCode(compiler); | 2821 JoinEntryInstr::EmitNativeCode(compiler); |
2892 } | 2822 } |
2893 | 2823 |
2894 | 2824 |
2895 LocationSummary* PhiInstr::MakeLocationSummary(Zone* zone, | 2825 LocationSummary* PhiInstr::MakeLocationSummary(Zone* zone, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2955 return NULL; | 2885 return NULL; |
2956 } | 2886 } |
2957 | 2887 |
2958 | 2888 |
2959 void ConstraintInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2889 void ConstraintInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2960 UNREACHABLE(); | 2890 UNREACHABLE(); |
2961 } | 2891 } |
2962 | 2892 |
2963 | 2893 |
2964 LocationSummary* MaterializeObjectInstr::MakeLocationSummary( | 2894 LocationSummary* MaterializeObjectInstr::MakeLocationSummary( |
2965 Zone* zone, bool optimizing) const { | 2895 Zone* zone, |
| 2896 bool optimizing) const { |
2966 UNREACHABLE(); | 2897 UNREACHABLE(); |
2967 return NULL; | 2898 return NULL; |
2968 } | 2899 } |
2969 | 2900 |
2970 | 2901 |
2971 void MaterializeObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2902 void MaterializeObjectInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2972 UNREACHABLE(); | 2903 UNREACHABLE(); |
2973 } | 2904 } |
2974 | 2905 |
2975 | 2906 |
(...skipping 23 matching lines...) Expand all Loading... |
2999 | 2930 |
3000 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2931 void CurrentContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3001 // Only appears in initial definitions, never in normal code. | 2932 // Only appears in initial definitions, never in normal code. |
3002 UNREACHABLE(); | 2933 UNREACHABLE(); |
3003 } | 2934 } |
3004 | 2935 |
3005 | 2936 |
3006 LocationSummary* DropTempsInstr::MakeLocationSummary(Zone* zone, | 2937 LocationSummary* DropTempsInstr::MakeLocationSummary(Zone* zone, |
3007 bool optimizing) const { | 2938 bool optimizing) const { |
3008 return (InputCount() == 1) | 2939 return (InputCount() == 1) |
3009 ? LocationSummary::Make(zone, | 2940 ? LocationSummary::Make(zone, 1, Location::SameAsFirstInput(), |
3010 1, | 2941 LocationSummary::kNoCall) |
3011 Location::SameAsFirstInput(), | 2942 : LocationSummary::Make(zone, 0, Location::NoLocation(), |
3012 LocationSummary::kNoCall) | 2943 LocationSummary::kNoCall); |
3013 : LocationSummary::Make(zone, | |
3014 0, | |
3015 Location::NoLocation(), | |
3016 LocationSummary::kNoCall); | |
3017 } | 2944 } |
3018 | 2945 |
3019 | 2946 |
3020 void DropTempsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2947 void DropTempsInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3021 #if defined(TARGET_ARCH_DBC) | 2948 #if defined(TARGET_ARCH_DBC) |
3022 // On DBC the action of poping the TOS value and then pushing it | 2949 // On DBC the action of poping the TOS value and then pushing it |
3023 // after all intermediates are poped is folded into a special | 2950 // after all intermediates are poped is folded into a special |
3024 // bytecode (DropR). On other architectures this is handled by | 2951 // bytecode (DropR). On other architectures this is handled by |
3025 // instruction prologue/epilogues. | 2952 // instruction prologue/epilogues. |
3026 ASSERT(!compiler->is_optimizing()); | 2953 ASSERT(!compiler->is_optimizing()); |
3027 if ((InputCount() != 0) && HasTemp()) { | 2954 if ((InputCount() != 0) && HasTemp()) { |
3028 __ DropR(num_temps()); | 2955 __ DropR(num_temps()); |
3029 } else { | 2956 } else { |
3030 __ Drop(num_temps() + ((InputCount() != 0) ? 1 : 0)); | 2957 __ Drop(num_temps() + ((InputCount() != 0) ? 1 : 0)); |
3031 } | 2958 } |
3032 #else | 2959 #else |
3033 ASSERT(!compiler->is_optimizing()); | 2960 ASSERT(!compiler->is_optimizing()); |
3034 // Assert that register assignment is correct. | 2961 // Assert that register assignment is correct. |
3035 ASSERT((InputCount() == 0) || (locs()->out(0).reg() == locs()->in(0).reg())); | 2962 ASSERT((InputCount() == 0) || (locs()->out(0).reg() == locs()->in(0).reg())); |
3036 __ Drop(num_temps()); | 2963 __ Drop(num_temps()); |
3037 #endif // defined(TARGET_ARCH_DBC) | 2964 #endif // defined(TARGET_ARCH_DBC) |
3038 } | 2965 } |
3039 | 2966 |
3040 | 2967 |
3041 StrictCompareInstr::StrictCompareInstr(TokenPosition token_pos, | 2968 StrictCompareInstr::StrictCompareInstr(TokenPosition token_pos, |
3042 Token::Kind kind, | 2969 Token::Kind kind, |
3043 Value* left, | 2970 Value* left, |
3044 Value* right, | 2971 Value* right, |
3045 bool needs_number_check) | 2972 bool needs_number_check) |
3046 : TemplateComparison(token_pos, | 2973 : TemplateComparison(token_pos, kind, Thread::Current()->GetNextDeoptId()), |
3047 kind, | |
3048 Thread::Current()->GetNextDeoptId()), | |
3049 needs_number_check_(needs_number_check) { | 2974 needs_number_check_(needs_number_check) { |
3050 ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT)); | 2975 ASSERT((kind == Token::kEQ_STRICT) || (kind == Token::kNE_STRICT)); |
3051 SetInputAt(0, left); | 2976 SetInputAt(0, left); |
3052 SetInputAt(1, right); | 2977 SetInputAt(1, right); |
3053 } | 2978 } |
3054 | 2979 |
3055 | 2980 |
3056 LocationSummary* InstanceCallInstr::MakeLocationSummary(Zone* zone, | 2981 LocationSummary* InstanceCallInstr::MakeLocationSummary(Zone* zone, |
3057 bool optimizing) const { | 2982 bool optimizing) const { |
3058 return MakeCallSummary(zone); | 2983 return MakeCallSummary(zone); |
3059 } | 2984 } |
3060 | 2985 |
3061 | 2986 |
3062 // DBC does not use specialized inline cache stubs for smi operations. | 2987 // DBC does not use specialized inline cache stubs for smi operations. |
3063 #if !defined(TARGET_ARCH_DBC) | 2988 #if !defined(TARGET_ARCH_DBC) |
3064 static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) { | 2989 static const StubEntry* TwoArgsSmiOpInlineCacheEntry(Token::Kind kind) { |
3065 if (!FLAG_two_args_smi_icd) { | 2990 if (!FLAG_two_args_smi_icd) { |
3066 return 0; | 2991 return 0; |
3067 } | 2992 } |
3068 switch (kind) { | 2993 switch (kind) { |
3069 case Token::kADD: return StubCode::SmiAddInlineCache_entry(); | 2994 case Token::kADD: |
3070 case Token::kSUB: return StubCode::SmiSubInlineCache_entry(); | 2995 return StubCode::SmiAddInlineCache_entry(); |
3071 case Token::kEQ: return StubCode::SmiEqualInlineCache_entry(); | 2996 case Token::kSUB: |
3072 default: return NULL; | 2997 return StubCode::SmiSubInlineCache_entry(); |
| 2998 case Token::kEQ: |
| 2999 return StubCode::SmiEqualInlineCache_entry(); |
| 3000 default: |
| 3001 return NULL; |
3073 } | 3002 } |
3074 } | 3003 } |
3075 #else | 3004 #else |
3076 static void TryFastPathSmiOp( | 3005 static void TryFastPathSmiOp(FlowGraphCompiler* compiler, |
3077 FlowGraphCompiler* compiler, ICData* call_ic_data, const String& name) { | 3006 ICData* call_ic_data, |
| 3007 const String& name) { |
3078 if (!FLAG_two_args_smi_icd) { | 3008 if (!FLAG_two_args_smi_icd) { |
3079 return; | 3009 return; |
3080 } | 3010 } |
3081 if (name.raw() == Symbols::Plus().raw()) { | 3011 if (name.raw() == Symbols::Plus().raw()) { |
3082 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3012 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
3083 __ AddTOS(); | 3013 __ AddTOS(); |
3084 } | 3014 } |
3085 } else if (name.raw() == Symbols::Minus().raw()) { | 3015 } else if (name.raw() == Symbols::Minus().raw()) { |
3086 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3016 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
3087 __ SubTOS(); | 3017 __ SubTOS(); |
3088 } | 3018 } |
3089 } else if (name.raw() == Symbols::EqualOperator().raw()) { | 3019 } else if (name.raw() == Symbols::EqualOperator().raw()) { |
3090 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3020 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
3091 __ EqualTOS(); | 3021 __ EqualTOS(); |
3092 } | 3022 } |
3093 } else if (name.raw() == Symbols::LAngleBracket().raw()) { | 3023 } else if (name.raw() == Symbols::LAngleBracket().raw()) { |
3094 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3024 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
3095 __ LessThanTOS(); | 3025 __ LessThanTOS(); |
3096 } | 3026 } |
3097 } else if (name.raw() == Symbols::RAngleBracket().raw()) { | 3027 } else if (name.raw() == Symbols::RAngleBracket().raw()) { |
3098 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3028 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
3099 __ GreaterThanTOS(); | 3029 __ GreaterThanTOS(); |
3100 } | 3030 } |
3101 } else if (name.raw() == Symbols::BitAnd().raw()) { | 3031 } else if (name.raw() == Symbols::BitAnd().raw()) { |
3102 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3032 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
3103 __ BitAndTOS(); | 3033 __ BitAndTOS(); |
3104 } | 3034 } |
3105 } else if (name.raw() == Symbols::BitOr().raw()) { | 3035 } else if (name.raw() == Symbols::BitOr().raw()) { |
3106 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3036 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
3107 __ BitOrTOS(); | 3037 __ BitOrTOS(); |
3108 } | 3038 } |
3109 } else if (name.raw() == Symbols::Star().raw()) { | 3039 } else if (name.raw() == Symbols::Star().raw()) { |
3110 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { | 3040 if (call_ic_data->AddSmiSmiCheckForFastSmiStubs()) { |
3111 __ MulTOS(); | 3041 __ MulTOS(); |
3112 } | 3042 } |
3113 } | 3043 } |
3114 } | 3044 } |
3115 #endif | 3045 #endif |
3116 | 3046 |
3117 | 3047 |
3118 void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3048 void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3119 Zone* zone = compiler->zone(); | 3049 Zone* zone = compiler->zone(); |
3120 const ICData* call_ic_data = NULL; | 3050 const ICData* call_ic_data = NULL; |
3121 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || | 3051 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || |
3122 (ic_data() == NULL)) { | 3052 (ic_data() == NULL)) { |
3123 const Array& arguments_descriptor = | 3053 const Array& arguments_descriptor = Array::Handle( |
3124 Array::Handle(zone, ArgumentsDescriptor::New(ArgumentCount(), | 3054 zone, ArgumentsDescriptor::New(ArgumentCount(), argument_names())); |
3125 argument_names())); | |
3126 call_ic_data = compiler->GetOrAddInstanceCallICData( | 3055 call_ic_data = compiler->GetOrAddInstanceCallICData( |
3127 deopt_id(), function_name(), arguments_descriptor, | 3056 deopt_id(), function_name(), arguments_descriptor, |
3128 checked_argument_count()); | 3057 checked_argument_count()); |
3129 } else { | 3058 } else { |
3130 call_ic_data = &ICData::ZoneHandle(zone, ic_data()->raw()); | 3059 call_ic_data = &ICData::ZoneHandle(zone, ic_data()->raw()); |
3131 } | 3060 } |
3132 | 3061 |
3133 #if !defined(TARGET_ARCH_DBC) | 3062 #if !defined(TARGET_ARCH_DBC) |
3134 if (compiler->is_optimizing() && HasICData()) { | 3063 if (compiler->is_optimizing() && HasICData()) { |
3135 ASSERT(HasICData()); | 3064 ASSERT(HasICData()); |
3136 if (ic_data()->NumberOfUsedChecks() > 0) { | 3065 if (ic_data()->NumberOfUsedChecks() > 0) { |
3137 const ICData& unary_ic_data = | 3066 const ICData& unary_ic_data = |
3138 ICData::ZoneHandle(zone, ic_data()->AsUnaryClassChecks()); | 3067 ICData::ZoneHandle(zone, ic_data()->AsUnaryClassChecks()); |
3139 compiler->GenerateInstanceCall(deopt_id(), | 3068 compiler->GenerateInstanceCall(deopt_id(), token_pos(), ArgumentCount(), |
3140 token_pos(), | 3069 locs(), unary_ic_data); |
3141 ArgumentCount(), | |
3142 locs(), | |
3143 unary_ic_data); | |
3144 } else { | 3070 } else { |
3145 // Call was not visited yet, use original ICData in order to populate it. | 3071 // Call was not visited yet, use original ICData in order to populate it. |
3146 compiler->GenerateInstanceCall(deopt_id(), | 3072 compiler->GenerateInstanceCall(deopt_id(), token_pos(), ArgumentCount(), |
3147 token_pos(), | 3073 locs(), *call_ic_data); |
3148 ArgumentCount(), | |
3149 locs(), | |
3150 *call_ic_data); | |
3151 } | 3074 } |
3152 } else { | 3075 } else { |
3153 // Unoptimized code. | 3076 // Unoptimized code. |
3154 ASSERT(!HasICData()); | 3077 ASSERT(!HasICData()); |
3155 bool is_smi_two_args_op = false; | 3078 bool is_smi_two_args_op = false; |
3156 const StubEntry* stub_entry = TwoArgsSmiOpInlineCacheEntry(token_kind()); | 3079 const StubEntry* stub_entry = TwoArgsSmiOpInlineCacheEntry(token_kind()); |
3157 if (stub_entry != NULL) { | 3080 if (stub_entry != NULL) { |
3158 // We have a dedicated inline cache stub for this operation, add an | 3081 // We have a dedicated inline cache stub for this operation, add an |
3159 // an initial Smi/Smi check with count 0. | 3082 // an initial Smi/Smi check with count 0. |
3160 is_smi_two_args_op = call_ic_data->AddSmiSmiCheckForFastSmiStubs(); | 3083 is_smi_two_args_op = call_ic_data->AddSmiSmiCheckForFastSmiStubs(); |
3161 } | 3084 } |
3162 if (is_smi_two_args_op) { | 3085 if (is_smi_two_args_op) { |
3163 ASSERT(ArgumentCount() == 2); | 3086 ASSERT(ArgumentCount() == 2); |
3164 compiler->EmitInstanceCall(*stub_entry, *call_ic_data, ArgumentCount(), | 3087 compiler->EmitInstanceCall(*stub_entry, *call_ic_data, ArgumentCount(), |
3165 deopt_id(), token_pos(), locs()); | 3088 deopt_id(), token_pos(), locs()); |
3166 } else { | 3089 } else { |
3167 compiler->GenerateInstanceCall(deopt_id(), | 3090 compiler->GenerateInstanceCall(deopt_id(), token_pos(), ArgumentCount(), |
3168 token_pos(), | 3091 locs(), *call_ic_data); |
3169 ArgumentCount(), | |
3170 locs(), | |
3171 *call_ic_data); | |
3172 } | 3092 } |
3173 } | 3093 } |
3174 #else | 3094 #else |
3175 ICData* original_ic_data = &ICData::ZoneHandle(call_ic_data->Original()); | 3095 ICData* original_ic_data = &ICData::ZoneHandle(call_ic_data->Original()); |
3176 | 3096 |
3177 // Emit smi fast path instruction. If fast-path succeeds it skips the next | 3097 // Emit smi fast path instruction. If fast-path succeeds it skips the next |
3178 // instruction otherwise it falls through. Only attempt in unoptimized code | 3098 // instruction otherwise it falls through. Only attempt in unoptimized code |
3179 // because TryFastPathSmiOp will update original_ic_data. | 3099 // because TryFastPathSmiOp will update original_ic_data. |
3180 if (!compiler->is_optimizing()) { | 3100 if (!compiler->is_optimizing()) { |
3181 TryFastPathSmiOp(compiler, original_ic_data, function_name()); | 3101 TryFastPathSmiOp(compiler, original_ic_data, function_name()); |
(...skipping 12 matching lines...) Expand all Loading... |
3194 if (compiler->is_optimizing()) { | 3114 if (compiler->is_optimizing()) { |
3195 __ InstanceCall2Opt(ArgumentCount(), call_ic_data_kidx); | 3115 __ InstanceCall2Opt(ArgumentCount(), call_ic_data_kidx); |
3196 } else { | 3116 } else { |
3197 __ InstanceCall2(ArgumentCount(), call_ic_data_kidx); | 3117 __ InstanceCall2(ArgumentCount(), call_ic_data_kidx); |
3198 } | 3118 } |
3199 break; | 3119 break; |
3200 default: | 3120 default: |
3201 UNIMPLEMENTED(); | 3121 UNIMPLEMENTED(); |
3202 break; | 3122 break; |
3203 } | 3123 } |
3204 compiler->AddCurrentDescriptor(RawPcDescriptors::kIcCall, | 3124 compiler->AddCurrentDescriptor(RawPcDescriptors::kIcCall, deopt_id(), |
3205 deopt_id(), | |
3206 token_pos()); | 3125 token_pos()); |
3207 compiler->RecordAfterCall(this); | 3126 compiler->RecordAfterCall(this); |
3208 | 3127 |
3209 if (compiler->is_optimizing()) { | 3128 if (compiler->is_optimizing()) { |
3210 __ PopLocal(locs()->out(0).reg()); | 3129 __ PopLocal(locs()->out(0).reg()); |
3211 } | 3130 } |
3212 #endif // !defined(TARGET_ARCH_DBC) | 3131 #endif // !defined(TARGET_ARCH_DBC) |
3213 } | 3132 } |
3214 | 3133 |
3215 | 3134 |
3216 bool PolymorphicInstanceCallInstr::HasSingleRecognizedTarget() const { | 3135 bool PolymorphicInstanceCallInstr::HasSingleRecognizedTarget() const { |
3217 if (FLAG_precompiled_mode && with_checks()) return false; | 3136 if (FLAG_precompiled_mode && with_checks()) return false; |
3218 | 3137 |
3219 return ic_data().HasOneTarget() && | 3138 return ic_data().HasOneTarget() && |
3220 (MethodRecognizer::RecognizeKind( | 3139 (MethodRecognizer::RecognizeKind(Function::Handle( |
3221 Function::Handle(ic_data().GetTargetAt(0))) != | 3140 ic_data().GetTargetAt(0))) != MethodRecognizer::kUnknown); |
3222 MethodRecognizer::kUnknown); | |
3223 } | 3141 } |
3224 | 3142 |
3225 | 3143 |
3226 // DBC does not support optimizing compiler and thus doesn't emit | 3144 // DBC does not support optimizing compiler and thus doesn't emit |
3227 // PolymorphicInstanceCallInstr. | 3145 // PolymorphicInstanceCallInstr. |
3228 #if !defined(TARGET_ARCH_DBC) | 3146 #if !defined(TARGET_ARCH_DBC) |
3229 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3147 void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3230 ASSERT(ic_data().NumArgsTested() == 1); | 3148 ASSERT(ic_data().NumArgsTested() == 1); |
3231 if (!with_checks()) { | 3149 if (!with_checks()) { |
3232 ASSERT(ic_data().HasOneTarget()); | 3150 ASSERT(ic_data().HasOneTarget()); |
3233 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); | 3151 const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0)); |
3234 compiler->GenerateStaticCall(deopt_id(), | 3152 compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(), |
3235 instance_call()->token_pos(), | 3153 target, instance_call()->ArgumentCount(), |
3236 target, | 3154 instance_call()->argument_names(), locs(), |
3237 instance_call()->ArgumentCount(), | |
3238 instance_call()->argument_names(), | |
3239 locs(), | |
3240 ICData::Handle()); | 3155 ICData::Handle()); |
3241 return; | 3156 return; |
3242 } | 3157 } |
3243 | 3158 |
3244 compiler->EmitPolymorphicInstanceCall(ic_data(), | 3159 compiler->EmitPolymorphicInstanceCall( |
3245 instance_call()->ArgumentCount(), | 3160 ic_data(), instance_call()->ArgumentCount(), |
3246 instance_call()->argument_names(), | 3161 instance_call()->argument_names(), deopt_id(), |
3247 deopt_id(), | 3162 instance_call()->token_pos(), locs(), complete()); |
3248 instance_call()->token_pos(), | |
3249 locs(), | |
3250 complete()); | |
3251 } | 3163 } |
3252 #endif | 3164 #endif |
3253 | 3165 |
3254 | 3166 |
3255 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( | 3167 RawType* PolymorphicInstanceCallInstr::ComputeRuntimeType( |
3256 const ICData& ic_data) { | 3168 const ICData& ic_data) { |
3257 bool is_string = true; | 3169 bool is_string = true; |
3258 bool is_integer = true; | 3170 bool is_integer = true; |
3259 bool is_double = true; | 3171 bool is_double = true; |
3260 | 3172 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3316 LocationSummary* StaticCallInstr::MakeLocationSummary(Zone* zone, | 3228 LocationSummary* StaticCallInstr::MakeLocationSummary(Zone* zone, |
3317 bool optimizing) const { | 3229 bool optimizing) const { |
3318 return MakeCallSummary(zone); | 3230 return MakeCallSummary(zone); |
3319 } | 3231 } |
3320 | 3232 |
3321 | 3233 |
3322 void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3234 void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3323 const ICData* call_ic_data = NULL; | 3235 const ICData* call_ic_data = NULL; |
3324 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || | 3236 if (!FLAG_propagate_ic_data || !compiler->is_optimizing() || |
3325 (ic_data() == NULL)) { | 3237 (ic_data() == NULL)) { |
3326 const Array& arguments_descriptor = | 3238 const Array& arguments_descriptor = Array::Handle( |
3327 Array::Handle(ArgumentsDescriptor::New(ArgumentCount(), | 3239 ArgumentsDescriptor::New(ArgumentCount(), argument_names())); |
3328 argument_names())); | |
3329 MethodRecognizer::Kind recognized_kind = | 3240 MethodRecognizer::Kind recognized_kind = |
3330 MethodRecognizer::RecognizeKind(function()); | 3241 MethodRecognizer::RecognizeKind(function()); |
3331 int num_args_checked = 0; | 3242 int num_args_checked = 0; |
3332 switch (recognized_kind) { | 3243 switch (recognized_kind) { |
3333 case MethodRecognizer::kDoubleFromInteger: | 3244 case MethodRecognizer::kDoubleFromInteger: |
3334 case MethodRecognizer::kMathMin: | 3245 case MethodRecognizer::kMathMin: |
3335 case MethodRecognizer::kMathMax: | 3246 case MethodRecognizer::kMathMax: |
3336 num_args_checked = 2; | 3247 num_args_checked = 2; |
3337 break; | 3248 break; |
3338 default: | 3249 default: |
3339 break; | 3250 break; |
3340 } | 3251 } |
3341 call_ic_data = compiler->GetOrAddStaticCallICData(deopt_id(), | 3252 call_ic_data = compiler->GetOrAddStaticCallICData( |
3342 function(), | 3253 deopt_id(), function(), arguments_descriptor, num_args_checked); |
3343 arguments_descriptor, | |
3344 num_args_checked); | |
3345 } else { | 3254 } else { |
3346 call_ic_data = &ICData::ZoneHandle(ic_data()->raw()); | 3255 call_ic_data = &ICData::ZoneHandle(ic_data()->raw()); |
3347 } | 3256 } |
3348 | 3257 |
3349 #if !defined(TARGET_ARCH_DBC) | 3258 #if !defined(TARGET_ARCH_DBC) |
3350 compiler->GenerateStaticCall(deopt_id(), | 3259 compiler->GenerateStaticCall(deopt_id(), token_pos(), function(), |
3351 token_pos(), | 3260 ArgumentCount(), argument_names(), locs(), |
3352 function(), | |
3353 ArgumentCount(), | |
3354 argument_names(), | |
3355 locs(), | |
3356 *call_ic_data); | 3261 *call_ic_data); |
3357 #else | 3262 #else |
3358 const Array& arguments_descriptor = | 3263 const Array& arguments_descriptor = |
3359 (ic_data() == NULL) ? | 3264 (ic_data() == NULL) ? Array::Handle(ArgumentsDescriptor::New( |
3360 Array::Handle(ArgumentsDescriptor::New(ArgumentCount(), | 3265 ArgumentCount(), argument_names())) |
3361 argument_names())) : | 3266 : Array::Handle(ic_data()->arguments_descriptor()); |
3362 Array::Handle(ic_data()->arguments_descriptor()); | |
3363 const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor); | 3267 const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor); |
3364 | 3268 |
3365 if (compiler->is_optimizing()) { | 3269 if (compiler->is_optimizing()) { |
3366 __ PushConstant(function()); | 3270 __ PushConstant(function()); |
3367 __ StaticCall(ArgumentCount(), argdesc_kidx); | 3271 __ StaticCall(ArgumentCount(), argdesc_kidx); |
3368 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, | 3272 compiler->AddCurrentDescriptor(RawPcDescriptors::kOther, deopt_id(), |
3369 deopt_id(), token_pos()); | 3273 token_pos()); |
3370 compiler->RecordAfterCall(this); | 3274 compiler->RecordAfterCall(this); |
3371 __ PopLocal(locs()->out(0).reg()); | 3275 __ PopLocal(locs()->out(0).reg()); |
3372 } else { | 3276 } else { |
3373 const intptr_t ic_data_kidx = __ AddConstant(*call_ic_data); | 3277 const intptr_t ic_data_kidx = __ AddConstant(*call_ic_data); |
3374 __ PushConstant(ic_data_kidx); | 3278 __ PushConstant(ic_data_kidx); |
3375 __ IndirectStaticCall(ArgumentCount(), argdesc_kidx); | 3279 __ IndirectStaticCall(ArgumentCount(), argdesc_kidx); |
3376 compiler->AddCurrentDescriptor(RawPcDescriptors::kUnoptStaticCall, | 3280 compiler->AddCurrentDescriptor(RawPcDescriptors::kUnoptStaticCall, |
3377 deopt_id(), token_pos()); | 3281 deopt_id(), token_pos()); |
3378 compiler->RecordAfterCall(this); | 3282 compiler->RecordAfterCall(this); |
3379 } | 3283 } |
3380 #endif // !defined(TARGET_ARCH_DBC) | 3284 #endif // !defined(TARGET_ARCH_DBC) |
3381 } | 3285 } |
3382 | 3286 |
3383 | 3287 |
3384 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3288 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3385 compiler->GenerateAssertAssignable(token_pos(), | 3289 compiler->GenerateAssertAssignable(token_pos(), deopt_id(), dst_type(), |
3386 deopt_id(), | 3290 dst_name(), locs()); |
3387 dst_type(), | |
3388 dst_name(), | |
3389 locs()); | |
3390 | 3291 |
3391 // DBC does not use LocationSummaries in the same way as other architectures. | 3292 // DBC does not use LocationSummaries in the same way as other architectures. |
3392 #if !defined(TARGET_ARCH_DBC) | 3293 #if !defined(TARGET_ARCH_DBC) |
3393 ASSERT(locs()->in(0).reg() == locs()->out(0).reg()); | 3294 ASSERT(locs()->in(0).reg() == locs()->out(0).reg()); |
3394 #endif // !defined(TARGET_ARCH_DBC) | 3295 #endif // !defined(TARGET_ARCH_DBC) |
3395 } | 3296 } |
3396 | 3297 |
3397 | 3298 |
3398 LocationSummary* DeoptimizeInstr::MakeLocationSummary(Zone* zone, | 3299 LocationSummary* DeoptimizeInstr::MakeLocationSummary(Zone* zone, |
3399 bool opt) const { | 3300 bool opt) const { |
3400 return new(zone) LocationSummary(zone, 0, 0, LocationSummary::kNoCall); | 3301 return new (zone) LocationSummary(zone, 0, 0, LocationSummary::kNoCall); |
3401 } | 3302 } |
3402 | 3303 |
3403 | 3304 |
3404 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3305 void DeoptimizeInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
3405 #if !defined(TARGET_ARCH_DBC) | 3306 #if !defined(TARGET_ARCH_DBC) |
3406 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); | 3307 __ Jump(compiler->AddDeoptStub(deopt_id(), deopt_reason_)); |
3407 #else | 3308 #else |
3408 compiler->EmitDeopt(deopt_id(), deopt_reason_); | 3309 compiler->EmitDeopt(deopt_id(), deopt_reason_); |
3409 #endif | 3310 #endif |
3410 } | 3311 } |
3411 | 3312 |
3412 | 3313 |
3413 Environment* Environment::From(Zone* zone, | 3314 Environment* Environment::From(Zone* zone, |
3414 const GrowableArray<Definition*>& definitions, | 3315 const GrowableArray<Definition*>& definitions, |
3415 intptr_t fixed_parameter_count, | 3316 intptr_t fixed_parameter_count, |
3416 const ParsedFunction& parsed_function) { | 3317 const ParsedFunction& parsed_function) { |
3417 Environment* env = | 3318 Environment* env = |
3418 new(zone) Environment(definitions.length(), | 3319 new (zone) Environment(definitions.length(), fixed_parameter_count, |
3419 fixed_parameter_count, | 3320 Thread::kNoDeoptId, parsed_function, NULL); |
3420 Thread::kNoDeoptId, | |
3421 parsed_function, | |
3422 NULL); | |
3423 for (intptr_t i = 0; i < definitions.length(); ++i) { | 3321 for (intptr_t i = 0; i < definitions.length(); ++i) { |
3424 env->values_.Add(new(zone) Value(definitions[i])); | 3322 env->values_.Add(new (zone) Value(definitions[i])); |
3425 } | 3323 } |
3426 return env; | 3324 return env; |
3427 } | 3325 } |
3428 | 3326 |
3429 | 3327 |
3430 Environment* Environment::DeepCopy(Zone* zone, intptr_t length) const { | 3328 Environment* Environment::DeepCopy(Zone* zone, intptr_t length) const { |
3431 ASSERT(length <= values_.length()); | 3329 ASSERT(length <= values_.length()); |
3432 Environment* copy = new(zone) Environment( | 3330 Environment* copy = new (zone) |
3433 length, | 3331 Environment(length, fixed_parameter_count_, deopt_id_, parsed_function_, |
3434 fixed_parameter_count_, | 3332 (outer_ == NULL) ? NULL : outer_->DeepCopy(zone)); |
3435 deopt_id_, | |
3436 parsed_function_, | |
3437 (outer_ == NULL) ? NULL : outer_->DeepCopy(zone)); | |
3438 if (locations_ != NULL) { | 3333 if (locations_ != NULL) { |
3439 Location* new_locations = zone->Alloc<Location>(length); | 3334 Location* new_locations = zone->Alloc<Location>(length); |
3440 copy->set_locations(new_locations); | 3335 copy->set_locations(new_locations); |
3441 } | 3336 } |
3442 for (intptr_t i = 0; i < length; ++i) { | 3337 for (intptr_t i = 0; i < length; ++i) { |
3443 copy->values_.Add(values_[i]->Copy(zone)); | 3338 copy->values_.Add(values_[i]->Copy(zone)); |
3444 if (locations_ != NULL) { | 3339 if (locations_ != NULL) { |
3445 copy->locations_[i] = locations_[i].Copy(); | 3340 copy->locations_[i] = locations_[i].Copy(); |
3446 } | 3341 } |
3447 } | 3342 } |
(...skipping 20 matching lines...) Expand all Loading... |
3468 Instruction* instr, | 3363 Instruction* instr, |
3469 intptr_t argc, | 3364 intptr_t argc, |
3470 Definition* dead, | 3365 Definition* dead, |
3471 Definition* result) const { | 3366 Definition* result) const { |
3472 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { | 3367 for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) { |
3473 it.CurrentValue()->RemoveFromUseList(); | 3368 it.CurrentValue()->RemoveFromUseList(); |
3474 } | 3369 } |
3475 | 3370 |
3476 Environment* copy = DeepCopy(zone, values_.length() - argc); | 3371 Environment* copy = DeepCopy(zone, values_.length() - argc); |
3477 for (intptr_t i = 0; i < argc; i++) { | 3372 for (intptr_t i = 0; i < argc; i++) { |
3478 copy->values_.Add(new(zone) Value(dead)); | 3373 copy->values_.Add(new (zone) Value(dead)); |
3479 } | 3374 } |
3480 copy->values_.Add(new(zone) Value(result)); | 3375 copy->values_.Add(new (zone) Value(result)); |
3481 | 3376 |
3482 instr->SetEnvironment(copy); | 3377 instr->SetEnvironment(copy); |
3483 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { | 3378 for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) { |
3484 Value* value = it.CurrentValue(); | 3379 Value* value = it.CurrentValue(); |
3485 value->definition()->AddEnvUse(value); | 3380 value->definition()->AddEnvUse(value); |
3486 } | 3381 } |
3487 } | 3382 } |
3488 | 3383 |
3489 | 3384 |
3490 // Copies the environment as outer on an inlined instruction and updates the | 3385 // Copies the environment as outer on an inlined instruction and updates the |
(...skipping 17 matching lines...) Expand all Loading... |
3508 | 3403 |
3509 ComparisonInstr* DoubleTestOpInstr::CopyWithNewOperands(Value* new_left, | 3404 ComparisonInstr* DoubleTestOpInstr::CopyWithNewOperands(Value* new_left, |
3510 Value* new_right) { | 3405 Value* new_right) { |
3511 UNREACHABLE(); | 3406 UNREACHABLE(); |
3512 return NULL; | 3407 return NULL; |
3513 } | 3408 } |
3514 | 3409 |
3515 | 3410 |
3516 ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left, | 3411 ComparisonInstr* EqualityCompareInstr::CopyWithNewOperands(Value* new_left, |
3517 Value* new_right) { | 3412 Value* new_right) { |
3518 return new EqualityCompareInstr(token_pos(), | 3413 return new EqualityCompareInstr(token_pos(), kind(), new_left, new_right, |
3519 kind(), | 3414 operation_cid(), deopt_id()); |
3520 new_left, | |
3521 new_right, | |
3522 operation_cid(), | |
3523 deopt_id()); | |
3524 } | 3415 } |
3525 | 3416 |
3526 | 3417 |
3527 ComparisonInstr* RelationalOpInstr::CopyWithNewOperands(Value* new_left, | 3418 ComparisonInstr* RelationalOpInstr::CopyWithNewOperands(Value* new_left, |
3528 Value* new_right) { | 3419 Value* new_right) { |
3529 return new RelationalOpInstr(token_pos(), | 3420 return new RelationalOpInstr(token_pos(), kind(), new_left, new_right, |
3530 kind(), | 3421 operation_cid(), deopt_id()); |
3531 new_left, | |
3532 new_right, | |
3533 operation_cid(), | |
3534 deopt_id()); | |
3535 } | 3422 } |
3536 | 3423 |
3537 | 3424 |
3538 ComparisonInstr* StrictCompareInstr::CopyWithNewOperands(Value* new_left, | 3425 ComparisonInstr* StrictCompareInstr::CopyWithNewOperands(Value* new_left, |
3539 Value* new_right) { | 3426 Value* new_right) { |
3540 return new StrictCompareInstr(token_pos(), | 3427 return new StrictCompareInstr(token_pos(), kind(), new_left, new_right, |
3541 kind(), | |
3542 new_left, | |
3543 new_right, | |
3544 needs_number_check()); | 3428 needs_number_check()); |
3545 } | 3429 } |
3546 | 3430 |
3547 | 3431 |
3548 | |
3549 ComparisonInstr* TestSmiInstr::CopyWithNewOperands(Value* new_left, | 3432 ComparisonInstr* TestSmiInstr::CopyWithNewOperands(Value* new_left, |
3550 Value* new_right) { | 3433 Value* new_right) { |
3551 return new TestSmiInstr(token_pos(), kind(), new_left, new_right); | 3434 return new TestSmiInstr(token_pos(), kind(), new_left, new_right); |
3552 } | 3435 } |
3553 | 3436 |
3554 | 3437 |
3555 | |
3556 ComparisonInstr* TestCidsInstr::CopyWithNewOperands(Value* new_left, | 3438 ComparisonInstr* TestCidsInstr::CopyWithNewOperands(Value* new_left, |
3557 Value* new_right) { | 3439 Value* new_right) { |
3558 return new TestCidsInstr(token_pos(), | 3440 return new TestCidsInstr(token_pos(), kind(), new_left, cid_results(), |
3559 kind(), | |
3560 new_left, | |
3561 cid_results(), | |
3562 deopt_id()); | 3441 deopt_id()); |
3563 } | 3442 } |
3564 | 3443 |
3565 | 3444 |
3566 bool TestCidsInstr::AttributesEqual(Instruction* other) const { | 3445 bool TestCidsInstr::AttributesEqual(Instruction* other) const { |
3567 TestCidsInstr* other_instr = other->AsTestCids(); | 3446 TestCidsInstr* other_instr = other->AsTestCids(); |
3568 if (!ComparisonInstr::AttributesEqual(other)) { | 3447 if (!ComparisonInstr::AttributesEqual(other)) { |
3569 return false; | 3448 return false; |
3570 } | 3449 } |
3571 if (cid_results().length() != other_instr->cid_results().length()) { | 3450 if (cid_results().length() != other_instr->cid_results().length()) { |
(...skipping 16 matching lines...) Expand all Loading... |
3588 | 3467 |
3589 | 3468 |
3590 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, | 3469 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, |
3591 Value* v1, | 3470 Value* v1, |
3592 Value* v2) { | 3471 Value* v2) { |
3593 #if !defined(TARGET_ARCH_DBC) | 3472 #if !defined(TARGET_ARCH_DBC) |
3594 bool is_smi_result = BindsToSmiConstant(v1) && BindsToSmiConstant(v2); | 3473 bool is_smi_result = BindsToSmiConstant(v1) && BindsToSmiConstant(v2); |
3595 if (comparison->IsStrictCompare()) { | 3474 if (comparison->IsStrictCompare()) { |
3596 // Strict comparison with number checks calls a stub and is not supported | 3475 // Strict comparison with number checks calls a stub and is not supported |
3597 // by if-conversion. | 3476 // by if-conversion. |
3598 return is_smi_result | 3477 return is_smi_result && |
3599 && !comparison->AsStrictCompare()->needs_number_check(); | 3478 !comparison->AsStrictCompare()->needs_number_check(); |
3600 } | 3479 } |
3601 if (comparison->operation_cid() != kSmiCid) { | 3480 if (comparison->operation_cid() != kSmiCid) { |
3602 // Non-smi comparisons are not supported by if-conversion. | 3481 // Non-smi comparisons are not supported by if-conversion. |
3603 return false; | 3482 return false; |
3604 } | 3483 } |
3605 return is_smi_result; | 3484 return is_smi_result; |
3606 #else | 3485 #else |
3607 return false; | 3486 return false; |
3608 #endif // !defined(TARGET_ARCH_DBC) | 3487 #endif // !defined(TARGET_ARCH_DBC) |
3609 } | 3488 } |
3610 | 3489 |
3611 | 3490 |
3612 bool PhiInstr::IsRedundant() const { | 3491 bool PhiInstr::IsRedundant() const { |
3613 ASSERT(InputCount() > 1); | 3492 ASSERT(InputCount() > 1); |
3614 Definition* first = InputAt(0)->definition(); | 3493 Definition* first = InputAt(0)->definition(); |
3615 for (intptr_t i = 1; i < InputCount(); ++i) { | 3494 for (intptr_t i = 1; i < InputCount(); ++i) { |
3616 Definition* def = InputAt(i)->definition(); | 3495 Definition* def = InputAt(i)->definition(); |
3617 if (def != first) return false; | 3496 if (def != first) return false; |
3618 } | 3497 } |
3619 return true; | 3498 return true; |
3620 } | 3499 } |
3621 | 3500 |
3622 | 3501 |
3623 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { | 3502 bool CheckArrayBoundInstr::IsFixedLengthArrayType(intptr_t cid) { |
3624 return LoadFieldInstr::IsFixedLengthArrayCid(cid); | 3503 return LoadFieldInstr::IsFixedLengthArrayCid(cid); |
3625 } | 3504 } |
3626 | 3505 |
3627 | 3506 |
3628 Instruction* CheckArrayBoundInstr::Canonicalize(FlowGraph* flow_graph) { | 3507 Instruction* CheckArrayBoundInstr::Canonicalize(FlowGraph* flow_graph) { |
3629 return IsRedundant(RangeBoundary::FromDefinition(length()->definition())) ? | 3508 return IsRedundant(RangeBoundary::FromDefinition(length()->definition())) |
3630 NULL : this; | 3509 ? NULL |
| 3510 : this; |
3631 } | 3511 } |
3632 | 3512 |
3633 | 3513 |
3634 intptr_t CheckArrayBoundInstr::LengthOffsetFor(intptr_t class_id) { | 3514 intptr_t CheckArrayBoundInstr::LengthOffsetFor(intptr_t class_id) { |
3635 if (RawObject::IsExternalTypedDataClassId(class_id)) { | 3515 if (RawObject::IsExternalTypedDataClassId(class_id)) { |
3636 return ExternalTypedData::length_offset(); | 3516 return ExternalTypedData::length_offset(); |
3637 } | 3517 } |
3638 if (RawObject::IsTypedDataClassId(class_id)) { | 3518 if (RawObject::IsTypedDataClassId(class_id)) { |
3639 return TypedData::length_offset(); | 3519 return TypedData::length_offset(); |
3640 } | 3520 } |
(...skipping 13 matching lines...) Expand all Loading... |
3654 } | 3534 } |
3655 | 3535 |
3656 | 3536 |
3657 const Function& StringInterpolateInstr::CallFunction() const { | 3537 const Function& StringInterpolateInstr::CallFunction() const { |
3658 if (function_.IsNull()) { | 3538 if (function_.IsNull()) { |
3659 const int kNumberOfArguments = 1; | 3539 const int kNumberOfArguments = 1; |
3660 const Array& kNoArgumentNames = Object::null_array(); | 3540 const Array& kNoArgumentNames = Object::null_array(); |
3661 const Class& cls = | 3541 const Class& cls = |
3662 Class::Handle(Library::LookupCoreClass(Symbols::StringBase())); | 3542 Class::Handle(Library::LookupCoreClass(Symbols::StringBase())); |
3663 ASSERT(!cls.IsNull()); | 3543 ASSERT(!cls.IsNull()); |
3664 function_ = | 3544 function_ = Resolver::ResolveStatic( |
3665 Resolver::ResolveStatic( | 3545 cls, Library::PrivateCoreLibName(Symbols::Interpolate()), |
3666 cls, | 3546 kNumberOfArguments, kNoArgumentNames); |
3667 Library::PrivateCoreLibName(Symbols::Interpolate()), | |
3668 kNumberOfArguments, | |
3669 kNoArgumentNames); | |
3670 } | 3547 } |
3671 ASSERT(!function_.IsNull()); | 3548 ASSERT(!function_.IsNull()); |
3672 return function_; | 3549 return function_; |
3673 } | 3550 } |
3674 | 3551 |
3675 | 3552 |
3676 // Replace StringInterpolateInstr with a constant string if all inputs are | 3553 // Replace StringInterpolateInstr with a constant string if all inputs are |
3677 // constant of [string, number, boolean, null]. | 3554 // constant of [string, number, boolean, null]. |
3678 // Leave the CreateArrayInstr and StoreIndexedInstr in the stream in case | 3555 // Leave the CreateArrayInstr and StoreIndexedInstr in the stream in case |
3679 // deoptimization occurs. | 3556 // deoptimization occurs. |
(...skipping 18 matching lines...) Expand all Loading... |
3698 return this; | 3575 return this; |
3699 } | 3576 } |
3700 const intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value(); | 3577 const intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value(); |
3701 Thread* thread = Thread::Current(); | 3578 Thread* thread = Thread::Current(); |
3702 Zone* zone = thread->zone(); | 3579 Zone* zone = thread->zone(); |
3703 GrowableHandlePtrArray<const String> pieces(zone, length); | 3580 GrowableHandlePtrArray<const String> pieces(zone, length); |
3704 for (intptr_t i = 0; i < length; i++) { | 3581 for (intptr_t i = 0; i < length; i++) { |
3705 pieces.Add(Object::null_string()); | 3582 pieces.Add(Object::null_string()); |
3706 } | 3583 } |
3707 | 3584 |
3708 for (Value::Iterator it(create_array->input_use_list()); | 3585 for (Value::Iterator it(create_array->input_use_list()); !it.Done(); |
3709 !it.Done(); | |
3710 it.Advance()) { | 3586 it.Advance()) { |
3711 Instruction* curr = it.Current()->instruction(); | 3587 Instruction* curr = it.Current()->instruction(); |
3712 if (curr == this) continue; | 3588 if (curr == this) continue; |
3713 | 3589 |
3714 StoreIndexedInstr* store = curr->AsStoreIndexed(); | 3590 StoreIndexedInstr* store = curr->AsStoreIndexed(); |
3715 if (!store->index()->BindsToConstant() || | 3591 if (!store->index()->BindsToConstant() || |
3716 !store->index()->BoundConstant().IsSmi()) { | 3592 !store->index()->BoundConstant().IsSmi()) { |
3717 return this; | 3593 return this; |
3718 } | 3594 } |
3719 intptr_t store_index = Smi::Cast(store->index()->BoundConstant()).Value(); | 3595 intptr_t store_index = Smi::Cast(store->index()->BoundConstant()).Value(); |
3720 ASSERT(store_index < length); | 3596 ASSERT(store_index < length); |
3721 ASSERT(store != NULL); | 3597 ASSERT(store != NULL); |
3722 if (store->value()->definition()->IsConstant()) { | 3598 if (store->value()->definition()->IsConstant()) { |
3723 ASSERT(store->index()->BindsToConstant()); | 3599 ASSERT(store->index()->BindsToConstant()); |
3724 const Object& obj = store->value()->definition()->AsConstant()->value(); | 3600 const Object& obj = store->value()->definition()->AsConstant()->value(); |
3725 // TODO(srdjan): Verify if any other types should be converted as well. | 3601 // TODO(srdjan): Verify if any other types should be converted as well. |
3726 if (obj.IsString()) { | 3602 if (obj.IsString()) { |
3727 pieces.SetAt(store_index, String::Cast(obj)); | 3603 pieces.SetAt(store_index, String::Cast(obj)); |
3728 } else if (obj.IsSmi()) { | 3604 } else if (obj.IsSmi()) { |
3729 const char* cstr = obj.ToCString(); | 3605 const char* cstr = obj.ToCString(); |
3730 pieces.SetAt(store_index, | 3606 pieces.SetAt(store_index, |
3731 String::Handle(zone, String::New(cstr, Heap::kOld))); | 3607 String::Handle(zone, String::New(cstr, Heap::kOld))); |
3732 } else if (obj.IsBool()) { | 3608 } else if (obj.IsBool()) { |
3733 pieces.SetAt(store_index, | 3609 pieces.SetAt(store_index, Bool::Cast(obj).value() ? Symbols::True() |
3734 Bool::Cast(obj).value() ? Symbols::True() : Symbols::False()); | 3610 : Symbols::False()); |
3735 } else if (obj.IsNull()) { | 3611 } else if (obj.IsNull()) { |
3736 pieces.SetAt(store_index, Symbols::Null()); | 3612 pieces.SetAt(store_index, Symbols::Null()); |
3737 } else { | 3613 } else { |
3738 return this; | 3614 return this; |
3739 } | 3615 } |
3740 } else { | 3616 } else { |
3741 return this; | 3617 return this; |
3742 } | 3618 } |
3743 } | 3619 } |
3744 | 3620 |
3745 const String& concatenated = String::ZoneHandle(zone, | 3621 const String& concatenated = |
3746 Symbols::FromConcatAll(thread, pieces)); | 3622 String::ZoneHandle(zone, Symbols::FromConcatAll(thread, pieces)); |
3747 return flow_graph->GetConstant(concatenated); | 3623 return flow_graph->GetConstant(concatenated); |
3748 } | 3624 } |
3749 | 3625 |
3750 | 3626 |
3751 static AlignmentType StrengthenAlignment(intptr_t cid, | 3627 static AlignmentType StrengthenAlignment(intptr_t cid, |
3752 AlignmentType alignment) { | 3628 AlignmentType alignment) { |
3753 switch (cid) { | 3629 switch (cid) { |
3754 case kTypedDataInt8ArrayCid: | 3630 case kTypedDataInt8ArrayCid: |
3755 case kTypedDataUint8ArrayCid: | 3631 case kTypedDataUint8ArrayCid: |
3756 case kTypedDataUint8ClampedArrayCid: | 3632 case kTypedDataUint8ClampedArrayCid: |
(...skipping 27 matching lines...) Expand all Loading... |
3784 : TemplateDefinition(deopt_id), | 3660 : TemplateDefinition(deopt_id), |
3785 index_scale_(index_scale), | 3661 index_scale_(index_scale), |
3786 class_id_(class_id), | 3662 class_id_(class_id), |
3787 alignment_(StrengthenAlignment(class_id, alignment)), | 3663 alignment_(StrengthenAlignment(class_id, alignment)), |
3788 token_pos_(token_pos) { | 3664 token_pos_(token_pos) { |
3789 SetInputAt(0, array); | 3665 SetInputAt(0, array); |
3790 SetInputAt(1, index); | 3666 SetInputAt(1, index); |
3791 } | 3667 } |
3792 | 3668 |
3793 | 3669 |
3794 | |
3795 StoreIndexedInstr::StoreIndexedInstr(Value* array, | 3670 StoreIndexedInstr::StoreIndexedInstr(Value* array, |
3796 Value* index, | 3671 Value* index, |
3797 Value* value, | 3672 Value* value, |
3798 StoreBarrierType emit_store_barrier, | 3673 StoreBarrierType emit_store_barrier, |
3799 intptr_t index_scale, | 3674 intptr_t index_scale, |
3800 intptr_t class_id, | 3675 intptr_t class_id, |
3801 AlignmentType alignment, | 3676 AlignmentType alignment, |
3802 intptr_t deopt_id, | 3677 intptr_t deopt_id, |
3803 TokenPosition token_pos) | 3678 TokenPosition token_pos) |
3804 : TemplateDefinition(deopt_id), | 3679 : TemplateDefinition(deopt_id), |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3852 case MethodRecognizer::kMathDoublePow: | 3727 case MethodRecognizer::kMathDoublePow: |
3853 case MethodRecognizer::kMathAtan2: | 3728 case MethodRecognizer::kMathAtan2: |
3854 return 2; | 3729 return 2; |
3855 default: | 3730 default: |
3856 UNREACHABLE(); | 3731 UNREACHABLE(); |
3857 } | 3732 } |
3858 return 0; | 3733 return 0; |
3859 } | 3734 } |
3860 | 3735 |
3861 // Use expected function signatures to help MSVC compiler resolve overloading. | 3736 // Use expected function signatures to help MSVC compiler resolve overloading. |
3862 typedef double (*UnaryMathCFunction) (double x); | 3737 typedef double (*UnaryMathCFunction)(double x); |
3863 typedef double (*BinaryMathCFunction) (double x, double y); | 3738 typedef double (*BinaryMathCFunction)(double x, double y); |
3864 | 3739 |
3865 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcPow, 2, true /* is_float */, | 3740 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3866 reinterpret_cast<RuntimeFunction>( | 3741 LibcPow, |
3867 static_cast<BinaryMathCFunction>(&pow))); | 3742 2, |
| 3743 true /* is_float */, |
| 3744 reinterpret_cast<RuntimeFunction>(static_cast<BinaryMathCFunction>(&pow))); |
3868 | 3745 |
3869 DEFINE_RAW_LEAF_RUNTIME_ENTRY(DartModulo, 2, true /* is_float */, | 3746 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3747 DartModulo, |
| 3748 2, |
| 3749 true /* is_float */, |
3870 reinterpret_cast<RuntimeFunction>( | 3750 reinterpret_cast<RuntimeFunction>( |
3871 static_cast<BinaryMathCFunction>(&DartModulo))); | 3751 static_cast<BinaryMathCFunction>(&DartModulo))); |
3872 | 3752 |
3873 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAtan2, 2, true /* is_float */, | 3753 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
| 3754 LibcAtan2, |
| 3755 2, |
| 3756 true /* is_float */, |
3874 reinterpret_cast<RuntimeFunction>( | 3757 reinterpret_cast<RuntimeFunction>( |
3875 static_cast<BinaryMathCFunction>(&atan2_ieee))); | 3758 static_cast<BinaryMathCFunction>(&atan2_ieee))); |
3876 | 3759 |
3877 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcFloor, 1, true /* is_float */, | 3760 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3878 reinterpret_cast<RuntimeFunction>( | 3761 LibcFloor, |
3879 static_cast<UnaryMathCFunction>(&floor))); | 3762 1, |
| 3763 true /* is_float */, |
| 3764 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&floor))); |
3880 | 3765 |
3881 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcCeil, 1, true /* is_float */, | 3766 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3882 reinterpret_cast<RuntimeFunction>( | 3767 LibcCeil, |
3883 static_cast<UnaryMathCFunction>(&ceil))); | 3768 1, |
| 3769 true /* is_float */, |
| 3770 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&ceil))); |
3884 | 3771 |
3885 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcTrunc, 1, true /* is_float */, | 3772 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3886 reinterpret_cast<RuntimeFunction>( | 3773 LibcTrunc, |
3887 static_cast<UnaryMathCFunction>(&trunc))); | 3774 1, |
| 3775 true /* is_float */, |
| 3776 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&trunc))); |
3888 | 3777 |
3889 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcRound, 1, true /* is_float */, | 3778 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3890 reinterpret_cast<RuntimeFunction>( | 3779 LibcRound, |
3891 static_cast<UnaryMathCFunction>(&round))); | 3780 1, |
| 3781 true /* is_float */, |
| 3782 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&round))); |
3892 | 3783 |
3893 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcCos, 1, true /* is_float */, | 3784 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3894 reinterpret_cast<RuntimeFunction>( | 3785 LibcCos, |
3895 static_cast<UnaryMathCFunction>(&cos))); | 3786 1, |
| 3787 true /* is_float */, |
| 3788 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&cos))); |
3896 | 3789 |
3897 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcSin, 1, true /* is_float */, | 3790 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3898 reinterpret_cast<RuntimeFunction>( | 3791 LibcSin, |
3899 static_cast<UnaryMathCFunction>(&sin))); | 3792 1, |
| 3793 true /* is_float */, |
| 3794 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&sin))); |
3900 | 3795 |
3901 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAsin, 1, true /* is_float */, | 3796 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3902 reinterpret_cast<RuntimeFunction>( | 3797 LibcAsin, |
3903 static_cast<UnaryMathCFunction>(&asin))); | 3798 1, |
| 3799 true /* is_float */, |
| 3800 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&asin))); |
3904 | 3801 |
3905 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAcos, 1, true /* is_float */, | 3802 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3906 reinterpret_cast<RuntimeFunction>( | 3803 LibcAcos, |
3907 static_cast<UnaryMathCFunction>(&acos))); | 3804 1, |
| 3805 true /* is_float */, |
| 3806 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&acos))); |
3908 | 3807 |
3909 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcTan, 1, true /* is_float */, | 3808 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3910 reinterpret_cast<RuntimeFunction>( | 3809 LibcTan, |
3911 static_cast<UnaryMathCFunction>(&tan))); | 3810 1, |
| 3811 true /* is_float */, |
| 3812 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&tan))); |
3912 | 3813 |
3913 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAtan, 1, true /* is_float */, | 3814 DEFINE_RAW_LEAF_RUNTIME_ENTRY( |
3914 reinterpret_cast<RuntimeFunction>( | 3815 LibcAtan, |
3915 static_cast<UnaryMathCFunction>(&atan))); | 3816 1, |
| 3817 true /* is_float */, |
| 3818 reinterpret_cast<RuntimeFunction>(static_cast<UnaryMathCFunction>(&atan))); |
3916 | 3819 |
3917 | 3820 |
3918 const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const { | 3821 const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const { |
3919 switch (recognized_kind_) { | 3822 switch (recognized_kind_) { |
3920 case MethodRecognizer::kDoubleTruncate: | 3823 case MethodRecognizer::kDoubleTruncate: |
3921 return kLibcTruncRuntimeEntry; | 3824 return kLibcTruncRuntimeEntry; |
3922 case MethodRecognizer::kDoubleRound: | 3825 case MethodRecognizer::kDoubleRound: |
3923 return kLibcRoundRuntimeEntry; | 3826 return kLibcRoundRuntimeEntry; |
3924 case MethodRecognizer::kDoubleFloor: | 3827 case MethodRecognizer::kDoubleFloor: |
3925 return kLibcFloorRuntimeEntry; | 3828 return kLibcFloorRuntimeEntry; |
(...skipping 19 matching lines...) Expand all Loading... |
3945 return kLibcAtan2RuntimeEntry; | 3848 return kLibcAtan2RuntimeEntry; |
3946 default: | 3849 default: |
3947 UNREACHABLE(); | 3850 UNREACHABLE(); |
3948 } | 3851 } |
3949 return kLibcPowRuntimeEntry; | 3852 return kLibcPowRuntimeEntry; |
3950 } | 3853 } |
3951 | 3854 |
3952 | 3855 |
3953 const char* MathUnaryInstr::KindToCString(MathUnaryKind kind) { | 3856 const char* MathUnaryInstr::KindToCString(MathUnaryKind kind) { |
3954 switch (kind) { | 3857 switch (kind) { |
3955 case kIllegal: return "illegal"; | 3858 case kIllegal: |
3956 case kSqrt: return "sqrt"; | 3859 return "illegal"; |
3957 case kDoubleSquare: return "double-square"; | 3860 case kSqrt: |
| 3861 return "sqrt"; |
| 3862 case kDoubleSquare: |
| 3863 return "double-square"; |
3958 } | 3864 } |
3959 UNREACHABLE(); | 3865 UNREACHABLE(); |
3960 return ""; | 3866 return ""; |
3961 } | 3867 } |
3962 | 3868 |
3963 | 3869 |
3964 const RuntimeEntry& CaseInsensitiveCompareUC16Instr::TargetFunction() const { | 3870 const RuntimeEntry& CaseInsensitiveCompareUC16Instr::TargetFunction() const { |
3965 return kCaseInsensitiveCompareUC16RuntimeEntry; | 3871 return kCaseInsensitiveCompareUC16RuntimeEntry; |
3966 } | 3872 } |
3967 | 3873 |
3968 | 3874 |
3969 MergedMathInstr::MergedMathInstr(ZoneGrowableArray<Value*>* inputs, | 3875 MergedMathInstr::MergedMathInstr(ZoneGrowableArray<Value*>* inputs, |
3970 intptr_t deopt_id, | 3876 intptr_t deopt_id, |
3971 MergedMathInstr::Kind kind) | 3877 MergedMathInstr::Kind kind) |
3972 : PureDefinition(deopt_id), | 3878 : PureDefinition(deopt_id), inputs_(inputs), kind_(kind) { |
3973 inputs_(inputs), | |
3974 kind_(kind) { | |
3975 ASSERT(inputs_->length() == InputCountFor(kind_)); | 3879 ASSERT(inputs_->length() == InputCountFor(kind_)); |
3976 for (intptr_t i = 0; i < inputs_->length(); ++i) { | 3880 for (intptr_t i = 0; i < inputs_->length(); ++i) { |
3977 ASSERT((*inputs)[i] != NULL); | 3881 ASSERT((*inputs)[i] != NULL); |
3978 (*inputs)[i]->set_instruction(this); | 3882 (*inputs)[i]->set_instruction(this); |
3979 (*inputs)[i]->set_use_index(i); | 3883 (*inputs)[i]->set_use_index(i); |
3980 } | 3884 } |
3981 } | 3885 } |
3982 | 3886 |
3983 | 3887 |
3984 intptr_t MergedMathInstr::OutputIndexOf(MethodRecognizer::Kind kind) { | 3888 intptr_t MergedMathInstr::OutputIndexOf(MethodRecognizer::Kind kind) { |
3985 switch (kind) { | 3889 switch (kind) { |
3986 case MethodRecognizer::kMathSin: return 1; | 3890 case MethodRecognizer::kMathSin: |
3987 case MethodRecognizer::kMathCos: return 0; | 3891 return 1; |
3988 default: UNIMPLEMENTED(); return -1; | 3892 case MethodRecognizer::kMathCos: |
| 3893 return 0; |
| 3894 default: |
| 3895 UNIMPLEMENTED(); |
| 3896 return -1; |
3989 } | 3897 } |
3990 } | 3898 } |
3991 | 3899 |
3992 | 3900 |
3993 intptr_t MergedMathInstr::OutputIndexOf(Token::Kind token) { | 3901 intptr_t MergedMathInstr::OutputIndexOf(Token::Kind token) { |
3994 switch (token) { | 3902 switch (token) { |
3995 case Token::kTRUNCDIV: return 0; | 3903 case Token::kTRUNCDIV: |
3996 case Token::kMOD: return 1; | 3904 return 0; |
3997 default: UNIMPLEMENTED(); return -1; | 3905 case Token::kMOD: |
| 3906 return 1; |
| 3907 default: |
| 3908 UNIMPLEMENTED(); |
| 3909 return -1; |
3998 } | 3910 } |
3999 } | 3911 } |
4000 | 3912 |
4001 | 3913 |
4002 void NativeCallInstr::SetupNative() { | 3914 void NativeCallInstr::SetupNative() { |
4003 Zone* zone = Thread::Current()->zone(); | 3915 Zone* zone = Thread::Current()->zone(); |
4004 const Class& cls = Class::Handle(zone, function().Owner()); | 3916 const Class& cls = Class::Handle(zone, function().Owner()); |
4005 const Library& library = Library::Handle(zone, cls.library()); | 3917 const Library& library = Library::Handle(zone, cls.library()); |
4006 const int num_params = | 3918 const int num_params = |
4007 NativeArguments::ParameterCountForResolution(function()); | 3919 NativeArguments::ParameterCountForResolution(function()); |
4008 bool auto_setup_scope = true; | 3920 bool auto_setup_scope = true; |
4009 NativeFunction native_function = NativeEntry::ResolveNative( | 3921 NativeFunction native_function = NativeEntry::ResolveNative( |
4010 library, native_name(), num_params, &auto_setup_scope); | 3922 library, native_name(), num_params, &auto_setup_scope); |
4011 if (native_function == NULL) { | 3923 if (native_function == NULL) { |
4012 Report::MessageF(Report::kError, | 3924 Report::MessageF(Report::kError, Script::Handle(function().script()), |
4013 Script::Handle(function().script()), | 3925 function().token_pos(), Report::AtLocation, |
4014 function().token_pos(), | |
4015 Report::AtLocation, | |
4016 "native function '%s' (%" Pd " arguments) cannot be found", | 3926 "native function '%s' (%" Pd " arguments) cannot be found", |
4017 native_name().ToCString(), | 3927 native_name().ToCString(), function().NumParameters()); |
4018 function().NumParameters()); | |
4019 } | 3928 } |
4020 set_native_c_function(native_function); | 3929 set_native_c_function(native_function); |
4021 function().SetIsNativeAutoSetupScope(auto_setup_scope); | 3930 function().SetIsNativeAutoSetupScope(auto_setup_scope); |
4022 Dart_NativeEntryResolver resolver = library.native_entry_resolver(); | 3931 Dart_NativeEntryResolver resolver = library.native_entry_resolver(); |
4023 bool is_bootstrap_native = Bootstrap::IsBootstapResolver(resolver); | 3932 bool is_bootstrap_native = Bootstrap::IsBootstapResolver(resolver); |
4024 set_is_bootstrap_native(is_bootstrap_native); | 3933 set_is_bootstrap_native(is_bootstrap_native); |
4025 } | 3934 } |
4026 | 3935 |
4027 #undef __ | 3936 #undef __ |
4028 | 3937 |
4029 } // namespace dart | 3938 } // namespace dart |
OLD | NEW |