| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/opt_code_generator.h" | 8 #include "vm/opt_code_generator.h" |
| 9 | 9 |
| 10 #include "vm/assembler_macros.h" | 10 #include "vm/assembler_macros.h" |
| (...skipping 537 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 548 return false; | 548 return false; |
| 549 } | 549 } |
| 550 if ((cls2.raw() != (*classes)[0]->raw()) && | 550 if ((cls2.raw() != (*classes)[0]->raw()) && |
| 551 (cls2.raw() != (*classes)[1]->raw())) { | 551 (cls2.raw() != (*classes)[1]->raw())) { |
| 552 return false; | 552 return false; |
| 553 } | 553 } |
| 554 return true; | 554 return true; |
| 555 } | 555 } |
| 556 | 556 |
| 557 | 557 |
| 558 static bool NodeHasOnlyClass(AstNode* node, const Class& cls) { | 558 static bool AtIdNodeHasOnlyClass(AstNode* node, intptr_t id, const Class& cls) { |
| 559 ASSERT(node != NULL); | 559 ASSERT(node != NULL); |
| 560 ASSERT(!cls.IsNull()); | 560 ASSERT(!cls.IsNull()); |
| 561 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); | 561 const ICData& ic_data = node->ICDataAtId(id); |
| 562 return (classes != NULL) && | 562 if ((ic_data.NumberOfArgumentsChecked() != 1) || |
| 563 (classes->length() == 1) && | 563 (ic_data.NumberOfChecks() != 1)) { |
| 564 ((*classes)[0]->raw() == cls.raw()); | 564 return false; |
| 565 } |
| 566 Class& target_cls = Class::Handle(); |
| 567 Function& target = Function::Handle(); |
| 568 ic_data.GetOneClassCheckAt(0, &target_cls, &target); |
| 569 return target_cls.raw() == cls.raw(); |
| 565 } | 570 } |
| 566 | 571 |
| 567 | 572 |
| 573 |
| 568 // Implement with slow case so that it can work both with Smi and Mint types. | 574 // Implement with slow case so that it can work both with Smi and Mint types. |
| 569 void OptimizingCodeGenerator::GenerateSmiShiftBinaryOp(BinaryOpNode* node) { | 575 void OptimizingCodeGenerator::GenerateSmiShiftBinaryOp(BinaryOpNode* node) { |
| 570 ASSERT(node->kind() == Token::kSHL); | 576 ASSERT(node->kind() == Token::kSHL); |
| 571 Label done; | 577 Label done; |
| 572 bool shift_generated = false; | 578 bool shift_generated = false; |
| 573 if (node->right()->IsLiteralNode() && | 579 if (node->right()->IsLiteralNode() && |
| 574 node->right()->AsLiteralNode()->literal().IsSmi()) { | 580 node->right()->AsLiteralNode()->literal().IsSmi()) { |
| 575 // Shift count is a Smi literal. | 581 // Shift count is a Smi literal. |
| 576 Smi& smi = Smi::Handle(); | 582 Smi& smi = Smi::Handle(); |
| 577 smi ^= node->right()->AsLiteralNode()->literal().raw(); | 583 smi ^= node->right()->AsLiteralNode()->literal().raw(); |
| (...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { | 1028 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { |
| 1023 if (FLAG_enable_type_checks) { | 1029 if (FLAG_enable_type_checks) { |
| 1024 CodeGenerator::VisitBinaryOpNode(node); | 1030 CodeGenerator::VisitBinaryOpNode(node); |
| 1025 return; | 1031 return; |
| 1026 } | 1032 } |
| 1027 GenerateLogicalBinaryOp(node); | 1033 GenerateLogicalBinaryOp(node); |
| 1028 return; | 1034 return; |
| 1029 } | 1035 } |
| 1030 | 1036 |
| 1031 ObjectStore* object_store = Isolate::Current()->object_store(); | 1037 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 1032 if (NodeHasOnlyClass(node, smi_class_)) { | 1038 if (AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { |
| 1033 GenerateSmiBinaryOp(node); | 1039 GenerateSmiBinaryOp(node); |
| 1034 return; | 1040 return; |
| 1035 } | 1041 } |
| 1036 | 1042 |
| 1037 if (NodeHasOnlyClass(node, double_class_)) { | 1043 if (AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { |
| 1038 GenerateDoubleBinaryOp(node); | 1044 GenerateDoubleBinaryOp(node); |
| 1039 return; | 1045 return; |
| 1040 } | 1046 } |
| 1041 | 1047 |
| 1042 if (NodeHasOnlyClass(node, Class::Handle(object_store->mint_class()))) { | 1048 if (AtIdNodeHasOnlyClass(node, |
| 1049 node->id(), |
| 1050 Class::Handle(object_store->mint_class()))) { |
| 1043 GenerateMintBinaryOp(node, false); | 1051 GenerateMintBinaryOp(node, false); |
| 1044 return; | 1052 return; |
| 1045 } | 1053 } |
| 1046 | 1054 |
| 1047 if (NodeHasBothClasses(node, | 1055 if (NodeHasBothClasses(node, |
| 1048 smi_class_, Class::Handle(object_store->mint_class()))) { | 1056 smi_class_, Class::Handle(object_store->mint_class()))) { |
| 1049 GenerateMintBinaryOp(node, true); | 1057 GenerateMintBinaryOp(node, true); |
| 1050 return; | 1058 return; |
| 1051 } | 1059 } |
| 1052 | 1060 |
| 1053 // Type feedback tells this is not a Smi or Double operation. | 1061 // Type feedback tells this is not a Smi or Double operation. |
| 1054 TraceNotOpt(node, | 1062 TraceNotOpt(node, |
| 1055 "BinaryOp: type feedback tells this is not a Smi or Double op"); | 1063 "BinaryOp: type feedback tells this is not a Smi or Double op"); |
| 1056 CodeGenerator::VisitBinaryOpNode(node); | 1064 CodeGenerator::VisitBinaryOpNode(node); |
| 1057 return; | 1065 return; |
| 1058 } | 1066 } |
| 1059 | 1067 |
| 1060 | 1068 |
| 1061 void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { | 1069 void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { |
| 1062 if (FLAG_enable_type_checks) { | 1070 if (FLAG_enable_type_checks) { |
| 1063 CodeGenerator::VisitIncrOpLocalNode(node); | 1071 CodeGenerator::VisitIncrOpLocalNode(node); |
| 1064 return; | 1072 return; |
| 1065 } | 1073 } |
| 1066 const char* kOptMessage = "Inlines IncrOpLocal"; | 1074 const char* kOptMessage = "Inlines IncrOpLocal"; |
| 1067 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); | 1075 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); |
| 1068 if (!NodeHasOnlyClass(node, smi_class_)) { | 1076 if (!AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { |
| 1069 TraceNotOpt(node, kOptMessage); | 1077 TraceNotOpt(node, kOptMessage); |
| 1070 CodeGenerator::VisitIncrOpLocalNode(node); | 1078 CodeGenerator::VisitIncrOpLocalNode(node); |
| 1071 return; | 1079 return; |
| 1072 } | 1080 } |
| 1073 TraceOpt(node, kOptMessage); | 1081 TraceOpt(node, kOptMessage); |
| 1074 | 1082 |
| 1075 GenerateLoadVariable(EAX, node->local()); | 1083 GenerateLoadVariable(EAX, node->local()); |
| 1076 if (!node->prefix() && IsResultNeeded(node)) { | 1084 if (!node->prefix() && IsResultNeeded(node)) { |
| 1077 // Preserve as result. | 1085 // Preserve as result. |
| 1078 __ movl(ECX, EAX); | 1086 __ movl(ECX, EAX); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1092 } | 1100 } |
| 1093 if (node->prefix()) { | 1101 if (node->prefix()) { |
| 1094 __ pushl(EAX); | 1102 __ pushl(EAX); |
| 1095 } else { | 1103 } else { |
| 1096 __ pushl(ECX); | 1104 __ pushl(ECX); |
| 1097 } | 1105 } |
| 1098 } | 1106 } |
| 1099 } | 1107 } |
| 1100 | 1108 |
| 1101 | 1109 |
| 1110 void OptimizingCodeGenerator::VisitIncrOpInstanceFieldNode( |
| 1111 IncrOpInstanceFieldNode* node) { |
| 1112 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); |
| 1113 VisitLoadOne(node->receiver(), EBX); |
| 1114 __ pushl(EBX); // Duplicate receiver (preserve for setter). |
| 1115 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1116 if (ic_data.NumberOfChecks() == 0) { |
| 1117 // Deoptimization point for this node is after receiver has been |
| 1118 // pushed twice on stack and before the getter (above) was executed. |
| 1119 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); |
| 1120 __ jmp(deopt_blob->label()); |
| 1121 return; |
| 1122 } |
| 1123 InlineInstanceGetter(node, |
| 1124 node->getter_id(), |
| 1125 node->receiver(), |
| 1126 node->field_name(), |
| 1127 EBX); |
| 1128 // result is in EAX. |
| 1129 __ popl(EDX); // Get receiver. |
| 1130 const bool return_original_value = !node->prefix() && IsResultNeeded(node); |
| 1131 const Immediate one_value = Immediate(Smi::RawValue(1)); |
| 1132 // EAX: Value. |
| 1133 // EDX: Receiver. |
| 1134 if (AtIdNodeHasOnlyClass(node, node->operator_id(), smi_class_)) { |
| 1135 // Deoptimization point for this node is after receiver has been |
| 1136 // pushed twice on stack and before the getter (above) was executed. |
| 1137 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EDX); |
| 1138 if (return_original_value) { |
| 1139 // Preserve pre increment result. |
| 1140 __ movl(ECX, EAX); |
| 1141 } |
| 1142 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1143 __ j(NOT_ZERO, deopt_blob->label()); |
| 1144 if (node->kind() == Token::kINCR) { |
| 1145 __ addl(EAX, one_value); |
| 1146 } else { |
| 1147 __ subl(EAX, one_value); |
| 1148 } |
| 1149 __ j(OVERFLOW, deopt_blob->label()); |
| 1150 if (return_original_value) { |
| 1151 // Preserve as result. |
| 1152 __ pushl(ECX); // Preserve pre-increment value as result. |
| 1153 } |
| 1154 } else { |
| 1155 if (return_original_value) { |
| 1156 // Preserve as result. |
| 1157 __ pushl(EAX); // Preserve value as result. |
| 1158 } |
| 1159 __ pushl(EDX); // Preserve receiver. |
| 1160 __ pushl(EAX); // Left operand. |
| 1161 __ pushl(one_value); // Right operand. |
| 1162 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; |
| 1163 GenerateBinaryOperatorCall(node->operator_id(), |
| 1164 node->token_index(), |
| 1165 operator_name); |
| 1166 __ popl(EDX); // Restore receiver. |
| 1167 } |
| 1168 // EAX: Result of binary operation. |
| 1169 // EDX: receiver |
| 1170 if (IsResultNeeded(node) && node->prefix()) { |
| 1171 // Value stored into field is the result. |
| 1172 __ pushl(EAX); |
| 1173 } |
| 1174 |
| 1175 // TODO(srdjan): Inline instance setter. |
| 1176 __ pushl(EDX); // Receiver. |
| 1177 __ pushl(EAX); // Value. |
| 1178 // It is not necessary to generate a type test of the assigned value here, |
| 1179 // because the setter will check the type of its incoming arguments. |
| 1180 GenerateInstanceSetterCall(node->setter_id(), |
| 1181 node->token_index(), |
| 1182 node->field_name()); |
| 1183 } |
| 1184 |
| 1185 |
| 1186 |
| 1187 |
| 1188 |
| 1102 // Return offset of a field or -1 if field is not found. | 1189 // Return offset of a field or -1 if field is not found. |
| 1103 static intptr_t GetFieldOffset(const Class& field_class, | 1190 static intptr_t GetFieldOffset(const Class& field_class, |
| 1104 const String& field_name) { | 1191 const String& field_name) { |
| 1105 Class& cls = Class::Handle(field_class.raw()); | 1192 Class& cls = Class::Handle(field_class.raw()); |
| 1106 Field& field = Field::Handle(); | 1193 Field& field = Field::Handle(); |
| 1107 while (!cls.IsNull()) { | 1194 while (!cls.IsNull()) { |
| 1108 field = cls.LookupInstanceField(field_name); | 1195 field = cls.LookupInstanceField(field_name); |
| 1109 if (!field.IsNull()) { | 1196 if (!field.IsNull()) { |
| 1110 return field.Offset(); | 1197 return field.Offset(); |
| 1111 } | 1198 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1136 if (!function_owner.IsSmi() && | 1223 if (!function_owner.IsSmi() && |
| 1137 (function_owner.raw() != integer_implementation_class.raw())) { | 1224 (function_owner.raw() != integer_implementation_class.raw())) { |
| 1138 return false; | 1225 return false; |
| 1139 } | 1226 } |
| 1140 } | 1227 } |
| 1141 return true; | 1228 return true; |
| 1142 } | 1229 } |
| 1143 | 1230 |
| 1144 | 1231 |
| 1145 // Emits code for an instance getter that has one or more collected classes, | 1232 // Emits code for an instance getter that has one or more collected classes, |
| 1146 // all with the same target. | 1233 // all with the same target. Deoptimizes for Smi or unexpected class. |
| 1234 // EBX: loaded receiver. |
| 1235 // Result is returned in EAX. |
| 1147 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( | 1236 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( |
| 1148 InstanceGetterNode* node, const Function& target) { | 1237 AstNode* node, |
| 1149 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); | 1238 AstNode* receiver, |
| 1150 ASSERT(classes->length() > 0); | 1239 const String& field_name, |
| 1151 Label load_field; | 1240 Register recv_reg) { |
| 1152 VisitLoadOne(node->receiver(), EBX); | 1241 if (recv_reg != EBX) { |
| 1242 // TODO(srdjan): Do not hardwire register. |
| 1243 UNIMPLEMENTED(); |
| 1244 } |
| 1153 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); | 1245 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); |
| 1154 if (NodeMayBeSmi(node->receiver())) { | 1246 if (NodeMayBeSmi(receiver)) { |
| 1155 __ testl(EBX, Immediate(kSmiTagMask)); | 1247 __ testl(EBX, Immediate(kSmiTagMask)); |
| 1156 __ j(ZERO, deopt_blob->label()); | 1248 __ j(ZERO, deopt_blob->label()); |
| 1157 } | 1249 } |
| 1250 |
| 1158 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 1251 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 1159 const int num_classes = classes->length(); | 1252 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1160 for (intptr_t i = 0; i < num_classes; i++) { | 1253 Function& target = Function::Handle(); |
| 1161 const Class& cls = *(*classes)[i]; | 1254 Label load_field; |
| 1255 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 1256 Class& cls = Class::ZoneHandle(); |
| 1257 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 1162 __ CompareObject(EAX, cls); | 1258 __ CompareObject(EAX, cls); |
| 1163 if (i == (num_classes - 1)) { | 1259 if (i == (ic_data.NumberOfChecks() - 1)) { |
| 1164 __ j(NOT_EQUAL, deopt_blob->label()); | 1260 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1165 } else { | 1261 } else { |
| 1166 __ j(EQUAL, &load_field, Assembler::kNearJump); | 1262 __ j(EQUAL, &load_field, Assembler::kNearJump); |
| 1167 } | 1263 } |
| 1168 } | 1264 } |
| 1265 Class& cls = Class::Handle(); |
| 1266 ic_data.GetOneClassCheckAt(0, &cls, &target); |
| 1267 |
| 1169 __ Bind(&load_field); | 1268 __ Bind(&load_field); |
| 1170 | |
| 1171 // EBX: receiver. | 1269 // EBX: receiver. |
| 1172 if (target.kind() == RawFunction::kImplicitGetter) { | 1270 if (target.kind() == RawFunction::kImplicitGetter) { |
| 1173 TraceOpt(node, "Inlines instance getter with same target"); | 1271 TraceOpt(node, "Inlines instance getter with same target"); |
| 1174 // Inlineable load field. | 1272 intptr_t field_offset = GetFieldOffset(cls, field_name); |
| 1175 intptr_t field_offset = GetFieldOffset(*(*classes)[0], | |
| 1176 node->field_name()); | |
| 1177 ASSERT(field_offset >= 0); | 1273 ASSERT(field_offset >= 0); |
| 1178 __ movl(EAX, FieldAddress(EBX, field_offset)); | 1274 __ movl(EAX, FieldAddress(EBX, field_offset)); |
| 1179 return; | 1275 return; |
| 1180 } | 1276 } |
| 1277 |
| 1181 Recognizer::Kind recognized_kind = Recognizer::RecognizeKind(target); | 1278 Recognizer::Kind recognized_kind = Recognizer::RecognizeKind(target); |
| 1182 switch (recognized_kind) { | 1279 switch (recognized_kind) { |
| 1183 case Recognizer::kObjectArrayLength: { | 1280 case Recognizer::kObjectArrayLength: { |
| 1184 TraceOpt(node, "Inlines ObjectArray.length"); | 1281 TraceOpt(node, "Inlines ObjectArray.length"); |
| 1185 __ movl(EAX, FieldAddress(EBX, Array::length_offset())); | 1282 __ movl(EAX, FieldAddress(EBX, Array::length_offset())); |
| 1186 return; | 1283 return; |
| 1187 } | 1284 } |
| 1188 case Recognizer::kGrowableArrayLength: { | 1285 case Recognizer::kGrowableArrayLength: { |
| 1189 TraceOpt(node, "Inlines GrowableObjectArray.length"); | 1286 TraceOpt(node, "Inlines GrowableObjectArray.length"); |
| 1190 intptr_t field_offset = GetFieldOffset( | 1287 intptr_t field_offset = GetFieldOffset( |
| 1191 *(*classes)[0], | 1288 cls, |
| 1192 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName))); | 1289 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName))); |
| 1193 __ movl(EAX, FieldAddress(EBX, field_offset)); | 1290 __ movl(EAX, FieldAddress(EBX, field_offset)); |
| 1194 return; | 1291 return; |
| 1195 } | 1292 } |
| 1196 default: | 1293 default: |
| 1197 UNIMPLEMENTED(); | 1294 UNIMPLEMENTED(); |
| 1198 } | 1295 } |
| 1199 } | 1296 } |
| 1200 | 1297 |
| 1201 | 1298 |
| 1202 bool OptimizingCodeGenerator::IsInlineableInstanceGetter( | 1299 bool OptimizingCodeGenerator::IsInlineableInstanceGetter( |
| 1203 const Function& function) { | 1300 const Function& function) { |
| 1204 if (function.kind() == RawFunction::kImplicitGetter) { | 1301 if (function.kind() == RawFunction::kImplicitGetter) { |
| 1205 return true; | 1302 return true; |
| 1206 } | 1303 } |
| 1207 Recognizer::Kind recognized = Recognizer::RecognizeKind(function); | 1304 Recognizer::Kind recognized = Recognizer::RecognizeKind(function); |
| 1208 if ((recognized == Recognizer::kObjectArrayLength) || | 1305 if ((recognized == Recognizer::kObjectArrayLength) || |
| 1209 (recognized == Recognizer::kGrowableArrayLength)) { | 1306 (recognized == Recognizer::kGrowableArrayLength)) { |
| 1210 return true; | 1307 return true; |
| 1211 } | 1308 } |
| 1212 return false; | 1309 return false; |
| 1213 } | 1310 } |
| 1214 | 1311 |
| 1215 | 1312 |
| 1313 // Return true if all targets in 'ic_data' point to same |
| 1314 // inlineable getter target. |
| 1315 bool OptimizingCodeGenerator::ICDataToSameInlineableInstanceGetter( |
| 1316 const ICData& ic_data) { |
| 1317 Function& prev_target = Function::Handle(); |
| 1318 Function& target = Function::Handle(); |
| 1319 Class& cls = Class::Handle(); |
| 1320 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 1321 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 1322 ASSERT(!target.IsNull()); |
| 1323 if (!prev_target.IsNull() && (prev_target.raw() != target.raw())) { |
| 1324 return false; |
| 1325 } |
| 1326 prev_target = target.raw(); |
| 1327 if (!IsInlineableInstanceGetter(target)) { |
| 1328 return false; |
| 1329 } |
| 1330 } |
| 1331 return true; |
| 1332 } |
| 1333 |
| 1334 |
| 1335 void OptimizingCodeGenerator::InlineInstanceGetter(AstNode* node, |
| 1336 intptr_t id, |
| 1337 AstNode* receiver, |
| 1338 const String& field_name, |
| 1339 Register recv_reg) { |
| 1340 if (ICDataToSameInlineableInstanceGetter(node->ICDataAtId(id))) { |
| 1341 InlineInstanceGettersWithSameTarget(node, receiver, field_name, recv_reg); |
| 1342 } else { |
| 1343 // TODO(srdjan): Inline access. |
| 1344 __ pushl(recv_reg); |
| 1345 const int kNumberOfArguments = 1; |
| 1346 const Array& kNoArgumentNames = Array::Handle(); |
| 1347 GenerateCheckedInstanceCalls(node, |
| 1348 receiver, |
| 1349 node->id(), |
| 1350 node->token_index(), |
| 1351 kNumberOfArguments, |
| 1352 kNoArgumentNames); |
| 1353 } |
| 1354 } |
| 1355 |
| 1356 |
| 1216 // TODO(srdjan): Implement for multiple getter targets. | 1357 // TODO(srdjan): Implement for multiple getter targets. |
| 1217 // For every class inline its implicit getter, or call the instance getter. | 1358 // For every class inline its implicit getter, or call the instance getter. |
| 1218 void OptimizingCodeGenerator::VisitInstanceGetterNode( | 1359 void OptimizingCodeGenerator::VisitInstanceGetterNode( |
| 1219 InstanceGetterNode* node) { | 1360 InstanceGetterNode* node) { |
| 1220 const char* kMessage = "Inline instance getter"; | 1361 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1221 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); | 1362 if (ic_data.NumberOfChecks() == 0) { |
| 1222 const String& getter_name = | 1363 // No type feedback collected. |
| 1223 String::Handle(Field::GetterName(node->field_name())); | 1364 node->receiver()->Visit(this); |
| 1224 if (FLAG_trace_optimization) { | 1365 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node); |
| 1225 OS::Print("Getter %s ", getter_name.ToCString()); | 1366 __ jmp(deopt_blob->label()); |
| 1226 } | |
| 1227 if ((classes == NULL) || classes->is_empty()) { | |
| 1228 TraceNotOpt(node, kMessage); | |
| 1229 CodeGenerator::VisitInstanceGetterNode(node); | |
| 1230 return; | 1367 return; |
| 1231 } | 1368 } |
| 1232 // Collect all targets and identify if they are all inlineable and | 1369 |
| 1233 // all same. Use 'targets' for case when not all targets are inlineable. | 1370 VisitLoadOne(node->receiver(), EBX); |
| 1234 const intptr_t num_classes = classes->length(); | 1371 InlineInstanceGetter(node, |
| 1235 GrowableArray<const Function*> targets(num_classes); | 1372 node->id(), |
| 1236 bool all_inlineable = true; | 1373 node->receiver(), |
| 1237 bool all_same_target = true; | 1374 node->field_name(), |
| 1238 for (intptr_t i = 0; i < num_classes; i++) { | 1375 EBX); |
| 1239 const Class& cls = *(*classes)[i]; | 1376 // Result is in EAX. |
| 1240 const int kNumArguments = 1; | |
| 1241 const int kNumNamedArguments = 0; | |
| 1242 const Function& target = Function::ZoneHandle( | |
| 1243 Resolver::ResolveDynamicForReceiverClass(cls, | |
| 1244 getter_name, | |
| 1245 kNumArguments, | |
| 1246 kNumNamedArguments)); | |
| 1247 ASSERT(!target.IsNull()); | |
| 1248 targets.Add(&target); | |
| 1249 if (targets[0]->raw() != target.raw()) { | |
| 1250 all_same_target = false; | |
| 1251 } | |
| 1252 if (!IsInlineableInstanceGetter(target)) { | |
| 1253 all_inlineable = false; | |
| 1254 } | |
| 1255 } | |
| 1256 // TODO(srdjan): implement other variants. | |
| 1257 if (all_inlineable && all_same_target) { | |
| 1258 InlineInstanceGettersWithSameTarget(node, *targets[0]); | |
| 1259 } else { | |
| 1260 // TODO(srdjan): Inline access. | |
| 1261 TraceNotOpt(node, kMessage); | |
| 1262 node->receiver()->Visit(this); | |
| 1263 const int kNumberOfArguments = 1; | |
| 1264 const Array& kNoArgumentNames = Array::Handle(); | |
| 1265 GenerateCheckedInstanceCalls(node, | |
| 1266 node->receiver(), | |
| 1267 node->id(), | |
| 1268 node->token_index(), | |
| 1269 kNumberOfArguments, | |
| 1270 kNoArgumentNames); | |
| 1271 } | |
| 1272 if (CodeGenerator::IsResultNeeded(node)) { | 1377 if (CodeGenerator::IsResultNeeded(node)) { |
| 1273 __ pushl(EAX); | 1378 __ pushl(EAX); |
| 1274 } | 1379 } |
| 1275 } | 1380 } |
| 1276 | 1381 |
| 1277 | 1382 |
| 1278 // The call to the instance setter implements the assignment to a field. | 1383 // The call to the instance setter implements the assignment to a field. |
| 1279 // The result of the assignment to a field is the value being stored. | 1384 // The result of the assignment to a field is the value being stored. |
| 1280 void OptimizingCodeGenerator::VisitInstanceSetterNode( | 1385 void OptimizingCodeGenerator::VisitInstanceSetterNode( |
| 1281 InstanceSetterNode* node) { | 1386 InstanceSetterNode* node) { |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1763 __ j(condition, &is_true); | 1868 __ j(condition, &is_true); |
| 1764 __ PushObject(bool_false); | 1869 __ PushObject(bool_false); |
| 1765 __ jmp(&done); | 1870 __ jmp(&done); |
| 1766 __ Bind(&is_true); | 1871 __ Bind(&is_true); |
| 1767 __ PushObject(bool_true); | 1872 __ PushObject(bool_true); |
| 1768 __ Bind(&done); | 1873 __ Bind(&done); |
| 1769 } | 1874 } |
| 1770 return; | 1875 return; |
| 1771 } | 1876 } |
| 1772 | 1877 |
| 1773 if (NodeHasOnlyClass(node, smi_class_)) { | 1878 if (AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { |
| 1774 if (GenerateSmiComparison(node)) { | 1879 if (GenerateSmiComparison(node)) { |
| 1775 return; | 1880 return; |
| 1776 } | 1881 } |
| 1777 // Fall through if condition is not supported. | 1882 // Fall through if condition is not supported. |
| 1778 } else if (NodeHasOnlyClass(node, double_class_)) { | 1883 } else if (AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { |
| 1779 // Double comparison | 1884 // Double comparison |
| 1780 if (GenerateDoubleComparison(node)) { | 1885 if (GenerateDoubleComparison(node)) { |
| 1781 return; | 1886 return; |
| 1782 } | 1887 } |
| 1783 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { | 1888 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { |
| 1784 // Equality, not-equality comparison of any other type. | 1889 // Equality, not-equality comparison of any other type. |
| 1785 if (GenerateEqualityComparison(node)) { | 1890 if (GenerateEqualityComparison(node)) { |
| 1786 return; | 1891 return; |
| 1787 } | 1892 } |
| 1788 } | 1893 } |
| 1789 | 1894 |
| 1790 // Fall through here if a comparison was not implemented. | 1895 // Fall through here if a comparison was not implemented. |
| 1791 CodeGenerator::VisitComparisonNode(node); | 1896 CodeGenerator::VisitComparisonNode(node); |
| 1792 } | 1897 } |
| 1793 | 1898 |
| 1794 | 1899 |
| 1795 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { | 1900 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { |
| 1796 const char* kMessage = "Inline indexed access"; | 1901 const char* kMessage = "Inline indexed access"; |
| 1797 ObjectStore* object_store = Isolate::Current()->object_store(); | 1902 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 1798 const Class& object_array_class = | 1903 const Class& object_array_class = |
| 1799 Class::ZoneHandle(object_store->array_class()); | 1904 Class::ZoneHandle(object_store->array_class()); |
| 1800 const Class& immutable_object_array_class = | 1905 const Class& immutable_object_array_class = |
| 1801 Class::ZoneHandle(object_store->immutable_array_class()); | 1906 Class::ZoneHandle(object_store->immutable_array_class()); |
| 1802 if (NodeHasOnlyClass(node, object_array_class) || | 1907 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class) || |
| 1803 NodeHasOnlyClass(node, immutable_object_array_class)) { | 1908 AtIdNodeHasOnlyClass(node, node->id(), immutable_object_array_class)) { |
| 1804 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); | 1909 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); |
| 1805 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX, EDX); | 1910 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX, EDX); |
| 1806 const Class& test_class = NodeHasOnlyClass(node, object_array_class) ? | 1911 const Class& test_class = |
| 1807 object_array_class : immutable_object_array_class; | 1912 AtIdNodeHasOnlyClass(node, node->id(), object_array_class) ? |
| 1913 object_array_class : immutable_object_array_class; |
| 1808 // Type checks of array. | 1914 // Type checks of array. |
| 1809 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. | 1915 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. |
| 1810 __ j(ZERO, deopt_blob->label()); | 1916 __ j(ZERO, deopt_blob->label()); |
| 1811 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 1917 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 1812 __ CompareObject(EAX, test_class); | 1918 __ CompareObject(EAX, test_class); |
| 1813 __ j(NOT_EQUAL, deopt_blob->label()); | 1919 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1814 | 1920 |
| 1815 // Type check of index. | 1921 // Type check of index. |
| 1816 __ testl(EDX, Immediate(kSmiTagMask)); | 1922 __ testl(EDX, Immediate(kSmiTagMask)); |
| 1817 __ j(NOT_ZERO, deopt_blob->label()); | 1923 __ j(NOT_ZERO, deopt_blob->label()); |
| 1818 // Range check. | 1924 // Range check. |
| 1819 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); | 1925 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); |
| 1820 __ j(ABOVE_EQUAL, deopt_blob->label()); | 1926 __ j(ABOVE_EQUAL, deopt_blob->label()); |
| 1821 // Note that EDX is Smi, i.e, times 2. | 1927 // Note that EDX is Smi, i.e, times 2. |
| 1822 ASSERT(kSmiTagShift == 1); | 1928 ASSERT(kSmiTagShift == 1); |
| 1823 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); | 1929 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); |
| 1824 if (CodeGenerator::IsResultNeeded(node)) { | 1930 if (CodeGenerator::IsResultNeeded(node)) { |
| 1825 __ pushl(EAX); | 1931 __ pushl(EAX); |
| 1826 } | 1932 } |
| 1827 TraceOpt(node, kMessage); | 1933 TraceOpt(node, kMessage); |
| 1828 return; | 1934 return; |
| 1829 } | 1935 } |
| 1830 | 1936 |
| 1831 const String& growable_object_array_class_name = String::Handle( | 1937 const String& growable_object_array_class_name = String::Handle( |
| 1832 String::NewSymbol(kGrowableArrayClassName)); | 1938 String::NewSymbol(kGrowableArrayClassName)); |
| 1833 const Class& growable_array_class = Class::ZoneHandle( | 1939 const Class& growable_array_class = Class::ZoneHandle( |
| 1834 Library::Handle(Library::CoreImplLibrary()). | 1940 Library::Handle(Library::CoreImplLibrary()). |
| 1835 LookupClass(growable_object_array_class_name)); | 1941 LookupClass(growable_object_array_class_name)); |
| 1836 if (NodeHasOnlyClass(node, growable_array_class)) { | 1942 if (AtIdNodeHasOnlyClass(node, node->id(), growable_array_class)) { |
| 1837 const String& growable_array_length_field_name = | 1943 const String& growable_array_length_field_name = |
| 1838 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); | 1944 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); |
| 1839 const String& growable_array_array_field_name = | 1945 const String& growable_array_array_field_name = |
| 1840 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); | 1946 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); |
| 1841 intptr_t length_offset = GetFieldOffset(growable_array_class, | 1947 intptr_t length_offset = GetFieldOffset(growable_array_class, |
| 1842 growable_array_length_field_name); | 1948 growable_array_length_field_name); |
| 1843 intptr_t array_offset = GetFieldOffset(growable_array_class, | 1949 intptr_t array_offset = GetFieldOffset(growable_array_class, |
| 1844 growable_array_array_field_name); | 1950 growable_array_array_field_name); |
| 1845 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); | 1951 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); |
| 1846 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EAX); | 1952 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EAX); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1875 void OptimizingCodeGenerator::VisitStoreIndexedNode(StoreIndexedNode* node) { | 1981 void OptimizingCodeGenerator::VisitStoreIndexedNode(StoreIndexedNode* node) { |
| 1876 if (FLAG_enable_type_checks) { | 1982 if (FLAG_enable_type_checks) { |
| 1877 CodeGenerator::VisitStoreIndexedNode(node); | 1983 CodeGenerator::VisitStoreIndexedNode(node); |
| 1878 return; | 1984 return; |
| 1879 } | 1985 } |
| 1880 node->array()->Visit(this); | 1986 node->array()->Visit(this); |
| 1881 // TODO(srdjan): Use VisitLoadTwo and check if index is smi (CodeGenInfo). | 1987 // TODO(srdjan): Use VisitLoadTwo and check if index is smi (CodeGenInfo). |
| 1882 ObjectStore* object_store = Isolate::Current()->object_store(); | 1988 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 1883 const Class& object_array_class = | 1989 const Class& object_array_class = |
| 1884 Class::ZoneHandle(object_store->array_class()); | 1990 Class::ZoneHandle(object_store->array_class()); |
| 1885 if (NodeHasOnlyClass(node, object_array_class)) { | 1991 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class)) { |
| 1886 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); | 1992 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); |
| 1887 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EBX, ECX); | 1993 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EBX, ECX); |
| 1888 __ popl(EAX); // array. | 1994 __ popl(EAX); // array. |
| 1889 // ECX: value, EBX:index, EAX: array. | 1995 // ECX: value, EBX:index, EAX: array. |
| 1890 // Check type of array. | 1996 // Check type of array. |
| 1891 __ testl(EAX, Immediate(kSmiTagMask)); | 1997 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1892 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. | 1998 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. |
| 1893 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); | 1999 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); |
| 1894 __ CompareObject(EDX, object_array_class); | 2000 __ CompareObject(EDX, object_array_class); |
| 1895 __ j(NOT_EQUAL, deopt_blob->label()); // Not ObjectArray -> deopt. | 2001 __ j(NOT_EQUAL, deopt_blob->label()); // Not ObjectArray -> deopt. |
| (...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2191 node->function_name(), | 2297 node->function_name(), |
| 2192 num_arguments, | 2298 num_arguments, |
| 2193 num_named_arguments)); | 2299 num_named_arguments)); |
| 2194 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); | 2300 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); |
| 2195 if (FLAG_trace_optimization) { | 2301 if (FLAG_trace_optimization) { |
| 2196 OS::Print("Monomorphic inline candidate: %s -> %s\n", | 2302 OS::Print("Monomorphic inline candidate: %s -> %s\n", |
| 2197 target.ToFullyQualifiedCString(), | 2303 target.ToFullyQualifiedCString(), |
| 2198 Recognizer::KindToCString(recognized)); | 2304 Recognizer::KindToCString(recognized)); |
| 2199 } | 2305 } |
| 2200 if ((recognized == Recognizer::kIntegerToDouble) && | 2306 if ((recognized == Recognizer::kIntegerToDouble) && |
| 2201 NodeHasOnlyClass(node, smi_class_)) { | 2307 AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { |
| 2202 // TODO(srdjan): Check if we could use temporary double instead of | 2308 // TODO(srdjan): Check if we could use temporary double instead of |
| 2203 // allocating a new object every time. | 2309 // allocating a new object every time. |
| 2204 const Code& stub = | 2310 const Code& stub = |
| 2205 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 2311 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 2206 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 2312 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 2207 GenerateCall(node->token_index(), &label); | 2313 GenerateCall(node->token_index(), &label); |
| 2208 // EAX is double object. | 2314 // EAX is double object. |
| 2209 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); | 2315 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); |
| 2210 __ popl(EBX); // Receiver | 2316 __ popl(EBX); // Receiver |
| 2211 __ testl(EBX, Immediate(kSmiTagMask)); | 2317 __ testl(EBX, Immediate(kSmiTagMask)); |
| 2212 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. | 2318 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. |
| 2213 __ SmiUntag(EBX); | 2319 __ SmiUntag(EBX); |
| 2214 __ cvtsi2sd(XMM0, EBX); | 2320 __ cvtsi2sd(XMM0, EBX); |
| 2215 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 2321 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 2216 return true; | 2322 return true; |
| 2217 } | 2323 } |
| 2218 | 2324 |
| 2219 if ((recognized == Recognizer::kDoubleToDouble) && | 2325 if ((recognized == Recognizer::kDoubleToDouble) && |
| 2220 NodeHasOnlyClass(node, double_class_)) { | 2326 AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { |
| 2221 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX); | 2327 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX); |
| 2222 __ popl(EAX); | 2328 __ popl(EAX); |
| 2223 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); | 2329 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); |
| 2224 return true; | 2330 return true; |
| 2225 } | 2331 } |
| 2226 } | 2332 } |
| 2227 return false; | 2333 return false; |
| 2228 } | 2334 } |
| 2229 | 2335 |
| 2230 | 2336 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2271 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); | 2377 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); |
| 2272 // Result is in EAX. | 2378 // Result is in EAX. |
| 2273 if (IsResultNeeded(node)) { | 2379 if (IsResultNeeded(node)) { |
| 2274 __ pushl(EAX); | 2380 __ pushl(EAX); |
| 2275 } | 2381 } |
| 2276 } | 2382 } |
| 2277 | 2383 |
| 2278 } // namespace dart | 2384 } // namespace dart |
| 2279 | 2385 |
| 2280 #endif // defined TARGET_ARCH_IA32 | 2386 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |