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

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

Issue 23684059: Polymorphic inlining of [] operations. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 3 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/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.h » ('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/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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_optimizer.h ('k') | runtime/vm/intermediate_language.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698