| 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/flow_graph_optimizer.h" | 5 #include "vm/flow_graph_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/cha.h" | 8 #include "vm/cha.h" |
| 9 #include "vm/dart_entry.h" | 9 #include "vm/dart_entry.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 (ic_data.GetReceiverClassIdAt(0) == cid)) { | 153 (ic_data.GetReceiverClassIdAt(0) == cid)) { |
| 154 return ic_data; // Nothing to do | 154 return ic_data; // Nothing to do |
| 155 } | 155 } |
| 156 | 156 |
| 157 const ICData& new_ic_data = ICData::ZoneHandle(ICData::New( | 157 const ICData& new_ic_data = ICData::ZoneHandle(ICData::New( |
| 158 Function::Handle(ic_data.function()), | 158 Function::Handle(ic_data.function()), |
| 159 String::Handle(ic_data.target_name()), | 159 String::Handle(ic_data.target_name()), |
| 160 Object::empty_array(), // Dummy argument descriptor. | 160 Object::empty_array(), // Dummy argument descriptor. |
| 161 ic_data.deopt_id(), | 161 ic_data.deopt_id(), |
| 162 ic_data.num_args_tested())); | 162 ic_data.num_args_tested())); |
| 163 new_ic_data.set_deopt_reason(ic_data.deopt_reason()); |
| 163 | 164 |
| 164 const Function& function = | 165 const Function& function = |
| 165 Function::Handle(ic_data.GetTargetForReceiverClassId(cid)); | 166 Function::Handle(ic_data.GetTargetForReceiverClassId(cid)); |
| 166 if (!function.IsNull()) { | 167 if (!function.IsNull()) { |
| 167 new_ic_data.AddReceiverCheck(cid, function); | 168 new_ic_data.AddReceiverCheck(cid, function); |
| 168 } | 169 } |
| 169 | 170 |
| 170 return new_ic_data; | 171 return new_ic_data; |
| 171 } | 172 } |
| 172 | 173 |
| (...skipping 609 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 length->set_recognized_kind( | 783 length->set_recognized_kind( |
| 783 LoadFieldInstr::RecognizedKindFromArrayCid(class_id)); | 784 LoadFieldInstr::RecognizedKindFromArrayCid(class_id)); |
| 784 InsertBefore(call, length, NULL, Definition::kValue); | 785 InsertBefore(call, length, NULL, Definition::kValue); |
| 785 InsertBefore(call, | 786 InsertBefore(call, |
| 786 new CheckArrayBoundInstr(new Value(length), | 787 new CheckArrayBoundInstr(new Value(length), |
| 787 new Value(*index), | 788 new Value(*index), |
| 788 call->deopt_id()), | 789 call->deopt_id()), |
| 789 call->env(), | 790 call->env(), |
| 790 Definition::kEffect); | 791 Definition::kEffect); |
| 791 | 792 |
| 792 | |
| 793 if (class_id == kGrowableObjectArrayCid) { | 793 if (class_id == kGrowableObjectArrayCid) { |
| 794 // Insert data elements load. | 794 // Insert data elements load. |
| 795 LoadFieldInstr* elements = | 795 LoadFieldInstr* elements = |
| 796 new LoadFieldInstr(new Value(*array), | 796 new LoadFieldInstr(new Value(*array), |
| 797 GrowableObjectArray::data_offset(), | 797 GrowableObjectArray::data_offset(), |
| 798 Type::ZoneHandle(Type::DynamicType())); | 798 Type::ZoneHandle(Type::DynamicType())); |
| 799 elements->set_result_cid(kArrayCid); | 799 elements->set_result_cid(kArrayCid); |
| 800 InsertBefore(call, elements, NULL, Definition::kValue); | 800 InsertBefore(call, elements, NULL, Definition::kValue); |
| 801 *array = elements; | 801 *array = elements; |
| 802 return kArrayCid; | 802 return kArrayCid; |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 989 new Value(index), | 989 new Value(index), |
| 990 new Value(stored_value), | 990 new Value(stored_value), |
| 991 needs_store_barrier, | 991 needs_store_barrier, |
| 992 index_scale, | 992 index_scale, |
| 993 array_cid, | 993 array_cid, |
| 994 call->deopt_id()); | 994 call->deopt_id()); |
| 995 ReplaceCall(call, array_op); | 995 ReplaceCall(call, array_op); |
| 996 } | 996 } |
| 997 | 997 |
| 998 | 998 |
| 999 static intptr_t MethodKindToCid(MethodRecognizer::Kind kind) { |
| 1000 switch (kind) { |
| 1001 case MethodRecognizer::kImmutableArrayGetIndexed: |
| 1002 return kImmutableArrayCid; |
| 1003 |
| 1004 case MethodRecognizer::kObjectArrayGetIndexed: |
| 1005 return kArrayCid; |
| 1006 |
| 1007 case MethodRecognizer::kGrowableArrayGetIndexed: |
| 1008 return kGrowableObjectArrayCid; |
| 1009 |
| 1010 case MethodRecognizer::kFloat32ArrayGetIndexed: |
| 1011 return kTypedDataFloat32ArrayCid; |
| 1012 |
| 1013 case MethodRecognizer::kFloat64ArrayGetIndexed: |
| 1014 return kTypedDataFloat64ArrayCid; |
| 1015 |
| 1016 case MethodRecognizer::kInt8ArrayGetIndexed: |
| 1017 return kTypedDataInt8ArrayCid; |
| 1018 |
| 1019 case MethodRecognizer::kUint8ArrayGetIndexed: |
| 1020 return kTypedDataUint8ArrayCid; |
| 1021 |
| 1022 case MethodRecognizer::kUint8ClampedArrayGetIndexed: |
| 1023 return kTypedDataUint8ClampedArrayCid; |
| 1024 |
| 1025 case MethodRecognizer::kExternalUint8ArrayGetIndexed: |
| 1026 return kExternalTypedDataUint8ArrayCid; |
| 1027 |
| 1028 case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed: |
| 1029 return kExternalTypedDataUint8ClampedArrayCid; |
| 1030 |
| 1031 case MethodRecognizer::kInt16ArrayGetIndexed: |
| 1032 return kTypedDataInt16ArrayCid; |
| 1033 |
| 1034 case MethodRecognizer::kUint16ArrayGetIndexed: |
| 1035 return kTypedDataUint16ArrayCid; |
| 1036 |
| 1037 case MethodRecognizer::kInt32ArrayGetIndexed: |
| 1038 return kTypedDataInt32ArrayCid; |
| 1039 |
| 1040 case MethodRecognizer::kUint32ArrayGetIndexed: |
| 1041 return kTypedDataUint32ArrayCid; |
| 1042 |
| 1043 case MethodRecognizer::kFloat32x4ArrayGetIndexed: |
| 1044 return kTypedDataFloat32x4ArrayCid; |
| 1045 |
| 1046 default: |
| 1047 break; |
| 1048 } |
| 1049 return kIllegalCid; |
| 1050 } |
| 1051 |
| 1052 |
| 1053 bool FlowGraphOptimizer::TryInlineRecognizedMethod(const Function& target, |
| 1054 Instruction* call, |
| 1055 const ICData& ic_data, |
| 1056 TargetEntryInstr** entry, |
| 1057 Definition** last) { |
| 1058 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); |
| 1059 switch (kind) { |
| 1060 case MethodRecognizer::kImmutableArrayGetIndexed: |
| 1061 case MethodRecognizer::kObjectArrayGetIndexed: |
| 1062 case MethodRecognizer::kGrowableArrayGetIndexed: |
| 1063 case MethodRecognizer::kFloat32ArrayGetIndexed: |
| 1064 case MethodRecognizer::kFloat64ArrayGetIndexed: |
| 1065 case MethodRecognizer::kInt8ArrayGetIndexed: |
| 1066 case MethodRecognizer::kUint8ArrayGetIndexed: |
| 1067 case MethodRecognizer::kUint8ClampedArrayGetIndexed: |
| 1068 case MethodRecognizer::kExternalUint8ArrayGetIndexed: |
| 1069 case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed: |
| 1070 case MethodRecognizer::kInt16ArrayGetIndexed: |
| 1071 case MethodRecognizer::kUint16ArrayGetIndexed: |
| 1072 case MethodRecognizer::kInt32ArrayGetIndexed: |
| 1073 case MethodRecognizer::kUint32ArrayGetIndexed: |
| 1074 case MethodRecognizer::kFloat32x4ArrayGetIndexed: |
| 1075 return TryInlineGetIndexed(kind, call, ic_data, entry, last); |
| 1076 default: |
| 1077 return false; |
| 1078 } |
| 1079 } |
| 1080 |
| 1081 |
| 1082 bool FlowGraphOptimizer::TryInlineGetIndexed(MethodRecognizer::Kind kind, |
| 1083 Instruction* call, |
| 1084 const ICData& ic_data, |
| 1085 TargetEntryInstr** entry, |
| 1086 Definition** last) { |
| 1087 intptr_t array_cid = MethodKindToCid(kind); |
| 1088 ASSERT(array_cid != kIllegalCid); |
| 1089 |
| 1090 // Insert index smi checks and attach a copy of the |
| 1091 // original environment because the operation can still deoptimize. |
| 1092 Definition* array = call->ArgumentAt(0); |
| 1093 Definition* index = call->ArgumentAt(1); |
| 1094 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(), |
| 1095 call->GetBlock()->try_index()); |
| 1096 (*entry)->InheritDeoptTarget(call); |
| 1097 |
| 1098 Instruction* cursor = *entry; |
| 1099 cursor = flow_graph()->AppendTo(cursor, |
| 1100 new CheckSmiInstr(new Value(index), |
| 1101 call->deopt_id()), |
| 1102 call->env(), |
| 1103 Definition::kEffect); |
| 1104 |
| 1105 // Insert array length load and bounds check. |
| 1106 const bool is_immutable = |
| 1107 CheckArrayBoundInstr::IsFixedLengthArrayType(array_cid); |
| 1108 LoadFieldInstr* length = |
| 1109 new LoadFieldInstr(new Value(array), |
| 1110 CheckArrayBoundInstr::LengthOffsetFor(array_cid), |
| 1111 Type::ZoneHandle(Type::SmiType()), |
| 1112 is_immutable); |
| 1113 length->set_result_cid(kSmiCid); |
| 1114 length->set_recognized_kind( |
| 1115 LoadFieldInstr::RecognizedKindFromArrayCid(array_cid)); |
| 1116 cursor = flow_graph()->AppendTo(cursor, |
| 1117 length, |
| 1118 NULL, |
| 1119 Definition::kValue); |
| 1120 |
| 1121 cursor = flow_graph()->AppendTo(cursor, |
| 1122 new CheckArrayBoundInstr( |
| 1123 new Value(length), |
| 1124 new Value(index), |
| 1125 call->deopt_id()), |
| 1126 call->env(), |
| 1127 Definition::kEffect); |
| 1128 |
| 1129 if (array_cid == kGrowableObjectArrayCid) { |
| 1130 // Insert data elements load. |
| 1131 LoadFieldInstr* elements = |
| 1132 new LoadFieldInstr(new Value(array), |
| 1133 GrowableObjectArray::data_offset(), |
| 1134 Type::ZoneHandle(Type::DynamicType())); |
| 1135 elements->set_result_cid(kArrayCid); |
| 1136 cursor = flow_graph()->AppendTo(cursor, |
| 1137 elements, |
| 1138 NULL, |
| 1139 Definition::kValue); |
| 1140 // Load from the data from backing store which is a fixed-length array. |
| 1141 array = elements; |
| 1142 array_cid = kArrayCid; |
| 1143 } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| 1144 LoadUntaggedInstr* elements = |
| 1145 new LoadUntaggedInstr(new Value(array), |
| 1146 ExternalTypedData::data_offset()); |
| 1147 cursor = flow_graph()->AppendTo(cursor, |
| 1148 elements, |
| 1149 NULL, |
| 1150 Definition::kValue); |
| 1151 array = elements; |
| 1152 } |
| 1153 |
| 1154 intptr_t deopt_id = Isolate::kNoDeoptId; |
| 1155 if ((array_cid == kTypedDataInt32ArrayCid) || |
| 1156 (array_cid == kTypedDataUint32ArrayCid)) { |
| 1157 // Set deopt_id if we can optimistically assume that the result is Smi. |
| 1158 // Assume mixed Mint/Smi if this instruction caused deoptimization once. |
| 1159 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? |
| 1160 call->deopt_id() : Isolate::kNoDeoptId; |
| 1161 } |
| 1162 |
| 1163 // Array load and return. |
| 1164 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); |
| 1165 *last = new LoadIndexedInstr(new Value(array), |
| 1166 new Value(index), |
| 1167 index_scale, |
| 1168 array_cid, |
| 1169 deopt_id); |
| 1170 flow_graph()->AppendTo(cursor, |
| 1171 *last, |
| 1172 deopt_id != Isolate::kNoDeoptId ? call->env() : NULL, |
| 1173 Definition::kValue); |
| 1174 return true; |
| 1175 } |
| 1176 |
| 999 | 1177 |
| 1000 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { | 1178 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { |
| 1001 const intptr_t class_id = ReceiverClassId(call); | 1179 const intptr_t class_id = ReceiverClassId(call); |
| 1002 // Set deopt_id to a valid id if the LoadIndexedInstr can cause deopt. | |
| 1003 intptr_t deopt_id = Isolate::kNoDeoptId; | |
| 1004 switch (class_id) { | 1180 switch (class_id) { |
| 1005 case kArrayCid: | 1181 case kArrayCid: |
| 1006 case kImmutableArrayCid: | 1182 case kImmutableArrayCid: |
| 1007 case kGrowableObjectArrayCid: | 1183 case kGrowableObjectArrayCid: |
| 1008 case kTypedDataFloat32ArrayCid: | 1184 case kTypedDataFloat32ArrayCid: |
| 1009 case kTypedDataFloat64ArrayCid: | 1185 case kTypedDataFloat64ArrayCid: |
| 1010 case kTypedDataInt8ArrayCid: | 1186 case kTypedDataInt8ArrayCid: |
| 1011 case kTypedDataUint8ArrayCid: | 1187 case kTypedDataUint8ArrayCid: |
| 1012 case kTypedDataUint8ClampedArrayCid: | 1188 case kTypedDataUint8ClampedArrayCid: |
| 1013 case kExternalTypedDataUint8ArrayCid: | 1189 case kExternalTypedDataUint8ArrayCid: |
| 1014 case kExternalTypedDataUint8ClampedArrayCid: | 1190 case kExternalTypedDataUint8ClampedArrayCid: |
| 1015 case kTypedDataInt16ArrayCid: | 1191 case kTypedDataInt16ArrayCid: |
| 1016 case kTypedDataUint16ArrayCid: | 1192 case kTypedDataUint16ArrayCid: |
| 1017 break; | 1193 break; |
| 1018 case kTypedDataFloat32x4ArrayCid: | 1194 case kTypedDataFloat32x4ArrayCid: |
| 1019 if (!ShouldInlineSimd()) { | 1195 if (!ShouldInlineSimd()) { |
| 1020 return false; | 1196 return false; |
| 1021 } | 1197 } |
| 1022 break; | 1198 break; |
| 1023 case kTypedDataInt32ArrayCid: | 1199 case kTypedDataInt32ArrayCid: |
| 1024 case kTypedDataUint32ArrayCid: { | 1200 case kTypedDataUint32ArrayCid: |
| 1025 if (!CanUnboxInt32()) return false; | 1201 if (!CanUnboxInt32()) return false; |
| 1026 | |
| 1027 // Set deopt_id if we can optimistically assume that the result is Smi. | |
| 1028 // Assume mixed Mint/Smi if this instruction caused deoptimization once. | |
| 1029 ASSERT(call->HasICData()); | |
| 1030 const ICData& ic_data = *call->ic_data(); | |
| 1031 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? | |
| 1032 call->deopt_id() : Isolate::kNoDeoptId; | |
| 1033 } | |
| 1034 break; | 1202 break; |
| 1035 default: | 1203 default: |
| 1036 return false; | 1204 return false; |
| 1037 } | 1205 } |
| 1038 Definition* array = call->ArgumentAt(0); | 1206 |
| 1039 Definition* index = call->ArgumentAt(1); | 1207 const Function& target = |
| 1040 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); | 1208 Function::Handle(call->ic_data()->GetTargetAt(0)); |
| 1041 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); | 1209 TargetEntryInstr* entry; |
| 1042 Definition* array_op = | 1210 Definition* last; |
| 1043 new LoadIndexedInstr(new Value(array), | 1211 ASSERT(class_id == MethodKindToCid(MethodRecognizer::RecognizeKind(target))); |
| 1044 new Value(index), | 1212 bool success = TryInlineRecognizedMethod(target, |
| 1045 index_scale, | 1213 call, |
| 1046 array_cid, | 1214 *call->ic_data(), |
| 1047 deopt_id); | 1215 &entry, &last); |
| 1048 ReplaceCall(call, array_op); | 1216 ASSERT(success); |
| 1217 // Insert receiver class check. |
| 1218 AddReceiverCheck(call); |
| 1219 // Remove the original push arguments. |
| 1220 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 1221 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 1222 push->ReplaceUsesWith(push->value()->definition()); |
| 1223 push->RemoveFromGraph(); |
| 1224 } |
| 1225 // Replace all uses of this definition with the result. |
| 1226 call->ReplaceUsesWith(last); |
| 1227 // Finally insert the sequence other definition in place of this one in the |
| 1228 // graph. |
| 1229 call->previous()->LinkTo(entry->next()); |
| 1230 entry->UnuseAllInputs(); // Entry block is not in the graph. |
| 1231 last->LinkTo(call); |
| 1232 // Remove through the iterator. |
| 1233 ASSERT(current_iterator()->Current() == call); |
| 1234 current_iterator()->RemoveCurrentFromGraph(); |
| 1235 call->set_previous(NULL); |
| 1236 call->set_next(NULL); |
| 1049 return true; | 1237 return true; |
| 1050 } | 1238 } |
| 1051 | 1239 |
| 1052 | 1240 |
| 1053 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 1241 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
| 1054 | 1242 |
| 1055 | 1243 |
| 1056 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 1244 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
| 1057 Token::Kind op_kind) { | 1245 Token::Kind op_kind) { |
| 1058 const ICData& ic_data = *call->ic_data(); | 1246 const ICData& ic_data = *call->ic_data(); |
| (...skipping 6424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7483 } | 7671 } |
| 7484 | 7672 |
| 7485 // Insert materializations at environment uses. | 7673 // Insert materializations at environment uses. |
| 7486 for (intptr_t i = 0; i < exits.length(); i++) { | 7674 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7487 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 7675 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 7488 } | 7676 } |
| 7489 } | 7677 } |
| 7490 | 7678 |
| 7491 | 7679 |
| 7492 } // namespace dart | 7680 } // namespace dart |
| OLD | NEW |