Chromium Code Reviews| 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 // Explicit instantiation because this variant used in flow_graph_inliner.cc. | |
| 1054 template bool FlowGraphOptimizer:: | |
| 1055 TryInlineRecognizedMethod<PolymorphicInstanceCallInstr*>( | |
| 1056 const Function&, | |
| 1057 PolymorphicInstanceCallInstr*, | |
| 1058 const ICData&, | |
| 1059 TargetEntryInstr**, | |
| 1060 Definition**); | |
| 1061 | |
| 1062 | |
| 1063 template <typename T> | |
| 1064 bool FlowGraphOptimizer::TryInlineRecognizedMethod(const Function& target, | |
| 1065 T call, | |
| 1066 const ICData& ic_data, | |
| 1067 TargetEntryInstr** entry, | |
| 1068 Definition** last) { | |
| 1069 // TODO(fschneider): Extend to other recognized methods. | |
|
Cutch
2013/09/17 16:08:47
The below code is specific to preparing an indexed
Florian Schneider
2013/09/18 14:00:36
Yes, I'd have to do that for the next CL anyway.
| |
| 1070 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); | |
| 1071 intptr_t array_cid = MethodKindToCid(kind); | |
| 1072 if (array_cid == kIllegalCid) return false; | |
| 1073 | |
| 1074 // Insert index smi checks and attach a copy of the | |
| 1075 // original environment because the operation can still deoptimize. | |
| 1076 Definition* array = call->ArgumentAt(0); | |
| 1077 Definition* index = call->ArgumentAt(1); | |
| 1078 *entry = new TargetEntryInstr(flow_graph()->allocate_block_id(), | |
| 1079 call->GetBlock()->try_index()); | |
| 1080 (*entry)->InheritDeoptTarget(call); | |
| 1081 | |
| 1082 Instruction* cursor = *entry; | |
| 1083 cursor = flow_graph()->AppendTo(cursor, | |
| 1084 new CheckSmiInstr(new Value(index), | |
| 1085 call->deopt_id()), | |
| 1086 call->env(), | |
| 1087 Definition::kEffect); | |
| 1088 | |
| 1089 // Insert array length load and bounds check. | |
| 1090 const bool is_immutable = | |
| 1091 CheckArrayBoundInstr::IsFixedLengthArrayType(array_cid); | |
| 1092 LoadFieldInstr* length = | |
| 1093 new LoadFieldInstr(new Value(array), | |
| 1094 CheckArrayBoundInstr::LengthOffsetFor(array_cid), | |
| 1095 Type::ZoneHandle(Type::SmiType()), | |
| 1096 is_immutable); | |
| 1097 length->set_result_cid(kSmiCid); | |
| 1098 length->set_recognized_kind( | |
| 1099 LoadFieldInstr::RecognizedKindFromArrayCid(array_cid)); | |
| 1100 cursor = flow_graph()->AppendTo(cursor, | |
| 1101 length, | |
| 1102 NULL, | |
| 1103 Definition::kValue); | |
| 1104 | |
| 1105 cursor = flow_graph()->AppendTo(cursor, | |
| 1106 new CheckArrayBoundInstr( | |
| 1107 new Value(length), | |
| 1108 new Value(index), | |
| 1109 call->deopt_id()), | |
| 1110 call->env(), | |
| 1111 Definition::kEffect); | |
| 1112 | |
| 1113 if (array_cid == kGrowableObjectArrayCid) { | |
| 1114 // Insert data elements load. | |
| 1115 LoadFieldInstr* elements = | |
| 1116 new LoadFieldInstr(new Value(array), | |
| 1117 GrowableObjectArray::data_offset(), | |
| 1118 Type::ZoneHandle(Type::DynamicType())); | |
| 1119 elements->set_result_cid(kArrayCid); | |
| 1120 cursor = flow_graph()->AppendTo(cursor, | |
| 1121 elements, | |
| 1122 NULL, | |
| 1123 Definition::kValue); | |
| 1124 // Load from the data from backing store which is a fixed-length array. | |
| 1125 array = elements; | |
| 1126 array_cid = kArrayCid; | |
| 1127 } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { | |
| 1128 LoadUntaggedInstr* elements = | |
| 1129 new LoadUntaggedInstr(new Value(array), | |
| 1130 ExternalTypedData::data_offset()); | |
| 1131 cursor = flow_graph()->AppendTo(cursor, | |
| 1132 elements, | |
| 1133 NULL, | |
| 1134 Definition::kValue); | |
| 1135 array = elements; | |
| 1136 } | |
| 1137 | |
| 1138 intptr_t deopt_id = Isolate::kNoDeoptId; | |
| 1139 if ((array_cid == kTypedDataInt32ArrayCid) || | |
| 1140 (array_cid == kTypedDataUint32ArrayCid)) { | |
| 1141 // Set deopt_id if we can optimistically assume that the result is Smi. | |
| 1142 // Assume mixed Mint/Smi if this instruction caused deoptimization once. | |
|
Cutch
2013/09/17 16:08:47
Shouldn't this include kTypedDataInt64ArrayCid and
| |
| 1143 deopt_id = (ic_data.deopt_reason() == kDeoptUnknown) ? | |
| 1144 call->deopt_id() : Isolate::kNoDeoptId; | |
| 1145 } | |
| 1146 | |
| 1147 // Array load and return. | |
| 1148 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); | |
| 1149 *last = new LoadIndexedInstr(new Value(array), | |
| 1150 new Value(index), | |
| 1151 index_scale, | |
| 1152 array_cid, | |
| 1153 deopt_id); | |
| 1154 flow_graph()->AppendTo(cursor, | |
| 1155 *last, | |
| 1156 deopt_id != Isolate::kNoDeoptId ? call->env() : NULL, | |
| 1157 Definition::kValue); | |
| 1158 return true; | |
| 1159 } | |
| 1160 | |
| 999 | 1161 |
| 1000 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { | 1162 bool FlowGraphOptimizer::TryReplaceWithLoadIndexed(InstanceCallInstr* call) { |
| 1001 const intptr_t class_id = ReceiverClassId(call); | 1163 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) { | 1164 switch (class_id) { |
| 1005 case kArrayCid: | 1165 case kArrayCid: |
| 1006 case kImmutableArrayCid: | 1166 case kImmutableArrayCid: |
| 1007 case kGrowableObjectArrayCid: | 1167 case kGrowableObjectArrayCid: |
| 1008 case kTypedDataFloat32ArrayCid: | 1168 case kTypedDataFloat32ArrayCid: |
| 1009 case kTypedDataFloat64ArrayCid: | 1169 case kTypedDataFloat64ArrayCid: |
| 1010 case kTypedDataInt8ArrayCid: | 1170 case kTypedDataInt8ArrayCid: |
| 1011 case kTypedDataUint8ArrayCid: | 1171 case kTypedDataUint8ArrayCid: |
| 1012 case kTypedDataUint8ClampedArrayCid: | 1172 case kTypedDataUint8ClampedArrayCid: |
| 1013 case kExternalTypedDataUint8ArrayCid: | 1173 case kExternalTypedDataUint8ArrayCid: |
| 1014 case kExternalTypedDataUint8ClampedArrayCid: | 1174 case kExternalTypedDataUint8ClampedArrayCid: |
| 1015 case kTypedDataInt16ArrayCid: | 1175 case kTypedDataInt16ArrayCid: |
| 1016 case kTypedDataUint16ArrayCid: | 1176 case kTypedDataUint16ArrayCid: |
| 1017 break; | 1177 break; |
| 1018 case kTypedDataFloat32x4ArrayCid: | 1178 case kTypedDataFloat32x4ArrayCid: |
| 1019 if (!ShouldInlineSimd()) { | 1179 if (!ShouldInlineSimd()) { |
| 1020 return false; | 1180 return false; |
| 1021 } | 1181 } |
| 1022 break; | 1182 break; |
| 1023 case kTypedDataInt32ArrayCid: | 1183 case kTypedDataInt32ArrayCid: |
| 1024 case kTypedDataUint32ArrayCid: { | 1184 case kTypedDataUint32ArrayCid: |
|
Cutch
2013/09/17 16:08:47
Ahh, I see we never supported unboxed loads from 6
| |
| 1025 if (!CanUnboxInt32()) return false; | 1185 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; | 1186 break; |
| 1035 default: | 1187 default: |
| 1036 return false; | 1188 return false; |
| 1037 } | 1189 } |
| 1038 Definition* array = call->ArgumentAt(0); | 1190 |
| 1039 Definition* index = call->ArgumentAt(1); | 1191 const Function& target = |
| 1040 intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index); | 1192 Function::Handle(call->ic_data()->GetTargetAt(0)); |
| 1041 intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(array_cid); | 1193 TargetEntryInstr* entry; |
| 1042 Definition* array_op = | 1194 Definition* last; |
| 1043 new LoadIndexedInstr(new Value(array), | 1195 ASSERT(class_id == MethodKindToCid(MethodRecognizer::RecognizeKind(target))); |
| 1044 new Value(index), | 1196 bool success = TryInlineRecognizedMethod(target, |
| 1045 index_scale, | 1197 call, |
| 1046 array_cid, | 1198 *call->ic_data(), |
| 1047 deopt_id); | 1199 &entry, &last); |
| 1048 ReplaceCall(call, array_op); | 1200 ASSERT(success); |
| 1201 // Insert receiver class check. | |
| 1202 AddReceiverCheck(call); | |
| 1203 // Remove the original push arguments. | |
| 1204 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 1205 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 1206 push->ReplaceUsesWith(push->value()->definition()); | |
| 1207 push->RemoveFromGraph(); | |
| 1208 } | |
| 1209 // Replace all uses of this definition with the result. | |
| 1210 call->ReplaceUsesWith(last); | |
| 1211 // Finally insert the sequence other definition in place of this one in the | |
| 1212 // graph. | |
| 1213 call->previous()->LinkTo(entry->next()); | |
| 1214 entry->UnuseAllInputs(); // Entry block is not in the graph. | |
| 1215 last->LinkTo(call); | |
| 1216 // Remove through the iterator. | |
| 1217 ASSERT(current_iterator()->Current() == call); | |
| 1218 current_iterator()->RemoveCurrentFromGraph(); | |
| 1219 call->set_previous(NULL); | |
| 1220 call->set_next(NULL); | |
| 1049 return true; | 1221 return true; |
| 1050 } | 1222 } |
| 1051 | 1223 |
| 1052 | 1224 |
| 1053 static bool SmiFitsInDouble() { return kSmiBits < 53; } | 1225 static bool SmiFitsInDouble() { return kSmiBits < 53; } |
| 1054 | 1226 |
| 1055 | 1227 |
| 1056 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, | 1228 bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call, |
| 1057 Token::Kind op_kind) { | 1229 Token::Kind op_kind) { |
| 1058 const ICData& ic_data = *call->ic_data(); | 1230 const ICData& ic_data = *call->ic_data(); |
| (...skipping 6424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7483 } | 7655 } |
| 7484 | 7656 |
| 7485 // Insert materializations at environment uses. | 7657 // Insert materializations at environment uses. |
| 7486 for (intptr_t i = 0; i < exits.length(); i++) { | 7658 for (intptr_t i = 0; i < exits.length(); i++) { |
| 7487 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); | 7659 CreateMaterializationAt(exits[i], alloc, alloc->cls(), *fields); |
| 7488 } | 7660 } |
| 7489 } | 7661 } |
| 7490 | 7662 |
| 7491 | 7663 |
| 7492 } // namespace dart | 7664 } // namespace dart |
| OLD | NEW |