Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(439)

Side by Side Diff: runtime/vm/intermediate_language.cc

Issue 12221139: Revert "Remove SminessPropagator and FlowGraphTypePropagator and all associated infrastructure and … (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/intermediate_language.h ('k') | runtime/vm/intermediate_language_arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
397 ForwardInstructionIterator it(entry); 400 ForwardInstructionIterator it(entry);
398 current_iterator_ = &it; 401 current_iterator_ = &it;
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language.h ('k') | runtime/vm/intermediate_language_arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698