| 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/dart_entry.h" | 8 #include "vm/dart_entry.h" |
| 9 #include "vm/flow_graph_allocator.h" | 9 #include "vm/flow_graph_allocator.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| 11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/flow_graph_optimizer.h" | 12 #include "vm/flow_graph_optimizer.h" |
| 13 #include "vm/locations.h" | 13 #include "vm/locations.h" |
| 14 #include "vm/object.h" | 14 #include "vm/object.h" |
| 15 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
| 16 #include "vm/os.h" | 16 #include "vm/os.h" |
| 17 #include "vm/scopes.h" | 17 #include "vm/scopes.h" |
| 18 #include "vm/stub_code.h" | 18 #include "vm/stub_code.h" |
| 19 #include "vm/symbols.h" | 19 #include "vm/symbols.h" |
| 20 | 20 |
| 21 namespace dart { | 21 namespace dart { |
| 22 | 22 |
| 23 DEFINE_FLAG(bool, new_identity_spec, true, | 23 DEFINE_FLAG(bool, new_identity_spec, true, |
| 24 "Use new identity check rules for numbers."); | 24 "Use new identity check rules for numbers."); |
| 25 DEFINE_FLAG(bool, propagate_ic_data, true, | 25 DEFINE_FLAG(bool, propagate_ic_data, true, |
| 26 "Propagate IC data from unoptimized to optimized IC calls."); | 26 "Propagate IC data from unoptimized to optimized IC calls."); |
| 27 DECLARE_FLAG(bool, enable_type_checks); | 27 DECLARE_FLAG(bool, enable_type_checks); |
| 28 DECLARE_FLAG(bool, eliminate_type_checks); | |
| 29 DECLARE_FLAG(int, max_polymorphic_checks); | 28 DECLARE_FLAG(int, max_polymorphic_checks); |
| 30 DECLARE_FLAG(bool, trace_optimization); | 29 DECLARE_FLAG(bool, trace_optimization); |
| 31 | 30 |
| 32 Definition::Definition() | 31 Definition::Definition() |
| 33 : range_(NULL), | 32 : range_(NULL), |
| 34 type_(NULL), | |
| 35 temp_index_(-1), | 33 temp_index_(-1), |
| 36 ssa_temp_index_(-1), | 34 ssa_temp_index_(-1), |
| 35 propagated_type_(AbstractType::Handle()), |
| 36 propagated_cid_(kIllegalCid), |
| 37 input_use_list_(NULL), | 37 input_use_list_(NULL), |
| 38 env_use_list_(NULL), | 38 env_use_list_(NULL), |
| 39 use_kind_(kValue), // Phis and parameters rely on this default. | 39 use_kind_(kValue), // Phis and parameters rely on this default. |
| 40 constant_value_(Object::ZoneHandle(ConstantPropagator::Unknown())) { | 40 constant_value_(Object::ZoneHandle(ConstantPropagator::Unknown())) { |
| 41 } | 41 } |
| 42 | 42 |
| 43 | 43 |
| 44 intptr_t Instruction::Hashcode() const { | 44 intptr_t Instruction::Hashcode() const { |
| 45 intptr_t result = tag(); | 45 intptr_t result = tag(); |
| 46 for (intptr_t i = 0; i < InputCount(); ++i) { | 46 for (intptr_t i = 0; i < InputCount(); ++i) { |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 ASSERT(other_op != NULL); | 139 ASSERT(other_op != NULL); |
| 140 return (op_kind() == other_op->op_kind()) && | 140 return (op_kind() == other_op->op_kind()) && |
| 141 (overflow_ == other_op->overflow_); | 141 (overflow_ == other_op->overflow_); |
| 142 } | 142 } |
| 143 | 143 |
| 144 | 144 |
| 145 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { | 145 bool LoadFieldInstr::AttributesEqual(Instruction* other) const { |
| 146 LoadFieldInstr* other_load = other->AsLoadField(); | 146 LoadFieldInstr* other_load = other->AsLoadField(); |
| 147 ASSERT(other_load != NULL); | 147 ASSERT(other_load != NULL); |
| 148 ASSERT((offset_in_bytes() != other_load->offset_in_bytes()) || | 148 ASSERT((offset_in_bytes() != other_load->offset_in_bytes()) || |
| 149 ((immutable_ == other_load->immutable_))); | 149 ((immutable_ == other_load->immutable_) && |
| 150 ((ResultCid() == other_load->ResultCid()) || |
| 151 (ResultCid() == kDynamicCid) || |
| 152 (other_load->ResultCid() == kDynamicCid)))); |
| 150 return offset_in_bytes() == other_load->offset_in_bytes(); | 153 return offset_in_bytes() == other_load->offset_in_bytes(); |
| 151 } | 154 } |
| 152 | 155 |
| 153 | 156 |
| 154 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { | 157 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { |
| 155 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); | 158 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); |
| 156 ASSERT(other_load != NULL); | 159 ASSERT(other_load != NULL); |
| 157 // Assert that the field is initialized. | 160 // Assert that the field is initialized. |
| 158 ASSERT(field().value() != Object::sentinel().raw()); | 161 ASSERT(field().value() != Object::sentinel().raw()); |
| 159 ASSERT(field().value() != Object::transition_sentinel().raw()); | 162 ASSERT(field().value() != Object::transition_sentinel().raw()); |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 ForwardInstructionIterator it(entry); | 400 ForwardInstructionIterator it(entry); |
| 398 current_iterator_ = ⁢ | 401 current_iterator_ = ⁢ |
| 399 for (; !it.Done(); it.Advance()) { | 402 for (; !it.Done(); it.Advance()) { |
| 400 it.Current()->Accept(this); | 403 it.Current()->Accept(this); |
| 401 } | 404 } |
| 402 current_iterator_ = NULL; | 405 current_iterator_ = NULL; |
| 403 } | 406 } |
| 404 } | 407 } |
| 405 | 408 |
| 406 | 409 |
| 407 bool Value::NeedsStoreBuffer() { | 410 // TODO(regis): Support a set of compile types for the given value. |
| 408 if (Type()->IsNull() || | 411 bool Value::CanComputeIsNull(bool* is_null) const { |
| 409 (Type()->ToNullableCid() == kSmiCid) || | 412 ASSERT(is_null != NULL); |
| 410 (Type()->ToNullableCid() == kBoolCid)) { | 413 // For now, we can only return a meaningful result if the value is constant. |
| 414 if (!BindsToConstant()) { |
| 411 return false; | 415 return false; |
| 412 } | 416 } |
| 413 | 417 |
| 418 // Return true if the constant value is Object::null. |
| 419 if (BindsToConstantNull()) { |
| 420 *is_null = true; |
| 421 return true; |
| 422 } |
| 423 |
| 424 // Consider the compile type of the value to check for sentinels, which are |
| 425 // also treated as null. |
| 426 const AbstractType& compile_type = AbstractType::Handle(CompileType()); |
| 427 ASSERT(!compile_type.IsMalformed()); |
| 428 ASSERT(!compile_type.IsVoidType()); |
| 429 |
| 430 // There are only three instances that can be of type Null: |
| 431 // Object::null(), Object::sentinel(), and Object::transition_sentinel(). |
| 432 // The inline code and run time code performing the type check will only |
| 433 // encounter the 2 sentinel values if type check elimination was disabled. |
| 434 // Otherwise, the type check of a sentinel value will be eliminated here, |
| 435 // because these sentinel values can only be encountered as constants, never |
| 436 // as actual value of a heap object being type checked. |
| 437 if (compile_type.IsNullType()) { |
| 438 *is_null = true; |
| 439 return true; |
| 440 } |
| 441 |
| 442 return false; |
| 443 } |
| 444 |
| 445 |
| 446 // TODO(regis): Support a set of compile types for the given value. |
| 447 bool Value::CanComputeIsInstanceOf(const AbstractType& type, |
| 448 bool* is_instance) const { |
| 449 ASSERT(is_instance != NULL); |
| 450 // We cannot give an answer if the given type is malformed. |
| 451 if (type.IsMalformed()) { |
| 452 return false; |
| 453 } |
| 454 |
| 455 // We should never test for an instance of null. |
| 456 ASSERT(!type.IsNullType()); |
| 457 |
| 458 // Consider the compile type of the value. |
| 459 const AbstractType& compile_type = AbstractType::Handle(CompileType()); |
| 460 if (compile_type.IsMalformed()) { |
| 461 return false; |
| 462 } |
| 463 |
| 464 // If the compile type of the value is void, we are type checking the result |
| 465 // of a void function, which was checked to be null at the return statement |
| 466 // inside the function. |
| 467 if (compile_type.IsVoidType()) { |
| 468 ASSERT(FLAG_enable_type_checks); |
| 469 *is_instance = true; |
| 470 return true; |
| 471 } |
| 472 |
| 473 // The Null type is only a subtype of Object and of dynamic. |
| 474 // Functions that do not explicitly return a value, implicitly return null, |
| 475 // except generative constructors, which return the object being constructed. |
| 476 // It is therefore acceptable for void functions to return null. |
| 477 if (compile_type.IsNullType()) { |
| 478 *is_instance = |
| 479 type.IsObjectType() || type.IsDynamicType() || type.IsVoidType(); |
| 480 return true; |
| 481 } |
| 482 |
| 483 // Until we support a set of compile types, we can only give answers for |
| 484 // constant values. Indeed, a variable of the proper compile time type may |
| 485 // still hold null at run time and therefore fail the test. |
| 486 if (!BindsToConstant()) { |
| 487 return false; |
| 488 } |
| 489 |
| 490 // A non-null constant is not an instance of void. |
| 491 if (type.IsVoidType()) { |
| 492 *is_instance = false; |
| 493 return true; |
| 494 } |
| 495 |
| 496 // Since the value is a constant, its type is instantiated. |
| 497 ASSERT(compile_type.IsInstantiated()); |
| 498 |
| 499 // The run time type of the value is guaranteed to be a subtype of the |
| 500 // compile time type of the value. However, establishing here that the |
| 501 // compile time type is a subtype of the given type does not guarantee that |
| 502 // the run time type will also be a subtype of the given type, because the |
| 503 // subtype relation is not transitive when an uninstantiated type is |
| 504 // involved. |
| 505 Error& malformed_error = Error::Handle(); |
| 506 if (type.IsInstantiated()) { |
| 507 // Perform the test on the compile-time type and provide the answer, unless |
| 508 // the type test produced a malformed error (e.g. an upper bound error). |
| 509 *is_instance = compile_type.IsSubtypeOf(type, &malformed_error); |
| 510 } else { |
| 511 // However, the 'more specific than' relation is transitive and used here. |
| 512 // In other words, if the compile type of the value is more specific than |
| 513 // the given type, the run time type of the value, which is guaranteed to be |
| 514 // a subtype of the compile type, is also guaranteed to be a subtype of the |
| 515 // given type. |
| 516 *is_instance = compile_type.IsMoreSpecificThan(type, &malformed_error); |
| 517 } |
| 518 return malformed_error.IsNull(); |
| 519 } |
| 520 |
| 521 |
| 522 bool Value::NeedsStoreBuffer() const { |
| 523 const intptr_t cid = ResultCid(); |
| 524 if ((cid == kSmiCid) || (cid == kBoolCid) || (cid == kNullCid)) { |
| 525 return false; |
| 526 } |
| 414 return !BindsToConstant(); | 527 return !BindsToConstant(); |
| 415 } | 528 } |
| 416 | 529 |
| 417 | 530 |
| 531 RawAbstractType* PhiInstr::CompileType() const { |
| 532 ASSERT(!HasPropagatedType()); |
| 533 // Since type propagation has not yet occured, we are reaching this phi via a |
| 534 // back edge phi input. Return null as compile type so that this input is |
| 535 // ignored in the first iteration of type propagation. |
| 536 return AbstractType::null(); |
| 537 } |
| 538 |
| 539 |
| 540 RawAbstractType* PhiInstr::LeastSpecificInputType() const { |
| 541 AbstractType& least_specific_type = AbstractType::Handle(); |
| 542 AbstractType& input_type = AbstractType::Handle(); |
| 543 for (intptr_t i = 0; i < InputCount(); i++) { |
| 544 input_type = InputAt(i)->CompileType(); |
| 545 if (input_type.IsNull()) { |
| 546 // This input is on a back edge and we are in the first iteration of type |
| 547 // propagation. Ignore it. |
| 548 continue; |
| 549 } |
| 550 ASSERT(!input_type.IsNull()); |
| 551 if (least_specific_type.IsNull() || |
| 552 least_specific_type.IsMoreSpecificThan(input_type, NULL)) { |
| 553 // Type input_type is less specific than the current least_specific_type. |
| 554 least_specific_type = input_type.raw(); |
| 555 } else if (input_type.IsMoreSpecificThan(least_specific_type, NULL)) { |
| 556 // Type least_specific_type is less specific than input_type. No change. |
| 557 } else { |
| 558 // The types are unrelated. No need to continue. |
| 559 least_specific_type = Type::ObjectType(); |
| 560 break; |
| 561 } |
| 562 } |
| 563 return least_specific_type.raw(); |
| 564 } |
| 565 |
| 566 |
| 567 RawAbstractType* ParameterInstr::CompileType() const { |
| 568 ASSERT(!HasPropagatedType()); |
| 569 // Note that returning the declared type of the formal parameter would be |
| 570 // incorrect, because ParameterInstr is used as input to the type check |
| 571 // verifying the run time type of the passed-in parameter and this check would |
| 572 // always be wrongly eliminated. |
| 573 return Type::DynamicType(); |
| 574 } |
| 575 |
| 576 |
| 577 RawAbstractType* PushArgumentInstr::CompileType() const { |
| 578 return AbstractType::null(); |
| 579 } |
| 580 |
| 581 |
| 418 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) { | 582 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) { |
| 419 // Require the predecessors to be sorted by block_id to make managing | 583 // Require the predecessors to be sorted by block_id to make managing |
| 420 // their corresponding phi inputs simpler. | 584 // their corresponding phi inputs simpler. |
| 421 intptr_t pred_id = predecessor->block_id(); | 585 intptr_t pred_id = predecessor->block_id(); |
| 422 intptr_t index = 0; | 586 intptr_t index = 0; |
| 423 while ((index < predecessors_.length()) && | 587 while ((index < predecessors_.length()) && |
| 424 (predecessors_[index]->block_id() < pred_id)) { | 588 (predecessors_[index]->block_id() < pred_id)) { |
| 425 ++index; | 589 ++index; |
| 426 } | 590 } |
| 427 #if defined(DEBUG) | 591 #if defined(DEBUG) |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 | 720 |
| 557 previous()->LinkTo(other); | 721 previous()->LinkTo(other); |
| 558 other->LinkTo(next()); | 722 other->LinkTo(next()); |
| 559 | 723 |
| 560 set_previous(NULL); | 724 set_previous(NULL); |
| 561 set_next(NULL); | 725 set_next(NULL); |
| 562 } | 726 } |
| 563 } | 727 } |
| 564 | 728 |
| 565 | 729 |
| 730 bool Definition::SetPropagatedCid(intptr_t cid) { |
| 731 if (cid == kIllegalCid) { |
| 732 return false; |
| 733 } |
| 734 if (propagated_cid_ == kIllegalCid) { |
| 735 // First setting, nothing has changed. |
| 736 propagated_cid_ = cid; |
| 737 return false; |
| 738 } |
| 739 bool has_changed = (propagated_cid_ != cid); |
| 740 propagated_cid_ = cid; |
| 741 return has_changed; |
| 742 } |
| 743 |
| 744 |
| 745 intptr_t Definition::GetPropagatedCid() { |
| 746 if (has_propagated_cid()) return propagated_cid(); |
| 747 intptr_t cid = ResultCid(); |
| 748 ASSERT(cid != kIllegalCid); |
| 749 SetPropagatedCid(cid); |
| 750 return cid; |
| 751 } |
| 752 |
| 753 |
| 754 intptr_t PhiInstr::GetPropagatedCid() { |
| 755 return propagated_cid(); |
| 756 } |
| 757 |
| 758 |
| 759 intptr_t ParameterInstr::GetPropagatedCid() { |
| 760 return propagated_cid(); |
| 761 } |
| 762 |
| 763 |
| 764 intptr_t AssertAssignableInstr::GetPropagatedCid() { |
| 765 return propagated_cid(); |
| 766 } |
| 767 |
| 768 |
| 566 // ==== Postorder graph traversal. | 769 // ==== Postorder graph traversal. |
| 567 static bool IsMarked(BlockEntryInstr* block, | 770 static bool IsMarked(BlockEntryInstr* block, |
| 568 GrowableArray<BlockEntryInstr*>* preorder) { | 771 GrowableArray<BlockEntryInstr*>* preorder) { |
| 569 // Detect that a block has been visited as part of the current | 772 // Detect that a block has been visited as part of the current |
| 570 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block | 773 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block |
| 571 // will be 'marked' by (1) having a preorder number in the range of the | 774 // will be 'marked' by (1) having a preorder number in the range of the |
| 572 // preorder array and (2) being in the preorder array at that index. | 775 // preorder array and (2) being in the preorder array at that index. |
| 573 intptr_t i = block->preorder_number(); | 776 intptr_t i = block->preorder_number(); |
| 574 return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block); | 777 return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block); |
| 575 } | 778 } |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 817 ASSERT(index == 0); | 1020 ASSERT(index == 0); |
| 818 return successor(); | 1021 return successor(); |
| 819 } | 1022 } |
| 820 | 1023 |
| 821 | 1024 |
| 822 void Instruction::Goto(JoinEntryInstr* entry) { | 1025 void Instruction::Goto(JoinEntryInstr* entry) { |
| 823 LinkTo(new GotoInstr(entry)); | 1026 LinkTo(new GotoInstr(entry)); |
| 824 } | 1027 } |
| 825 | 1028 |
| 826 | 1029 |
| 1030 RawAbstractType* Value::CompileType() const { |
| 1031 if (definition()->HasPropagatedType()) { |
| 1032 return definition()->PropagatedType(); |
| 1033 } |
| 1034 // The compile type may be requested when building the flow graph, i.e. before |
| 1035 // type propagation has occurred. To avoid repeatedly computing the compile |
| 1036 // type of the definition, we store it as initial propagated type. |
| 1037 AbstractType& type = AbstractType::Handle(definition()->CompileType()); |
| 1038 definition()->SetPropagatedType(type); |
| 1039 return type.raw(); |
| 1040 } |
| 1041 |
| 1042 |
| 1043 intptr_t Value::ResultCid() const { |
| 1044 if (reaching_cid() == kIllegalCid) { |
| 1045 return definition()->GetPropagatedCid(); |
| 1046 } |
| 1047 return reaching_cid(); |
| 1048 } |
| 1049 |
| 1050 |
| 1051 |
| 1052 RawAbstractType* ConstantInstr::CompileType() const { |
| 1053 if (value().IsNull()) { |
| 1054 return Type::NullType(); |
| 1055 } |
| 1056 if (value().IsInstance()) { |
| 1057 return Instance::Cast(value()).GetType(); |
| 1058 } else { |
| 1059 ASSERT(value().IsAbstractTypeArguments()); |
| 1060 return AbstractType::null(); |
| 1061 } |
| 1062 } |
| 1063 |
| 1064 |
| 1065 intptr_t ConstantInstr::ResultCid() const { |
| 1066 if (value().IsNull()) { |
| 1067 return kNullCid; |
| 1068 } |
| 1069 if (value().IsInstance()) { |
| 1070 return Class::Handle(value().clazz()).id(); |
| 1071 } else { |
| 1072 ASSERT(value().IsAbstractTypeArguments()); |
| 1073 return kDynamicCid; |
| 1074 } |
| 1075 } |
| 1076 |
| 1077 |
| 1078 RawAbstractType* AssertAssignableInstr::CompileType() const { |
| 1079 const AbstractType& value_compile_type = |
| 1080 AbstractType::Handle(value()->CompileType()); |
| 1081 if (!value_compile_type.IsNull() && |
| 1082 value_compile_type.IsMoreSpecificThan(dst_type(), NULL)) { |
| 1083 return value_compile_type.raw(); |
| 1084 } |
| 1085 return dst_type().raw(); |
| 1086 } |
| 1087 |
| 1088 |
| 1089 RawAbstractType* AssertBooleanInstr::CompileType() const { |
| 1090 return Type::BoolType(); |
| 1091 } |
| 1092 |
| 1093 |
| 1094 RawAbstractType* ArgumentDefinitionTestInstr::CompileType() const { |
| 1095 return Type::BoolType(); |
| 1096 } |
| 1097 |
| 1098 |
| 1099 RawAbstractType* CurrentContextInstr::CompileType() const { |
| 1100 return AbstractType::null(); |
| 1101 } |
| 1102 |
| 1103 |
| 1104 RawAbstractType* StoreContextInstr::CompileType() const { |
| 1105 return AbstractType::null(); |
| 1106 } |
| 1107 |
| 1108 |
| 1109 RawAbstractType* ClosureCallInstr::CompileType() const { |
| 1110 // Because of function subtyping rules, the declared return type of a closure |
| 1111 // call cannot be relied upon for compile type analysis. For example, a |
| 1112 // function returning dynamic can be assigned to a closure variable declared |
| 1113 // to return int and may actually return a double at run-time. |
| 1114 return Type::DynamicType(); |
| 1115 } |
| 1116 |
| 1117 |
| 1118 RawAbstractType* InstanceCallInstr::CompileType() const { |
| 1119 // TODO(regis): Return a more specific type than dynamic for recognized |
| 1120 // combinations of receiver type and method name. |
| 1121 return Type::DynamicType(); |
| 1122 } |
| 1123 |
| 1124 |
| 1125 RawAbstractType* PolymorphicInstanceCallInstr::CompileType() const { |
| 1126 return Type::DynamicType(); |
| 1127 } |
| 1128 |
| 1129 |
| 1130 RawAbstractType* StaticCallInstr::CompileType() const { |
| 1131 if (FLAG_enable_type_checks) { |
| 1132 return function().result_type(); |
| 1133 } |
| 1134 return Type::DynamicType(); |
| 1135 } |
| 1136 |
| 1137 |
| 1138 RawAbstractType* LoadLocalInstr::CompileType() const { |
| 1139 if (FLAG_enable_type_checks) { |
| 1140 return local().type().raw(); |
| 1141 } |
| 1142 return Type::DynamicType(); |
| 1143 } |
| 1144 |
| 1145 |
| 1146 RawAbstractType* StoreLocalInstr::CompileType() const { |
| 1147 return value()->CompileType(); |
| 1148 } |
| 1149 |
| 1150 |
| 1151 RawAbstractType* StrictCompareInstr::CompileType() const { |
| 1152 return Type::BoolType(); |
| 1153 } |
| 1154 |
| 1155 |
| 1156 // Only known == targets return a Boolean. |
| 1157 RawAbstractType* EqualityCompareInstr::CompileType() const { |
| 1158 if ((receiver_class_id() == kSmiCid) || |
| 1159 (receiver_class_id() == kDoubleCid) || |
| 1160 (receiver_class_id() == kNumberCid)) { |
| 1161 return Type::BoolType(); |
| 1162 } |
| 1163 return Type::DynamicType(); |
| 1164 } |
| 1165 |
| 1166 |
| 1167 intptr_t EqualityCompareInstr::ResultCid() const { |
| 1168 if ((receiver_class_id() == kSmiCid) || |
| 1169 (receiver_class_id() == kDoubleCid) || |
| 1170 (receiver_class_id() == kNumberCid)) { |
| 1171 // Known/library equalities that are guaranteed to return Boolean. |
| 1172 return kBoolCid; |
| 1173 } |
| 1174 return kDynamicCid; |
| 1175 } |
| 1176 |
| 1177 |
| 827 bool EqualityCompareInstr::IsPolymorphic() const { | 1178 bool EqualityCompareInstr::IsPolymorphic() const { |
| 828 return HasICData() && | 1179 return HasICData() && |
| 829 (ic_data()->NumberOfChecks() > 0) && | 1180 (ic_data()->NumberOfChecks() > 0) && |
| 830 (ic_data()->NumberOfChecks() <= FLAG_max_polymorphic_checks); | 1181 (ic_data()->NumberOfChecks() <= FLAG_max_polymorphic_checks); |
| 831 } | 1182 } |
| 832 | 1183 |
| 833 | 1184 |
| 1185 RawAbstractType* RelationalOpInstr::CompileType() const { |
| 1186 if ((operands_class_id() == kSmiCid) || |
| 1187 (operands_class_id() == kDoubleCid) || |
| 1188 (operands_class_id() == kNumberCid)) { |
| 1189 // Known/library relational ops that are guaranteed to return Boolean. |
| 1190 return Type::BoolType(); |
| 1191 } |
| 1192 return Type::DynamicType(); |
| 1193 } |
| 1194 |
| 1195 |
| 1196 intptr_t RelationalOpInstr::ResultCid() const { |
| 1197 if ((operands_class_id() == kSmiCid) || |
| 1198 (operands_class_id() == kDoubleCid) || |
| 1199 (operands_class_id() == kNumberCid)) { |
| 1200 // Known/library relational ops that are guaranteed to return Boolean. |
| 1201 return kBoolCid; |
| 1202 } |
| 1203 return kDynamicCid; |
| 1204 } |
| 1205 |
| 1206 |
| 1207 RawAbstractType* NativeCallInstr::CompileType() const { |
| 1208 // The result type of the native function is identical to the result type of |
| 1209 // the enclosing native Dart function. However, we prefer to check the type |
| 1210 // of the value returned from the native call. |
| 1211 return Type::DynamicType(); |
| 1212 } |
| 1213 |
| 1214 |
| 1215 RawAbstractType* StringFromCharCodeInstr::CompileType() const { |
| 1216 return Type::StringType(); |
| 1217 } |
| 1218 |
| 1219 |
| 1220 RawAbstractType* LoadIndexedInstr::CompileType() const { |
| 1221 switch (class_id_) { |
| 1222 case kArrayCid: |
| 1223 case kImmutableArrayCid: |
| 1224 return Type::DynamicType(); |
| 1225 case kFloat32ArrayCid : |
| 1226 case kFloat64ArrayCid : |
| 1227 return Type::Double(); |
| 1228 case kInt8ArrayCid: |
| 1229 case kUint8ArrayCid: |
| 1230 case kUint8ClampedArrayCid: |
| 1231 case kExternalUint8ArrayCid: |
| 1232 case kExternalUint8ClampedArrayCid: |
| 1233 case kInt16ArrayCid: |
| 1234 case kUint16ArrayCid: |
| 1235 case kInt32ArrayCid: |
| 1236 case kUint32ArrayCid: |
| 1237 case kOneByteStringCid: |
| 1238 case kTwoByteStringCid: |
| 1239 return Type::IntType(); |
| 1240 default: |
| 1241 UNIMPLEMENTED(); |
| 1242 return Type::IntType(); |
| 1243 } |
| 1244 } |
| 1245 |
| 1246 |
| 1247 RawAbstractType* StoreIndexedInstr::CompileType() const { |
| 1248 return AbstractType::null(); |
| 1249 } |
| 1250 |
| 1251 |
| 1252 RawAbstractType* StoreInstanceFieldInstr::CompileType() const { |
| 1253 return value()->CompileType(); |
| 1254 } |
| 1255 |
| 1256 |
| 1257 RawAbstractType* LoadStaticFieldInstr::CompileType() const { |
| 1258 if (FLAG_enable_type_checks) { |
| 1259 return field().type(); |
| 1260 } |
| 1261 return Type::DynamicType(); |
| 1262 } |
| 1263 |
| 1264 |
| 1265 RawAbstractType* StoreStaticFieldInstr::CompileType() const { |
| 1266 return value()->CompileType(); |
| 1267 } |
| 1268 |
| 1269 |
| 1270 RawAbstractType* BooleanNegateInstr::CompileType() const { |
| 1271 return Type::BoolType(); |
| 1272 } |
| 1273 |
| 1274 |
| 1275 RawAbstractType* InstanceOfInstr::CompileType() const { |
| 1276 return Type::BoolType(); |
| 1277 } |
| 1278 |
| 1279 |
| 1280 RawAbstractType* CreateArrayInstr::CompileType() const { |
| 1281 return type().raw(); |
| 1282 } |
| 1283 |
| 1284 |
| 1285 RawAbstractType* CreateClosureInstr::CompileType() const { |
| 1286 const Function& fun = function(); |
| 1287 const Class& signature_class = Class::Handle(fun.signature_class()); |
| 1288 return signature_class.SignatureType(); |
| 1289 } |
| 1290 |
| 1291 |
| 1292 RawAbstractType* AllocateObjectInstr::CompileType() const { |
| 1293 // TODO(regis): Be more specific. |
| 1294 return Type::DynamicType(); |
| 1295 } |
| 1296 |
| 1297 |
| 1298 RawAbstractType* AllocateObjectWithBoundsCheckInstr::CompileType() const { |
| 1299 // TODO(regis): Be more specific. |
| 1300 return Type::DynamicType(); |
| 1301 } |
| 1302 |
| 1303 |
| 1304 RawAbstractType* LoadFieldInstr::CompileType() const { |
| 1305 // Type may be null if the field is a VM field, e.g. context parent. |
| 1306 // Keep it as null for debug purposes and do not return dynamic in production |
| 1307 // mode, since misuse of the type would remain undetected. |
| 1308 if (type().IsNull()) { |
| 1309 return AbstractType::null(); |
| 1310 } |
| 1311 if (FLAG_enable_type_checks) { |
| 1312 return type().raw(); |
| 1313 } |
| 1314 return Type::DynamicType(); |
| 1315 } |
| 1316 |
| 1317 |
| 1318 RawAbstractType* StoreVMFieldInstr::CompileType() const { |
| 1319 return value()->CompileType(); |
| 1320 } |
| 1321 |
| 1322 |
| 1323 RawAbstractType* InstantiateTypeArgumentsInstr::CompileType() const { |
| 1324 return AbstractType::null(); |
| 1325 } |
| 1326 |
| 1327 |
| 1328 RawAbstractType* ExtractConstructorTypeArgumentsInstr::CompileType() const { |
| 1329 return AbstractType::null(); |
| 1330 } |
| 1331 |
| 1332 |
| 1333 RawAbstractType* ExtractConstructorInstantiatorInstr::CompileType() const { |
| 1334 return AbstractType::null(); |
| 1335 } |
| 1336 |
| 1337 |
| 1338 RawAbstractType* AllocateContextInstr::CompileType() const { |
| 1339 return AbstractType::null(); |
| 1340 } |
| 1341 |
| 1342 |
| 1343 RawAbstractType* ChainContextInstr::CompileType() const { |
| 1344 return AbstractType::null(); |
| 1345 } |
| 1346 |
| 1347 |
| 1348 RawAbstractType* CloneContextInstr::CompileType() const { |
| 1349 return AbstractType::null(); |
| 1350 } |
| 1351 |
| 1352 |
| 1353 RawAbstractType* CatchEntryInstr::CompileType() const { |
| 1354 return AbstractType::null(); |
| 1355 } |
| 1356 |
| 1357 |
| 1358 RawAbstractType* CheckStackOverflowInstr::CompileType() const { |
| 1359 return AbstractType::null(); |
| 1360 } |
| 1361 |
| 1362 |
| 1363 RawAbstractType* BinarySmiOpInstr::CompileType() const { |
| 1364 return Type::SmiType(); |
| 1365 } |
| 1366 |
| 1367 |
| 1368 intptr_t BinarySmiOpInstr::ResultCid() const { |
| 1369 return kSmiCid; |
| 1370 } |
| 1371 |
| 1372 |
| 834 bool BinarySmiOpInstr::CanDeoptimize() const { | 1373 bool BinarySmiOpInstr::CanDeoptimize() const { |
| 835 switch (op_kind()) { | 1374 switch (op_kind()) { |
| 836 case Token::kBIT_AND: | 1375 case Token::kBIT_AND: |
| 837 case Token::kBIT_OR: | 1376 case Token::kBIT_OR: |
| 838 case Token::kBIT_XOR: | 1377 case Token::kBIT_XOR: |
| 839 return false; | 1378 return false; |
| 840 case Token::kSHR: { | 1379 case Token::kSHR: { |
| 841 // Can't deopt if shift-count is known positive. | 1380 // Can't deopt if shift-count is known positive. |
| 842 Range* right_range = this->right()->definition()->range(); | 1381 Range* right_range = this->right()->definition()->range(); |
| 843 return (right_range == NULL) | 1382 return (right_range == NULL) |
| 844 || !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); | 1383 || !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); |
| 845 } | 1384 } |
| 846 default: | 1385 default: |
| 847 return overflow_; | 1386 return overflow_; |
| 848 } | 1387 } |
| 849 } | 1388 } |
| 850 | 1389 |
| 851 | 1390 |
| 852 bool BinarySmiOpInstr::RightIsPowerOfTwoConstant() const { | 1391 bool BinarySmiOpInstr::RightIsPowerOfTwoConstant() const { |
| 853 if (!right()->definition()->IsConstant()) return false; | 1392 if (!right()->definition()->IsConstant()) return false; |
| 854 const Object& constant = right()->definition()->AsConstant()->value(); | 1393 const Object& constant = right()->definition()->AsConstant()->value(); |
| 855 if (!constant.IsSmi()) return false; | 1394 if (!constant.IsSmi()) return false; |
| 856 const intptr_t int_value = Smi::Cast(constant).Value(); | 1395 const intptr_t int_value = Smi::Cast(constant).Value(); |
| 857 if (int_value == 0) return false; | 1396 if (int_value == 0) return false; |
| 858 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); | 1397 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); |
| 859 } | 1398 } |
| 860 | 1399 |
| 861 | 1400 |
| 1401 RawAbstractType* BinaryMintOpInstr::CompileType() const { |
| 1402 return Type::IntType(); |
| 1403 } |
| 1404 |
| 1405 |
| 1406 intptr_t BinaryMintOpInstr::ResultCid() const { |
| 1407 return kDynamicCid; |
| 1408 } |
| 1409 |
| 1410 |
| 1411 RawAbstractType* ShiftMintOpInstr::CompileType() const { |
| 1412 return Type::IntType(); |
| 1413 } |
| 1414 |
| 1415 |
| 1416 intptr_t ShiftMintOpInstr::ResultCid() const { |
| 1417 return kDynamicCid; |
| 1418 } |
| 1419 |
| 1420 |
| 1421 RawAbstractType* UnaryMintOpInstr::CompileType() const { |
| 1422 return Type::IntType(); |
| 1423 } |
| 1424 |
| 1425 |
| 1426 intptr_t UnaryMintOpInstr::ResultCid() const { |
| 1427 return kDynamicCid; |
| 1428 } |
| 1429 |
| 1430 |
| 1431 RawAbstractType* BinaryDoubleOpInstr::CompileType() const { |
| 1432 return Type::Double(); |
| 1433 } |
| 1434 |
| 1435 |
| 1436 intptr_t BinaryDoubleOpInstr::ResultCid() const { |
| 1437 // The output is not an instance but when it is boxed it becomes double. |
| 1438 return kDoubleCid; |
| 1439 } |
| 1440 |
| 1441 |
| 862 static bool ToIntegerConstant(Value* value, intptr_t* result) { | 1442 static bool ToIntegerConstant(Value* value, intptr_t* result) { |
| 863 if (!value->BindsToConstant()) { | 1443 if (!value->BindsToConstant()) { |
| 864 if (value->definition()->IsUnboxDouble()) { | 1444 if (value->definition()->IsUnboxDouble()) { |
| 865 return ToIntegerConstant(value->definition()->AsUnboxDouble()->value(), | 1445 return ToIntegerConstant(value->definition()->AsUnboxDouble()->value(), |
| 866 result); | 1446 result); |
| 867 } | 1447 } |
| 868 | 1448 |
| 869 return false; | 1449 return false; |
| 870 } | 1450 } |
| 871 | 1451 |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1012 right(), | 1592 right(), |
| 1013 left()); | 1593 left()); |
| 1014 if (result != NULL) { | 1594 if (result != NULL) { |
| 1015 return result; | 1595 return result; |
| 1016 } | 1596 } |
| 1017 | 1597 |
| 1018 return this; | 1598 return this; |
| 1019 } | 1599 } |
| 1020 | 1600 |
| 1021 | 1601 |
| 1602 RawAbstractType* MathSqrtInstr::CompileType() const { |
| 1603 return Type::Double(); |
| 1604 } |
| 1605 |
| 1606 |
| 1607 RawAbstractType* UnboxDoubleInstr::CompileType() const { |
| 1608 return Type::null(); |
| 1609 } |
| 1610 |
| 1611 |
| 1612 intptr_t BoxDoubleInstr::ResultCid() const { |
| 1613 return kDoubleCid; |
| 1614 } |
| 1615 |
| 1616 |
| 1617 RawAbstractType* BoxDoubleInstr::CompileType() const { |
| 1618 return Type::Double(); |
| 1619 } |
| 1620 |
| 1621 |
| 1622 intptr_t BoxIntegerInstr::ResultCid() const { |
| 1623 return kDynamicCid; |
| 1624 } |
| 1625 |
| 1626 |
| 1627 RawAbstractType* BoxIntegerInstr::CompileType() const { |
| 1628 return Type::IntType(); |
| 1629 } |
| 1630 |
| 1631 |
| 1632 intptr_t UnboxIntegerInstr::ResultCid() const { |
| 1633 return kDynamicCid; |
| 1634 } |
| 1635 |
| 1636 |
| 1637 RawAbstractType* UnboxIntegerInstr::CompileType() const { |
| 1638 return Type::null(); |
| 1639 } |
| 1640 |
| 1641 |
| 1642 RawAbstractType* UnarySmiOpInstr::CompileType() const { |
| 1643 return Type::SmiType(); |
| 1644 } |
| 1645 |
| 1646 |
| 1647 RawAbstractType* SmiToDoubleInstr::CompileType() const { |
| 1648 return Type::Double(); |
| 1649 } |
| 1650 |
| 1651 |
| 1652 RawAbstractType* DoubleToIntegerInstr::CompileType() const { |
| 1653 return Type::IntType(); |
| 1654 } |
| 1655 |
| 1656 |
| 1657 RawAbstractType* DoubleToSmiInstr::CompileType() const { |
| 1658 return Type::SmiType(); |
| 1659 } |
| 1660 |
| 1661 |
| 1662 RawAbstractType* DoubleToDoubleInstr::CompileType() const { |
| 1663 return Type::Double(); |
| 1664 } |
| 1665 |
| 1666 |
| 1667 RawAbstractType* InvokeMathCFunctionInstr::CompileType() const { |
| 1668 return Type::Double(); |
| 1669 } |
| 1670 |
| 1671 |
| 1672 RawAbstractType* CheckClassInstr::CompileType() const { |
| 1673 return AbstractType::null(); |
| 1674 } |
| 1675 |
| 1676 |
| 1677 RawAbstractType* CheckSmiInstr::CompileType() const { |
| 1678 return AbstractType::null(); |
| 1679 } |
| 1680 |
| 1681 |
| 1682 RawAbstractType* CheckArrayBoundInstr::CompileType() const { |
| 1683 return AbstractType::null(); |
| 1684 } |
| 1685 |
| 1686 |
| 1687 RawAbstractType* CheckEitherNonSmiInstr::CompileType() const { |
| 1688 return AbstractType::null(); |
| 1689 } |
| 1690 |
| 1691 |
| 1022 // Optimizations that eliminate or simplify individual instructions. | 1692 // Optimizations that eliminate or simplify individual instructions. |
| 1023 Instruction* Instruction::Canonicalize(FlowGraphOptimizer* optimizer) { | 1693 Instruction* Instruction::Canonicalize(FlowGraphOptimizer* optimizer) { |
| 1024 return this; | 1694 return this; |
| 1025 } | 1695 } |
| 1026 | 1696 |
| 1027 | 1697 |
| 1028 Definition* Definition::Canonicalize(FlowGraphOptimizer* optimizer) { | 1698 Definition* Definition::Canonicalize(FlowGraphOptimizer* optimizer) { |
| 1029 return this; | 1699 return this; |
| 1030 } | 1700 } |
| 1031 | 1701 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1075 | 1745 |
| 1076 Definition* LoadFieldInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1746 Definition* LoadFieldInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
| 1077 if (!IsImmutableLengthLoad()) return this; | 1747 if (!IsImmutableLengthLoad()) return this; |
| 1078 | 1748 |
| 1079 // For fixed length arrays if the array is the result of a known constructor | 1749 // For fixed length arrays if the array is the result of a known constructor |
| 1080 // call we can replace the length load with the length argument passed to | 1750 // call we can replace the length load with the length argument passed to |
| 1081 // the constructor. | 1751 // the constructor. |
| 1082 StaticCallInstr* call = value()->definition()->AsStaticCall(); | 1752 StaticCallInstr* call = value()->definition()->AsStaticCall(); |
| 1083 if (call != NULL && | 1753 if (call != NULL && |
| 1084 call->is_known_constructor() && | 1754 call->is_known_constructor() && |
| 1085 (call->Type()->ToCid() == kArrayCid)) { | 1755 call->ResultCid() == kArrayCid) { |
| 1086 return call->ArgumentAt(1)->value()->definition(); | 1756 return call->ArgumentAt(1)->value()->definition(); |
| 1087 } | 1757 } |
| 1088 return this; | 1758 return this; |
| 1089 } | 1759 } |
| 1090 | 1760 |
| 1091 | 1761 |
| 1092 Definition* AssertBooleanInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1762 Definition* AssertBooleanInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
| 1093 if (FLAG_eliminate_type_checks && (value()->Type()->ToCid() == kBoolCid)) { | 1763 const intptr_t value_cid = value()->ResultCid(); |
| 1094 return value()->definition(); | 1764 return (value_cid == kBoolCid) ? value()->definition() : this; |
| 1095 } | |
| 1096 | |
| 1097 return this; | |
| 1098 } | 1765 } |
| 1099 | 1766 |
| 1100 | 1767 |
| 1101 Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1768 Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
| 1102 if (FLAG_eliminate_type_checks && | 1769 // (1) Replace the assert with its input if the input has a known compatible |
| 1103 value()->Type()->IsAssignableTo(dst_type())) { | 1770 // class-id. The class-ids handled here are those that are known to be |
| 1104 return value()->definition(); | 1771 // results of IL instructions. |
| 1772 intptr_t cid = value()->ResultCid(); |
| 1773 bool is_redundant = false; |
| 1774 if (dst_type().IsIntType()) { |
| 1775 is_redundant = (cid == kSmiCid) || (cid == kMintCid); |
| 1776 } else if (dst_type().IsDoubleType()) { |
| 1777 is_redundant = (cid == kDoubleCid); |
| 1778 } else if (dst_type().IsBoolType()) { |
| 1779 is_redundant = (cid == kBoolCid); |
| 1780 } |
| 1781 if (is_redundant) return value()->definition(); |
| 1782 |
| 1783 // (2) Replace the assert with its input if the input is the result of a |
| 1784 // compatible assert itself. |
| 1785 AssertAssignableInstr* check = value()->definition()->AsAssertAssignable(); |
| 1786 if ((check != NULL) && check->dst_type().Equals(dst_type())) { |
| 1787 // TODO(fschneider): Propagate type-assertions across phi-nodes. |
| 1788 // TODO(fschneider): Eliminate more asserts with subtype relation. |
| 1789 return check; |
| 1105 } | 1790 } |
| 1106 | 1791 |
| 1107 // (3) For uninstantiated target types: If the instantiator type arguments | 1792 // (3) For uninstantiated target types: If the instantiator type arguments |
| 1108 // are constant, instantiate the target type here. | 1793 // are constant, instantiate the target type here. |
| 1109 if (dst_type().IsInstantiated()) return this; | 1794 if (dst_type().IsInstantiated()) return this; |
| 1110 | 1795 |
| 1111 ConstantInstr* constant_type_args = | 1796 ConstantInstr* constant_type_args = |
| 1112 instantiator_type_arguments()->definition()->AsConstant(); | 1797 instantiator_type_arguments()->definition()->AsConstant(); |
| 1113 if (constant_type_args != NULL && | 1798 if (constant_type_args != NULL && |
| 1114 !constant_type_args->value().IsNull() && | 1799 !constant_type_args->value().IsNull() && |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1167 | 1852 |
| 1168 | 1853 |
| 1169 Definition* StrictCompareInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1854 Definition* StrictCompareInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
| 1170 if (!right()->BindsToConstant()) return this; | 1855 if (!right()->BindsToConstant()) return this; |
| 1171 const Object& right_constant = right()->BoundConstant(); | 1856 const Object& right_constant = right()->BoundConstant(); |
| 1172 Definition* left_defn = left()->definition(); | 1857 Definition* left_defn = left()->definition(); |
| 1173 // TODO(fschneider): Handle other cases: e === false and e !== true/false. | 1858 // TODO(fschneider): Handle other cases: e === false and e !== true/false. |
| 1174 // Handles e === true. | 1859 // Handles e === true. |
| 1175 if ((kind() == Token::kEQ_STRICT) && | 1860 if ((kind() == Token::kEQ_STRICT) && |
| 1176 (right_constant.raw() == Bool::True().raw()) && | 1861 (right_constant.raw() == Bool::True().raw()) && |
| 1177 (left()->Type()->ToCid() == kBoolCid)) { | 1862 (left()->ResultCid() == kBoolCid)) { |
| 1178 // Return left subexpression as the replacement for this instruction. | 1863 // Return left subexpression as the replacement for this instruction. |
| 1179 return left_defn; | 1864 return left_defn; |
| 1180 } | 1865 } |
| 1181 return this; | 1866 return this; |
| 1182 } | 1867 } |
| 1183 | 1868 |
| 1184 | 1869 |
| 1185 Instruction* CheckClassInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1870 Instruction* CheckClassInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
| 1186 // TODO(vegorov): Replace class checks with null checks when ToNullableCid | 1871 const intptr_t value_cid = value()->ResultCid(); |
| 1187 // matches. | |
| 1188 | |
| 1189 const intptr_t value_cid = value()->Type()->ToCid(); | |
| 1190 if (value_cid == kDynamicCid) { | 1872 if (value_cid == kDynamicCid) { |
| 1191 return this; | 1873 return this; |
| 1192 } | 1874 } |
| 1193 | 1875 |
| 1194 const intptr_t num_checks = unary_checks().NumberOfChecks(); | 1876 const intptr_t num_checks = unary_checks().NumberOfChecks(); |
| 1195 | 1877 |
| 1196 for (intptr_t i = 0; i < num_checks; i++) { | 1878 for (intptr_t i = 0; i < num_checks; i++) { |
| 1197 if (value_cid == unary_checks().GetReceiverClassIdAt(i)) { | 1879 if (value_cid == unary_checks().GetReceiverClassIdAt(i)) { |
| 1198 // No checks needed. | 1880 // No checks needed. |
| 1199 return NULL; | 1881 return NULL; |
| 1200 } | 1882 } |
| 1201 } | 1883 } |
| 1202 | 1884 |
| 1203 return this; | 1885 return this; |
| 1204 } | 1886 } |
| 1205 | 1887 |
| 1206 | 1888 |
| 1207 Instruction* CheckSmiInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1889 Instruction* CheckSmiInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
| 1208 return (value()->Type()->ToCid() == kSmiCid) ? NULL : this; | 1890 return (value()->ResultCid() == kSmiCid) ? NULL : this; |
| 1209 } | 1891 } |
| 1210 | 1892 |
| 1211 | 1893 |
| 1212 Instruction* CheckEitherNonSmiInstr::Canonicalize( | 1894 Instruction* CheckEitherNonSmiInstr::Canonicalize( |
| 1213 FlowGraphOptimizer* optimizer) { | 1895 FlowGraphOptimizer* optimizer) { |
| 1214 if ((left()->Type()->ToCid() == kDoubleCid) || | 1896 if ((left()->ResultCid() == kDoubleCid) || |
| 1215 (right()->Type()->ToCid() == kDoubleCid)) { | 1897 (right()->ResultCid() == kDoubleCid)) { |
| 1216 return NULL; // Remove from the graph. | 1898 return NULL; // Remove from the graph. |
| 1217 } | 1899 } |
| 1218 return this; | 1900 return this; |
| 1219 } | 1901 } |
| 1220 | 1902 |
| 1221 | 1903 |
| 1222 // Shared code generation methods (EmitNativeCode, MakeLocationSummary, and | 1904 // Shared code generation methods (EmitNativeCode, MakeLocationSummary, and |
| 1223 // PrepareEntry). Only assembly code that can be shared across all architectures | 1905 // PrepareEntry). Only assembly code that can be shared across all architectures |
| 1224 // can be used. Machine specific register allocation and code generation | 1906 // can be used. Machine specific register allocation and code generation |
| 1225 // is located in intermediate_language_<arch>.cc | 1907 // is located in intermediate_language_<arch>.cc |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1424 token_pos(), | 2106 token_pos(), |
| 1425 function(), | 2107 function(), |
| 1426 ArgumentCount(), | 2108 ArgumentCount(), |
| 1427 argument_names(), | 2109 argument_names(), |
| 1428 locs()); | 2110 locs()); |
| 1429 __ Bind(&skip_call); | 2111 __ Bind(&skip_call); |
| 1430 } | 2112 } |
| 1431 | 2113 |
| 1432 | 2114 |
| 1433 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 2115 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1434 compiler->GenerateAssertAssignable(token_pos(), | 2116 if (!is_eliminated()) { |
| 1435 deopt_id(), | 2117 compiler->GenerateAssertAssignable(token_pos(), |
| 1436 dst_type(), | 2118 deopt_id(), |
| 1437 dst_name(), | 2119 dst_type(), |
| 1438 locs()); | 2120 dst_name(), |
| 2121 locs()); |
| 2122 } |
| 1439 ASSERT(locs()->in(0).reg() == locs()->out().reg()); | 2123 ASSERT(locs()->in(0).reg() == locs()->out().reg()); |
| 1440 } | 2124 } |
| 1441 | 2125 |
| 1442 | 2126 |
| 1443 Environment* Environment::From(const GrowableArray<Definition*>& definitions, | 2127 Environment* Environment::From(const GrowableArray<Definition*>& definitions, |
| 1444 intptr_t fixed_parameter_count, | 2128 intptr_t fixed_parameter_count, |
| 1445 const Function& function) { | 2129 const Function& function) { |
| 1446 Environment* env = | 2130 Environment* env = |
| 1447 new Environment(definitions.length(), | 2131 new Environment(definitions.length(), |
| 1448 fixed_parameter_count, | 2132 fixed_parameter_count, |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1700 } | 2384 } |
| 1701 | 2385 |
| 1702 const intptr_t max_a = a.UpperBound().Clamp().value(); | 2386 const intptr_t max_a = a.UpperBound().Clamp().value(); |
| 1703 const intptr_t max_b = b.UpperBound().Clamp().value(); | 2387 const intptr_t max_b = b.UpperBound().Clamp().value(); |
| 1704 | 2388 |
| 1705 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); | 2389 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); |
| 1706 } | 2390 } |
| 1707 | 2391 |
| 1708 | 2392 |
| 1709 void Definition::InferRange() { | 2393 void Definition::InferRange() { |
| 1710 ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis. | 2394 ASSERT(GetPropagatedCid() == kSmiCid); // Has meaning only for smis. |
| 1711 if (range_ == NULL) { | 2395 if (range_ == NULL) { |
| 1712 range_ = Range::Unknown(); | 2396 range_ = Range::Unknown(); |
| 1713 } | 2397 } |
| 1714 } | 2398 } |
| 1715 | 2399 |
| 1716 | 2400 |
| 1717 void ConstantInstr::InferRange() { | 2401 void ConstantInstr::InferRange() { |
| 1718 ASSERT(value_.IsSmi()); | 2402 ASSERT(value_.IsSmi()); |
| 1719 if (range_ == NULL) { | 2403 if (range_ == NULL) { |
| 1720 intptr_t value = Smi::Cast(value_).Value(); | 2404 intptr_t value = Smi::Cast(value_).Value(); |
| (...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2184 default: | 2868 default: |
| 2185 UNREACHABLE(); | 2869 UNREACHABLE(); |
| 2186 } | 2870 } |
| 2187 return kPowRuntimeEntry; | 2871 return kPowRuntimeEntry; |
| 2188 } | 2872 } |
| 2189 | 2873 |
| 2190 | 2874 |
| 2191 #undef __ | 2875 #undef __ |
| 2192 | 2876 |
| 2193 } // namespace dart | 2877 } // namespace dart |
| OLD | NEW |