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); |
28 DECLARE_FLAG(int, max_polymorphic_checks); | 29 DECLARE_FLAG(int, max_polymorphic_checks); |
29 DECLARE_FLAG(bool, trace_optimization); | 30 DECLARE_FLAG(bool, trace_optimization); |
30 | 31 |
31 Definition::Definition() | 32 Definition::Definition() |
32 : range_(NULL), | 33 : range_(NULL), |
| 34 type_(NULL), |
33 temp_index_(-1), | 35 temp_index_(-1), |
34 ssa_temp_index_(-1), | 36 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)))); | |
153 return offset_in_bytes() == other_load->offset_in_bytes(); | 150 return offset_in_bytes() == other_load->offset_in_bytes(); |
154 } | 151 } |
155 | 152 |
156 | 153 |
157 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { | 154 bool LoadStaticFieldInstr::AttributesEqual(Instruction* other) const { |
158 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); | 155 LoadStaticFieldInstr* other_load = other->AsLoadStaticField(); |
159 ASSERT(other_load != NULL); | 156 ASSERT(other_load != NULL); |
160 // Assert that the field is initialized. | 157 // Assert that the field is initialized. |
161 ASSERT(field().value() != Object::sentinel().raw()); | 158 ASSERT(field().value() != Object::sentinel().raw()); |
162 ASSERT(field().value() != Object::transition_sentinel().raw()); | 159 ASSERT(field().value() != Object::transition_sentinel().raw()); |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 ForwardInstructionIterator it(entry); | 397 ForwardInstructionIterator it(entry); |
401 current_iterator_ = ⁢ | 398 current_iterator_ = ⁢ |
402 for (; !it.Done(); it.Advance()) { | 399 for (; !it.Done(); it.Advance()) { |
403 it.Current()->Accept(this); | 400 it.Current()->Accept(this); |
404 } | 401 } |
405 current_iterator_ = NULL; | 402 current_iterator_ = NULL; |
406 } | 403 } |
407 } | 404 } |
408 | 405 |
409 | 406 |
410 // TODO(regis): Support a set of compile types for the given value. | 407 bool Value::NeedsStoreBuffer() { |
411 bool Value::CanComputeIsNull(bool* is_null) const { | 408 if (Type()->IsNull() || |
412 ASSERT(is_null != NULL); | 409 (Type()->ToNullableCid() == kSmiCid) || |
413 // For now, we can only return a meaningful result if the value is constant. | 410 (Type()->ToNullableCid() == kBoolCid)) { |
414 if (!BindsToConstant()) { | |
415 return false; | 411 return false; |
416 } | 412 } |
417 | 413 |
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 } | |
527 return !BindsToConstant(); | 414 return !BindsToConstant(); |
528 } | 415 } |
529 | 416 |
530 | 417 |
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 | |
582 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) { | 418 void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) { |
583 // Require the predecessors to be sorted by block_id to make managing | 419 // Require the predecessors to be sorted by block_id to make managing |
584 // their corresponding phi inputs simpler. | 420 // their corresponding phi inputs simpler. |
585 intptr_t pred_id = predecessor->block_id(); | 421 intptr_t pred_id = predecessor->block_id(); |
586 intptr_t index = 0; | 422 intptr_t index = 0; |
587 while ((index < predecessors_.length()) && | 423 while ((index < predecessors_.length()) && |
588 (predecessors_[index]->block_id() < pred_id)) { | 424 (predecessors_[index]->block_id() < pred_id)) { |
589 ++index; | 425 ++index; |
590 } | 426 } |
591 #if defined(DEBUG) | 427 #if defined(DEBUG) |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
720 | 556 |
721 previous()->LinkTo(other); | 557 previous()->LinkTo(other); |
722 other->LinkTo(next()); | 558 other->LinkTo(next()); |
723 | 559 |
724 set_previous(NULL); | 560 set_previous(NULL); |
725 set_next(NULL); | 561 set_next(NULL); |
726 } | 562 } |
727 } | 563 } |
728 | 564 |
729 | 565 |
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 | |
769 // ==== Postorder graph traversal. | 566 // ==== Postorder graph traversal. |
770 static bool IsMarked(BlockEntryInstr* block, | 567 static bool IsMarked(BlockEntryInstr* block, |
771 GrowableArray<BlockEntryInstr*>* preorder) { | 568 GrowableArray<BlockEntryInstr*>* preorder) { |
772 // Detect that a block has been visited as part of the current | 569 // Detect that a block has been visited as part of the current |
773 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block | 570 // DiscoverBlocks (we can call DiscoverBlocks multiple times). The block |
774 // will be 'marked' by (1) having a preorder number in the range of the | 571 // will be 'marked' by (1) having a preorder number in the range of the |
775 // preorder array and (2) being in the preorder array at that index. | 572 // preorder array and (2) being in the preorder array at that index. |
776 intptr_t i = block->preorder_number(); | 573 intptr_t i = block->preorder_number(); |
777 return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block); | 574 return (i >= 0) && (i < preorder->length()) && ((*preorder)[i] == block); |
778 } | 575 } |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1020 ASSERT(index == 0); | 817 ASSERT(index == 0); |
1021 return successor(); | 818 return successor(); |
1022 } | 819 } |
1023 | 820 |
1024 | 821 |
1025 void Instruction::Goto(JoinEntryInstr* entry) { | 822 void Instruction::Goto(JoinEntryInstr* entry) { |
1026 LinkTo(new GotoInstr(entry)); | 823 LinkTo(new GotoInstr(entry)); |
1027 } | 824 } |
1028 | 825 |
1029 | 826 |
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 | |
1178 bool EqualityCompareInstr::IsPolymorphic() const { | 827 bool EqualityCompareInstr::IsPolymorphic() const { |
1179 return HasICData() && | 828 return HasICData() && |
1180 (ic_data()->NumberOfChecks() > 0) && | 829 (ic_data()->NumberOfChecks() > 0) && |
1181 (ic_data()->NumberOfChecks() <= FLAG_max_polymorphic_checks); | 830 (ic_data()->NumberOfChecks() <= FLAG_max_polymorphic_checks); |
1182 } | 831 } |
1183 | 832 |
1184 | 833 |
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 | |
1373 bool BinarySmiOpInstr::CanDeoptimize() const { | 834 bool BinarySmiOpInstr::CanDeoptimize() const { |
1374 switch (op_kind()) { | 835 switch (op_kind()) { |
1375 case Token::kBIT_AND: | 836 case Token::kBIT_AND: |
1376 case Token::kBIT_OR: | 837 case Token::kBIT_OR: |
1377 case Token::kBIT_XOR: | 838 case Token::kBIT_XOR: |
1378 return false; | 839 return false; |
1379 case Token::kSHR: { | 840 case Token::kSHR: { |
1380 // Can't deopt if shift-count is known positive. | 841 // Can't deopt if shift-count is known positive. |
1381 Range* right_range = this->right()->definition()->range(); | 842 Range* right_range = this->right()->definition()->range(); |
1382 return (right_range == NULL) | 843 return (right_range == NULL) |
1383 || !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); | 844 || !right_range->IsWithin(0, RangeBoundary::kPlusInfinity); |
1384 } | 845 } |
1385 default: | 846 default: |
1386 return overflow_; | 847 return overflow_; |
1387 } | 848 } |
1388 } | 849 } |
1389 | 850 |
1390 | 851 |
1391 bool BinarySmiOpInstr::RightIsPowerOfTwoConstant() const { | 852 bool BinarySmiOpInstr::RightIsPowerOfTwoConstant() const { |
1392 if (!right()->definition()->IsConstant()) return false; | 853 if (!right()->definition()->IsConstant()) return false; |
1393 const Object& constant = right()->definition()->AsConstant()->value(); | 854 const Object& constant = right()->definition()->AsConstant()->value(); |
1394 if (!constant.IsSmi()) return false; | 855 if (!constant.IsSmi()) return false; |
1395 const intptr_t int_value = Smi::Cast(constant).Value(); | 856 const intptr_t int_value = Smi::Cast(constant).Value(); |
1396 if (int_value == 0) return false; | 857 if (int_value == 0) return false; |
1397 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); | 858 return Utils::IsPowerOfTwo(Utils::Abs(int_value)); |
1398 } | 859 } |
1399 | 860 |
1400 | 861 |
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 | |
1442 static bool ToIntegerConstant(Value* value, intptr_t* result) { | 862 static bool ToIntegerConstant(Value* value, intptr_t* result) { |
1443 if (!value->BindsToConstant()) { | 863 if (!value->BindsToConstant()) { |
1444 if (value->definition()->IsUnboxDouble()) { | 864 if (value->definition()->IsUnboxDouble()) { |
1445 return ToIntegerConstant(value->definition()->AsUnboxDouble()->value(), | 865 return ToIntegerConstant(value->definition()->AsUnboxDouble()->value(), |
1446 result); | 866 result); |
1447 } | 867 } |
1448 | 868 |
1449 return false; | 869 return false; |
1450 } | 870 } |
1451 | 871 |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1592 right(), | 1012 right(), |
1593 left()); | 1013 left()); |
1594 if (result != NULL) { | 1014 if (result != NULL) { |
1595 return result; | 1015 return result; |
1596 } | 1016 } |
1597 | 1017 |
1598 return this; | 1018 return this; |
1599 } | 1019 } |
1600 | 1020 |
1601 | 1021 |
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 | |
1692 // Optimizations that eliminate or simplify individual instructions. | 1022 // Optimizations that eliminate or simplify individual instructions. |
1693 Instruction* Instruction::Canonicalize(FlowGraphOptimizer* optimizer) { | 1023 Instruction* Instruction::Canonicalize(FlowGraphOptimizer* optimizer) { |
1694 return this; | 1024 return this; |
1695 } | 1025 } |
1696 | 1026 |
1697 | 1027 |
1698 Definition* Definition::Canonicalize(FlowGraphOptimizer* optimizer) { | 1028 Definition* Definition::Canonicalize(FlowGraphOptimizer* optimizer) { |
1699 return this; | 1029 return this; |
1700 } | 1030 } |
1701 | 1031 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1745 | 1075 |
1746 Definition* LoadFieldInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1076 Definition* LoadFieldInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
1747 if (!IsImmutableLengthLoad()) return this; | 1077 if (!IsImmutableLengthLoad()) return this; |
1748 | 1078 |
1749 // For fixed length arrays if the array is the result of a known constructor | 1079 // For fixed length arrays if the array is the result of a known constructor |
1750 // call we can replace the length load with the length argument passed to | 1080 // call we can replace the length load with the length argument passed to |
1751 // the constructor. | 1081 // the constructor. |
1752 StaticCallInstr* call = value()->definition()->AsStaticCall(); | 1082 StaticCallInstr* call = value()->definition()->AsStaticCall(); |
1753 if (call != NULL && | 1083 if (call != NULL && |
1754 call->is_known_constructor() && | 1084 call->is_known_constructor() && |
1755 call->ResultCid() == kArrayCid) { | 1085 (call->Type()->ToCid() == kArrayCid)) { |
1756 return call->ArgumentAt(1)->value()->definition(); | 1086 return call->ArgumentAt(1)->value()->definition(); |
1757 } | 1087 } |
1758 return this; | 1088 return this; |
1759 } | 1089 } |
1760 | 1090 |
1761 | 1091 |
1762 Definition* AssertBooleanInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1092 Definition* AssertBooleanInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
1763 const intptr_t value_cid = value()->ResultCid(); | 1093 if (FLAG_eliminate_type_checks && (value()->Type()->ToCid() == kBoolCid)) { |
1764 return (value_cid == kBoolCid) ? value()->definition() : this; | 1094 return value()->definition(); |
| 1095 } |
| 1096 |
| 1097 return this; |
1765 } | 1098 } |
1766 | 1099 |
1767 | 1100 |
1768 Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1101 Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
1769 // (1) Replace the assert with its input if the input has a known compatible | 1102 if (FLAG_eliminate_type_checks && |
1770 // class-id. The class-ids handled here are those that are known to be | 1103 value()->Type()->IsAssignableTo(dst_type())) { |
1771 // results of IL instructions. | 1104 return value()->definition(); |
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; | |
1790 } | 1105 } |
1791 | 1106 |
1792 // (3) For uninstantiated target types: If the instantiator type arguments | 1107 // (3) For uninstantiated target types: If the instantiator type arguments |
1793 // are constant, instantiate the target type here. | 1108 // are constant, instantiate the target type here. |
1794 if (dst_type().IsInstantiated()) return this; | 1109 if (dst_type().IsInstantiated()) return this; |
1795 | 1110 |
1796 ConstantInstr* constant_type_args = | 1111 ConstantInstr* constant_type_args = |
1797 instantiator_type_arguments()->definition()->AsConstant(); | 1112 instantiator_type_arguments()->definition()->AsConstant(); |
1798 if (constant_type_args != NULL && | 1113 if (constant_type_args != NULL && |
1799 !constant_type_args->value().IsNull() && | 1114 !constant_type_args->value().IsNull() && |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1861 | 1176 |
1862 | 1177 |
1863 Definition* StrictCompareInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1178 Definition* StrictCompareInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
1864 if (!right()->BindsToConstant()) return this; | 1179 if (!right()->BindsToConstant()) return this; |
1865 const Object& right_constant = right()->BoundConstant(); | 1180 const Object& right_constant = right()->BoundConstant(); |
1866 Definition* left_defn = left()->definition(); | 1181 Definition* left_defn = left()->definition(); |
1867 // TODO(fschneider): Handle other cases: e === false and e !== true/false. | 1182 // TODO(fschneider): Handle other cases: e === false and e !== true/false. |
1868 // Handles e === true. | 1183 // Handles e === true. |
1869 if ((kind() == Token::kEQ_STRICT) && | 1184 if ((kind() == Token::kEQ_STRICT) && |
1870 (right_constant.raw() == Bool::True().raw()) && | 1185 (right_constant.raw() == Bool::True().raw()) && |
1871 (left()->ResultCid() == kBoolCid)) { | 1186 (left()->Type()->ToCid() == kBoolCid)) { |
1872 // Return left subexpression as the replacement for this instruction. | 1187 // Return left subexpression as the replacement for this instruction. |
1873 return left_defn; | 1188 return left_defn; |
1874 } | 1189 } |
1875 return this; | 1190 return this; |
1876 } | 1191 } |
1877 | 1192 |
1878 | 1193 |
1879 Instruction* CheckClassInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1194 Instruction* CheckClassInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
1880 const intptr_t value_cid = value()->ResultCid(); | 1195 // TODO(vegorov): Replace class checks with null checks when ToNullableCid |
| 1196 // matches. |
| 1197 |
| 1198 const intptr_t value_cid = value()->Type()->ToCid(); |
1881 if (value_cid == kDynamicCid) { | 1199 if (value_cid == kDynamicCid) { |
1882 return this; | 1200 return this; |
1883 } | 1201 } |
1884 | 1202 |
1885 const intptr_t num_checks = unary_checks().NumberOfChecks(); | 1203 const intptr_t num_checks = unary_checks().NumberOfChecks(); |
1886 | 1204 |
1887 for (intptr_t i = 0; i < num_checks; i++) { | 1205 for (intptr_t i = 0; i < num_checks; i++) { |
1888 if (value_cid == unary_checks().GetReceiverClassIdAt(i)) { | 1206 if (value_cid == unary_checks().GetReceiverClassIdAt(i)) { |
1889 // No checks needed. | 1207 // No checks needed. |
1890 return NULL; | 1208 return NULL; |
1891 } | 1209 } |
1892 } | 1210 } |
1893 | 1211 |
1894 return this; | 1212 return this; |
1895 } | 1213 } |
1896 | 1214 |
1897 | 1215 |
1898 Instruction* CheckSmiInstr::Canonicalize(FlowGraphOptimizer* optimizer) { | 1216 Instruction* CheckSmiInstr::Canonicalize(FlowGraphOptimizer* optimizer) { |
1899 return (value()->ResultCid() == kSmiCid) ? NULL : this; | 1217 return (value()->Type()->ToCid() == kSmiCid) ? NULL : this; |
1900 } | 1218 } |
1901 | 1219 |
1902 | 1220 |
1903 Instruction* CheckEitherNonSmiInstr::Canonicalize( | 1221 Instruction* CheckEitherNonSmiInstr::Canonicalize( |
1904 FlowGraphOptimizer* optimizer) { | 1222 FlowGraphOptimizer* optimizer) { |
1905 if ((left()->ResultCid() == kDoubleCid) || | 1223 if ((left()->Type()->ToCid() == kDoubleCid) || |
1906 (right()->ResultCid() == kDoubleCid)) { | 1224 (right()->Type()->ToCid() == kDoubleCid)) { |
1907 return NULL; // Remove from the graph. | 1225 return NULL; // Remove from the graph. |
1908 } | 1226 } |
1909 return this; | 1227 return this; |
1910 } | 1228 } |
1911 | 1229 |
1912 | 1230 |
1913 // Shared code generation methods (EmitNativeCode, MakeLocationSummary, and | 1231 // Shared code generation methods (EmitNativeCode, MakeLocationSummary, and |
1914 // PrepareEntry). Only assembly code that can be shared across all architectures | 1232 // PrepareEntry). Only assembly code that can be shared across all architectures |
1915 // can be used. Machine specific register allocation and code generation | 1233 // can be used. Machine specific register allocation and code generation |
1916 // is located in intermediate_language_<arch>.cc | 1234 // is located in intermediate_language_<arch>.cc |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2115 token_pos(), | 1433 token_pos(), |
2116 function(), | 1434 function(), |
2117 ArgumentCount(), | 1435 ArgumentCount(), |
2118 argument_names(), | 1436 argument_names(), |
2119 locs()); | 1437 locs()); |
2120 __ Bind(&skip_call); | 1438 __ Bind(&skip_call); |
2121 } | 1439 } |
2122 | 1440 |
2123 | 1441 |
2124 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1442 void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
2125 if (!is_eliminated()) { | 1443 compiler->GenerateAssertAssignable(token_pos(), |
2126 compiler->GenerateAssertAssignable(token_pos(), | 1444 deopt_id(), |
2127 deopt_id(), | 1445 dst_type(), |
2128 dst_type(), | 1446 dst_name(), |
2129 dst_name(), | 1447 locs()); |
2130 locs()); | |
2131 } | |
2132 ASSERT(locs()->in(0).reg() == locs()->out().reg()); | 1448 ASSERT(locs()->in(0).reg() == locs()->out().reg()); |
2133 } | 1449 } |
2134 | 1450 |
2135 | 1451 |
2136 Environment* Environment::From(const GrowableArray<Definition*>& definitions, | 1452 Environment* Environment::From(const GrowableArray<Definition*>& definitions, |
2137 intptr_t fixed_parameter_count, | 1453 intptr_t fixed_parameter_count, |
2138 const Function& function) { | 1454 const Function& function) { |
2139 Environment* env = | 1455 Environment* env = |
2140 new Environment(definitions.length(), | 1456 new Environment(definitions.length(), |
2141 fixed_parameter_count, | 1457 fixed_parameter_count, |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2393 } | 1709 } |
2394 | 1710 |
2395 const intptr_t max_a = a.UpperBound().Clamp().value(); | 1711 const intptr_t max_a = a.UpperBound().Clamp().value(); |
2396 const intptr_t max_b = b.UpperBound().Clamp().value(); | 1712 const intptr_t max_b = b.UpperBound().Clamp().value(); |
2397 | 1713 |
2398 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); | 1714 return RangeBoundary::FromConstant(Utils::Maximum(max_a, max_b)); |
2399 } | 1715 } |
2400 | 1716 |
2401 | 1717 |
2402 void Definition::InferRange() { | 1718 void Definition::InferRange() { |
2403 ASSERT(GetPropagatedCid() == kSmiCid); // Has meaning only for smis. | 1719 ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis. |
2404 if (range_ == NULL) { | 1720 if (range_ == NULL) { |
2405 range_ = Range::Unknown(); | 1721 range_ = Range::Unknown(); |
2406 } | 1722 } |
2407 } | 1723 } |
2408 | 1724 |
2409 | 1725 |
2410 void ConstantInstr::InferRange() { | 1726 void ConstantInstr::InferRange() { |
2411 ASSERT(value_.IsSmi()); | 1727 ASSERT(value_.IsSmi()); |
2412 if (range_ == NULL) { | 1728 if (range_ == NULL) { |
2413 intptr_t value = Smi::Cast(value_).Value(); | 1729 intptr_t value = Smi::Cast(value_).Value(); |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2877 default: | 2193 default: |
2878 UNREACHABLE(); | 2194 UNREACHABLE(); |
2879 } | 2195 } |
2880 return kPowRuntimeEntry; | 2196 return kPowRuntimeEntry; |
2881 } | 2197 } |
2882 | 2198 |
2883 | 2199 |
2884 #undef __ | 2200 #undef __ |
2885 | 2201 |
2886 } // namespace dart | 2202 } // namespace dart |
OLD | NEW |