Chromium Code Reviews| 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) { |
|
regis
2011/11/02 02:02:54
Missing 2 pairs of parenthesis.
srdjan
2011/11/02 15:26:20
Done.
| |
| 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 InlineInstanceGetter(node, | |
| 1116 node->getter_id(), | |
| 1117 node->receiver(), | |
| 1118 node->field_name(), | |
| 1119 EBX); | |
| 1120 // result is in EAX. | |
| 1121 __ popl(EDX); // Get receiver. | |
| 1122 const bool has_pre_inc_result = !node->prefix() && IsResultNeeded(node); | |
|
regis
2011/11/02 02:02:54
The name of the flag is a bit confusing, "has_pre"
srdjan
2011/11/02 15:26:20
Changed to : return_original_value
| |
| 1123 const Immediate one_value = Immediate(reinterpret_cast<int32_t>(Smi::New(1))); | |
|
regis
2011/11/02 02:02:54
You can hide the cast with Immediate(Smi::RawValue
srdjan
2011/11/02 15:26:20
Done.
| |
| 1124 // EAX: Value. | |
| 1125 // EDX: Receiver. | |
| 1126 if (AtIdNodeHasOnlyClass(node, node->operator_id(), smi_class_)) { | |
| 1127 // Deoptimization point for this node is after receiver has been | |
| 1128 // pushed twice on stack and before the getter (above) was executed. | |
| 1129 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EDX); | |
| 1130 if (has_pre_inc_result) { | |
| 1131 // Preserve pre increment result. | |
| 1132 __ movl(ECX, EAX); | |
| 1133 } | |
| 1134 __ testl(EAX, Immediate(kSmiTagMask)); | |
| 1135 __ j(NOT_ZERO, deopt_blob->label()); | |
| 1136 if (node->kind() == Token::kINCR) { | |
| 1137 __ addl(EAX, one_value); | |
| 1138 } else { | |
| 1139 __ subl(EAX, one_value); | |
| 1140 } | |
| 1141 __ j(OVERFLOW, deopt_blob->label()); | |
| 1142 if (has_pre_inc_result) { | |
| 1143 // Preserve as result. | |
| 1144 __ pushl(ECX); // Preserve pre-increment value as result. | |
| 1145 } | |
| 1146 } else { | |
| 1147 if (has_pre_inc_result) { | |
| 1148 // Preserve as result. | |
| 1149 __ pushl(EAX); // Preserve value as result. | |
| 1150 } | |
| 1151 __ pushl(EDX); // Preserve receiver. | |
| 1152 __ pushl(EAX); // Left operand. | |
| 1153 __ pushl(one_value); // Right operand. | |
| 1154 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; | |
| 1155 GenerateBinaryOperatorCall(node->operator_id(), | |
| 1156 node->token_index(), | |
| 1157 operator_name); | |
| 1158 __ popl(EDX); // Restore receiver. | |
| 1159 } | |
| 1160 // EAX: Result of binary operation. | |
| 1161 // EDX: receiver | |
| 1162 if (IsResultNeeded(node) && node->prefix()) { | |
| 1163 // Value stored into field is the result. | |
| 1164 __ pushl(EAX); | |
| 1165 } | |
| 1166 | |
| 1167 // TODO(srdjan): Inline instance setter. | |
| 1168 __ pushl(EDX); // Receiver. | |
| 1169 __ pushl(EAX); // Value. | |
| 1170 // It is not necessary to generate a type test of the assigned value here, | |
| 1171 // because the setter will check the type of its incoming arguments. | |
| 1172 GenerateInstanceSetterCall(node->setter_id(), | |
| 1173 node->token_index(), | |
| 1174 node->field_name()); | |
| 1175 } | |
| 1176 | |
| 1177 | |
| 1178 | |
| 1179 | |
| 1180 | |
| 1102 // Return offset of a field or -1 if field is not found. | 1181 // Return offset of a field or -1 if field is not found. |
| 1103 static intptr_t GetFieldOffset(const Class& field_class, | 1182 static intptr_t GetFieldOffset(const Class& field_class, |
| 1104 const String& field_name) { | 1183 const String& field_name) { |
| 1105 Class& cls = Class::Handle(field_class.raw()); | 1184 Class& cls = Class::Handle(field_class.raw()); |
| 1106 Field& field = Field::Handle(); | 1185 Field& field = Field::Handle(); |
| 1107 while (!cls.IsNull()) { | 1186 while (!cls.IsNull()) { |
| 1108 field = cls.LookupInstanceField(field_name); | 1187 field = cls.LookupInstanceField(field_name); |
| 1109 if (!field.IsNull()) { | 1188 if (!field.IsNull()) { |
| 1110 return field.Offset(); | 1189 return field.Offset(); |
| 1111 } | 1190 } |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1136 if (!function_owner.IsSmi() && | 1215 if (!function_owner.IsSmi() && |
| 1137 (function_owner.raw() != integer_implementation_class.raw())) { | 1216 (function_owner.raw() != integer_implementation_class.raw())) { |
| 1138 return false; | 1217 return false; |
| 1139 } | 1218 } |
| 1140 } | 1219 } |
| 1141 return true; | 1220 return true; |
| 1142 } | 1221 } |
| 1143 | 1222 |
| 1144 | 1223 |
| 1145 // Emits code for an instance getter that has one or more collected classes, | 1224 // Emits code for an instance getter that has one or more collected classes, |
| 1146 // all with the same target. | 1225 // all with the same target. Deoptimizes for Smi or unexpected class. |
| 1226 // EBX: loaded receiver. | |
| 1227 // Result is returned in EAX. | |
| 1147 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( | 1228 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( |
| 1148 InstanceGetterNode* node, const Function& target) { | 1229 AstNode* node, |
| 1149 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); | 1230 AstNode* receiver, |
| 1150 ASSERT(classes->length() > 0); | 1231 const String& field_name, |
| 1151 Label load_field; | 1232 Register recv_reg) { |
| 1152 VisitLoadOne(node->receiver(), EBX); | 1233 if (recv_reg != EBX) { |
| 1234 // TODO(srdjan): Do not hardwire register. | |
| 1235 UNIMPLEMENTED(); | |
| 1236 } | |
| 1153 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); | 1237 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); |
| 1154 if (NodeMayBeSmi(node->receiver())) { | 1238 if (NodeMayBeSmi(receiver)) { |
| 1155 __ testl(EBX, Immediate(kSmiTagMask)); | 1239 __ testl(EBX, Immediate(kSmiTagMask)); |
| 1156 __ j(ZERO, deopt_blob->label()); | 1240 __ j(ZERO, deopt_blob->label()); |
| 1157 } | 1241 } |
| 1242 | |
| 1158 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 1243 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 1159 const int num_classes = classes->length(); | 1244 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1160 for (intptr_t i = 0; i < num_classes; i++) { | 1245 Function& target = Function::Handle(); |
| 1161 const Class& cls = *(*classes)[i]; | 1246 Label load_field; |
| 1247 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | |
| 1248 Class& cls = Class::ZoneHandle(); | |
| 1249 ic_data.GetOneClassCheckAt(i, &cls, &target); | |
| 1162 __ CompareObject(EAX, cls); | 1250 __ CompareObject(EAX, cls); |
| 1163 if (i == (num_classes - 1)) { | 1251 if (i == (ic_data.NumberOfChecks() - 1)) { |
| 1164 __ j(NOT_EQUAL, deopt_blob->label()); | 1252 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1165 } else { | 1253 } else { |
| 1166 __ j(EQUAL, &load_field, Assembler::kNearJump); | 1254 __ j(EQUAL, &load_field, Assembler::kNearJump); |
| 1167 } | 1255 } |
| 1168 } | 1256 } |
| 1257 Class& cls = Class::Handle(); | |
| 1258 ic_data.GetOneClassCheckAt(0, &cls, &target); | |
| 1259 | |
| 1169 __ Bind(&load_field); | 1260 __ Bind(&load_field); |
| 1170 | |
| 1171 // EBX: receiver. | 1261 // EBX: receiver. |
| 1172 if (target.kind() == RawFunction::kImplicitGetter) { | 1262 if (target.kind() == RawFunction::kImplicitGetter) { |
| 1173 TraceOpt(node, "Inlines instance getter with same target"); | 1263 TraceOpt(node, "Inlines instance getter with same target"); |
| 1174 // Inlineable load field. | 1264 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); | 1265 ASSERT(field_offset >= 0); |
| 1178 __ movl(EAX, FieldAddress(EBX, field_offset)); | 1266 __ movl(EAX, FieldAddress(EBX, field_offset)); |
| 1179 return; | 1267 return; |
| 1180 } | 1268 } |
| 1269 | |
| 1181 Recognizer::Kind recognized_kind = Recognizer::RecognizeKind(target); | 1270 Recognizer::Kind recognized_kind = Recognizer::RecognizeKind(target); |
| 1182 switch (recognized_kind) { | 1271 switch (recognized_kind) { |
| 1183 case Recognizer::kObjectArrayLength: { | 1272 case Recognizer::kObjectArrayLength: { |
| 1184 TraceOpt(node, "Inlines ObjectArray.length"); | 1273 TraceOpt(node, "Inlines ObjectArray.length"); |
| 1185 __ movl(EAX, FieldAddress(EBX, Array::length_offset())); | 1274 __ movl(EAX, FieldAddress(EBX, Array::length_offset())); |
| 1186 return; | 1275 return; |
| 1187 } | 1276 } |
| 1188 case Recognizer::kGrowableArrayLength: { | 1277 case Recognizer::kGrowableArrayLength: { |
| 1189 TraceOpt(node, "Inlines GrowableObjectArray.length"); | 1278 TraceOpt(node, "Inlines GrowableObjectArray.length"); |
| 1190 intptr_t field_offset = GetFieldOffset( | 1279 intptr_t field_offset = GetFieldOffset( |
| 1191 *(*classes)[0], | 1280 cls, |
| 1192 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName))); | 1281 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName))); |
| 1193 __ movl(EAX, FieldAddress(EBX, field_offset)); | 1282 __ movl(EAX, FieldAddress(EBX, field_offset)); |
| 1194 return; | 1283 return; |
| 1195 } | 1284 } |
| 1196 default: | 1285 default: |
| 1197 UNIMPLEMENTED(); | 1286 UNIMPLEMENTED(); |
| 1198 } | 1287 } |
| 1199 } | 1288 } |
| 1200 | 1289 |
| 1201 | 1290 |
| 1202 bool OptimizingCodeGenerator::IsInlineableInstanceGetter( | 1291 bool OptimizingCodeGenerator::IsInlineableInstanceGetter( |
| 1203 const Function& function) { | 1292 const Function& function) { |
| 1204 if (function.kind() == RawFunction::kImplicitGetter) { | 1293 if (function.kind() == RawFunction::kImplicitGetter) { |
| 1205 return true; | 1294 return true; |
| 1206 } | 1295 } |
| 1207 Recognizer::Kind recognized = Recognizer::RecognizeKind(function); | 1296 Recognizer::Kind recognized = Recognizer::RecognizeKind(function); |
| 1208 if ((recognized == Recognizer::kObjectArrayLength) || | 1297 if ((recognized == Recognizer::kObjectArrayLength) || |
| 1209 (recognized == Recognizer::kGrowableArrayLength)) { | 1298 (recognized == Recognizer::kGrowableArrayLength)) { |
| 1210 return true; | 1299 return true; |
| 1211 } | 1300 } |
| 1212 return false; | 1301 return false; |
| 1213 } | 1302 } |
| 1214 | 1303 |
| 1215 | 1304 |
| 1305 // Return true if all targets in 'ic_data' point to same | |
| 1306 // inlineable getter targe. | |
|
regis
2011/11/02 02:02:54
target
srdjan
2011/11/02 15:26:20
Done.
| |
| 1307 bool OptimizingCodeGenerator::ICDataToSameInlineableInstanceGetter( | |
| 1308 const ICData& ic_data) { | |
| 1309 Function& prev_target = Function::Handle(); | |
| 1310 Function& target = Function::Handle(); | |
| 1311 Class& cls = Class::Handle(); | |
| 1312 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | |
| 1313 ic_data.GetOneClassCheckAt(i, &cls, &target); | |
| 1314 ASSERT(!target.IsNull()); | |
| 1315 if (!prev_target.IsNull() && (prev_target.raw() != target.raw())) { | |
| 1316 return false; | |
| 1317 } | |
| 1318 prev_target = target.raw(); | |
| 1319 if (!IsInlineableInstanceGetter(target)) { | |
| 1320 return false; | |
| 1321 } | |
| 1322 } | |
| 1323 return true; | |
| 1324 } | |
| 1325 | |
| 1326 | |
| 1327 void OptimizingCodeGenerator::InlineInstanceGetter(AstNode* node, | |
| 1328 intptr_t id, | |
| 1329 AstNode* receiver, | |
| 1330 const String& field_name, | |
| 1331 Register recv_reg) { | |
| 1332 if (ICDataToSameInlineableInstanceGetter(node->ICDataAtId(id))) { | |
| 1333 InlineInstanceGettersWithSameTarget(node, receiver, field_name, recv_reg); | |
| 1334 } else { | |
| 1335 // TODO(srdjan): Inline access. | |
| 1336 __ pushl(recv_reg); | |
| 1337 const int kNumberOfArguments = 1; | |
| 1338 const Array& kNoArgumentNames = Array::Handle(); | |
| 1339 GenerateCheckedInstanceCalls(node, | |
| 1340 receiver, | |
| 1341 node->id(), | |
| 1342 node->token_index(), | |
| 1343 kNumberOfArguments, | |
| 1344 kNoArgumentNames); | |
| 1345 } | |
| 1346 } | |
| 1347 | |
| 1348 | |
| 1216 // TODO(srdjan): Implement for multiple getter targets. | 1349 // TODO(srdjan): Implement for multiple getter targets. |
| 1217 // For every class inline its implicit getter, or call the instance getter. | 1350 // For every class inline its implicit getter, or call the instance getter. |
| 1218 void OptimizingCodeGenerator::VisitInstanceGetterNode( | 1351 void OptimizingCodeGenerator::VisitInstanceGetterNode( |
| 1219 InstanceGetterNode* node) { | 1352 InstanceGetterNode* node) { |
| 1220 const char* kMessage = "Inline instance getter"; | 1353 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1221 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); | 1354 if (ic_data.NumberOfChecks() == 0) { |
| 1222 const String& getter_name = | 1355 // No type feedback collected. |
| 1223 String::Handle(Field::GetterName(node->field_name())); | 1356 node->receiver()->Visit(this); |
| 1224 if (FLAG_trace_optimization) { | 1357 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node); |
| 1225 OS::Print("Getter %s ", getter_name.ToCString()); | 1358 __ jmp(deopt_blob->label()); |
| 1226 } | |
| 1227 if ((classes == NULL) || classes->is_empty()) { | |
| 1228 TraceNotOpt(node, kMessage); | |
| 1229 CodeGenerator::VisitInstanceGetterNode(node); | |
| 1230 return; | 1359 return; |
| 1231 } | 1360 } |
| 1232 // Collect all targets and identify if they are all inlineable and | 1361 |
| 1233 // all same. Use 'targets' for case when not all targets are inlineable. | 1362 VisitLoadOne(node->receiver(), EBX); |
| 1234 const intptr_t num_classes = classes->length(); | 1363 InlineInstanceGetter(node, |
| 1235 GrowableArray<const Function*> targets(num_classes); | 1364 node->id(), |
| 1236 bool all_inlineable = true; | 1365 node->receiver(), |
| 1237 bool all_same_target = true; | 1366 node->field_name(), |
| 1238 for (intptr_t i = 0; i < num_classes; i++) { | 1367 EBX); |
| 1239 const Class& cls = *(*classes)[i]; | 1368 // 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)) { | 1369 if (CodeGenerator::IsResultNeeded(node)) { |
| 1273 __ pushl(EAX); | 1370 __ pushl(EAX); |
| 1274 } | 1371 } |
| 1275 } | 1372 } |
| 1276 | 1373 |
| 1277 | 1374 |
| 1278 // The call to the instance setter implements the assignment to a field. | 1375 // 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. | 1376 // The result of the assignment to a field is the value being stored. |
| 1280 void OptimizingCodeGenerator::VisitInstanceSetterNode( | 1377 void OptimizingCodeGenerator::VisitInstanceSetterNode( |
| 1281 InstanceSetterNode* node) { | 1378 InstanceSetterNode* node) { |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1763 __ j(condition, &is_true); | 1860 __ j(condition, &is_true); |
| 1764 __ PushObject(bool_false); | 1861 __ PushObject(bool_false); |
| 1765 __ jmp(&done); | 1862 __ jmp(&done); |
| 1766 __ Bind(&is_true); | 1863 __ Bind(&is_true); |
| 1767 __ PushObject(bool_true); | 1864 __ PushObject(bool_true); |
| 1768 __ Bind(&done); | 1865 __ Bind(&done); |
| 1769 } | 1866 } |
| 1770 return; | 1867 return; |
| 1771 } | 1868 } |
| 1772 | 1869 |
| 1773 if (NodeHasOnlyClass(node, smi_class_)) { | 1870 if (AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { |
| 1774 if (GenerateSmiComparison(node)) { | 1871 if (GenerateSmiComparison(node)) { |
| 1775 return; | 1872 return; |
| 1776 } | 1873 } |
| 1777 // Fall through if condition is not supported. | 1874 // Fall through if condition is not supported. |
| 1778 } else if (NodeHasOnlyClass(node, double_class_)) { | 1875 } else if (AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { |
| 1779 // Double comparison | 1876 // Double comparison |
| 1780 if (GenerateDoubleComparison(node)) { | 1877 if (GenerateDoubleComparison(node)) { |
| 1781 return; | 1878 return; |
| 1782 } | 1879 } |
| 1783 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { | 1880 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { |
| 1784 // Equality, not-equality comparison of any other type. | 1881 // Equality, not-equality comparison of any other type. |
| 1785 if (GenerateEqualityComparison(node)) { | 1882 if (GenerateEqualityComparison(node)) { |
| 1786 return; | 1883 return; |
| 1787 } | 1884 } |
| 1788 } | 1885 } |
| 1789 | 1886 |
| 1790 // Fall through here if a comparison was not implemented. | 1887 // Fall through here if a comparison was not implemented. |
| 1791 CodeGenerator::VisitComparisonNode(node); | 1888 CodeGenerator::VisitComparisonNode(node); |
| 1792 } | 1889 } |
| 1793 | 1890 |
| 1794 | 1891 |
| 1795 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { | 1892 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { |
| 1796 const char* kMessage = "Inline indexed access"; | 1893 const char* kMessage = "Inline indexed access"; |
| 1797 ObjectStore* object_store = Isolate::Current()->object_store(); | 1894 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 1798 const Class& object_array_class = | 1895 const Class& object_array_class = |
| 1799 Class::ZoneHandle(object_store->array_class()); | 1896 Class::ZoneHandle(object_store->array_class()); |
| 1800 const Class& immutable_object_array_class = | 1897 const Class& immutable_object_array_class = |
| 1801 Class::ZoneHandle(object_store->immutable_array_class()); | 1898 Class::ZoneHandle(object_store->immutable_array_class()); |
| 1802 if (NodeHasOnlyClass(node, object_array_class) || | 1899 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class) || |
| 1803 NodeHasOnlyClass(node, immutable_object_array_class)) { | 1900 AtIdNodeHasOnlyClass(node, node->id(), immutable_object_array_class)) { |
| 1804 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); | 1901 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); |
| 1805 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX, EDX); | 1902 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX, EDX); |
| 1806 const Class& test_class = NodeHasOnlyClass(node, object_array_class) ? | 1903 const Class& test_class = |
| 1807 object_array_class : immutable_object_array_class; | 1904 AtIdNodeHasOnlyClass(node, node->id(), object_array_class) ? |
| 1905 object_array_class : immutable_object_array_class; | |
| 1808 // Type checks of array. | 1906 // Type checks of array. |
| 1809 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. | 1907 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. |
| 1810 __ j(ZERO, deopt_blob->label()); | 1908 __ j(ZERO, deopt_blob->label()); |
| 1811 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 1909 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 1812 __ CompareObject(EAX, test_class); | 1910 __ CompareObject(EAX, test_class); |
| 1813 __ j(NOT_EQUAL, deopt_blob->label()); | 1911 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1814 | 1912 |
| 1815 // Type check of index. | 1913 // Type check of index. |
| 1816 __ testl(EDX, Immediate(kSmiTagMask)); | 1914 __ testl(EDX, Immediate(kSmiTagMask)); |
| 1817 __ j(NOT_ZERO, deopt_blob->label()); | 1915 __ j(NOT_ZERO, deopt_blob->label()); |
| 1818 // Range check. | 1916 // Range check. |
| 1819 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); | 1917 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); |
| 1820 __ j(ABOVE_EQUAL, deopt_blob->label()); | 1918 __ j(ABOVE_EQUAL, deopt_blob->label()); |
| 1821 // Note that EDX is Smi, i.e, times 2. | 1919 // Note that EDX is Smi, i.e, times 2. |
| 1822 ASSERT(kSmiTagShift == 1); | 1920 ASSERT(kSmiTagShift == 1); |
| 1823 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); | 1921 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); |
| 1824 if (CodeGenerator::IsResultNeeded(node)) { | 1922 if (CodeGenerator::IsResultNeeded(node)) { |
| 1825 __ pushl(EAX); | 1923 __ pushl(EAX); |
| 1826 } | 1924 } |
| 1827 TraceOpt(node, kMessage); | 1925 TraceOpt(node, kMessage); |
| 1828 return; | 1926 return; |
| 1829 } | 1927 } |
| 1830 | 1928 |
| 1831 const String& growable_object_array_class_name = String::Handle( | 1929 const String& growable_object_array_class_name = String::Handle( |
| 1832 String::NewSymbol(kGrowableArrayClassName)); | 1930 String::NewSymbol(kGrowableArrayClassName)); |
| 1833 const Class& growable_array_class = Class::ZoneHandle( | 1931 const Class& growable_array_class = Class::ZoneHandle( |
| 1834 Library::Handle(Library::CoreImplLibrary()). | 1932 Library::Handle(Library::CoreImplLibrary()). |
| 1835 LookupClass(growable_object_array_class_name)); | 1933 LookupClass(growable_object_array_class_name)); |
| 1836 if (NodeHasOnlyClass(node, growable_array_class)) { | 1934 if (AtIdNodeHasOnlyClass(node, node->id(), growable_array_class)) { |
| 1837 const String& growable_array_length_field_name = | 1935 const String& growable_array_length_field_name = |
| 1838 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); | 1936 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); |
| 1839 const String& growable_array_array_field_name = | 1937 const String& growable_array_array_field_name = |
| 1840 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); | 1938 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); |
| 1841 intptr_t length_offset = GetFieldOffset(growable_array_class, | 1939 intptr_t length_offset = GetFieldOffset(growable_array_class, |
| 1842 growable_array_length_field_name); | 1940 growable_array_length_field_name); |
| 1843 intptr_t array_offset = GetFieldOffset(growable_array_class, | 1941 intptr_t array_offset = GetFieldOffset(growable_array_class, |
| 1844 growable_array_array_field_name); | 1942 growable_array_array_field_name); |
| 1845 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); | 1943 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); |
| 1846 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EAX); | 1944 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EAX); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 1875 void OptimizingCodeGenerator::VisitStoreIndexedNode(StoreIndexedNode* node) { | 1973 void OptimizingCodeGenerator::VisitStoreIndexedNode(StoreIndexedNode* node) { |
| 1876 if (FLAG_enable_type_checks) { | 1974 if (FLAG_enable_type_checks) { |
| 1877 CodeGenerator::VisitStoreIndexedNode(node); | 1975 CodeGenerator::VisitStoreIndexedNode(node); |
| 1878 return; | 1976 return; |
| 1879 } | 1977 } |
| 1880 node->array()->Visit(this); | 1978 node->array()->Visit(this); |
| 1881 // TODO(srdjan): Use VisitLoadTwo and check if index is smi (CodeGenInfo). | 1979 // TODO(srdjan): Use VisitLoadTwo and check if index is smi (CodeGenInfo). |
| 1882 ObjectStore* object_store = Isolate::Current()->object_store(); | 1980 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 1883 const Class& object_array_class = | 1981 const Class& object_array_class = |
| 1884 Class::ZoneHandle(object_store->array_class()); | 1982 Class::ZoneHandle(object_store->array_class()); |
| 1885 if (NodeHasOnlyClass(node, object_array_class)) { | 1983 if (AtIdNodeHasOnlyClass(node, node->id(), object_array_class)) { |
| 1886 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); | 1984 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); |
| 1887 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EBX, ECX); | 1985 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EBX, ECX); |
| 1888 __ popl(EAX); // array. | 1986 __ popl(EAX); // array. |
| 1889 // ECX: value, EBX:index, EAX: array. | 1987 // ECX: value, EBX:index, EAX: array. |
| 1890 // Check type of array. | 1988 // Check type of array. |
| 1891 __ testl(EAX, Immediate(kSmiTagMask)); | 1989 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1892 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. | 1990 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. |
| 1893 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); | 1991 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); |
| 1894 __ CompareObject(EDX, object_array_class); | 1992 __ CompareObject(EDX, object_array_class); |
| 1895 __ j(NOT_EQUAL, deopt_blob->label()); // Not ObjectArray -> deopt. | 1993 __ 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(), | 2289 node->function_name(), |
| 2192 num_arguments, | 2290 num_arguments, |
| 2193 num_named_arguments)); | 2291 num_named_arguments)); |
| 2194 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); | 2292 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); |
| 2195 if (FLAG_trace_optimization) { | 2293 if (FLAG_trace_optimization) { |
| 2196 OS::Print("Monomorphic inline candidate: %s -> %s\n", | 2294 OS::Print("Monomorphic inline candidate: %s -> %s\n", |
| 2197 target.ToFullyQualifiedCString(), | 2295 target.ToFullyQualifiedCString(), |
| 2198 Recognizer::KindToCString(recognized)); | 2296 Recognizer::KindToCString(recognized)); |
| 2199 } | 2297 } |
| 2200 if ((recognized == Recognizer::kIntegerToDouble) && | 2298 if ((recognized == Recognizer::kIntegerToDouble) && |
| 2201 NodeHasOnlyClass(node, smi_class_)) { | 2299 AtIdNodeHasOnlyClass(node, node->id(), smi_class_)) { |
| 2202 // TODO(srdjan): Check if we could use temporary double instead of | 2300 // TODO(srdjan): Check if we could use temporary double instead of |
| 2203 // allocating a new object every time. | 2301 // allocating a new object every time. |
| 2204 const Code& stub = | 2302 const Code& stub = |
| 2205 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 2303 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 2206 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 2304 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 2207 GenerateCall(node->token_index(), &label); | 2305 GenerateCall(node->token_index(), &label); |
| 2208 // EAX is double object. | 2306 // EAX is double object. |
| 2209 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); | 2307 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); |
| 2210 __ popl(EBX); // Receiver | 2308 __ popl(EBX); // Receiver |
| 2211 __ testl(EBX, Immediate(kSmiTagMask)); | 2309 __ testl(EBX, Immediate(kSmiTagMask)); |
| 2212 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. | 2310 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. |
| 2213 __ SmiUntag(EBX); | 2311 __ SmiUntag(EBX); |
| 2214 __ cvtsi2sd(XMM0, EBX); | 2312 __ cvtsi2sd(XMM0, EBX); |
| 2215 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 2313 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 2216 return true; | 2314 return true; |
| 2217 } | 2315 } |
| 2218 | 2316 |
| 2219 if ((recognized == Recognizer::kDoubleToDouble) && | 2317 if ((recognized == Recognizer::kDoubleToDouble) && |
| 2220 NodeHasOnlyClass(node, double_class_)) { | 2318 AtIdNodeHasOnlyClass(node, node->id(), double_class_)) { |
| 2221 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX); | 2319 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX); |
| 2222 __ popl(EAX); | 2320 __ popl(EAX); |
| 2223 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); | 2321 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); |
| 2224 return true; | 2322 return true; |
| 2225 } | 2323 } |
| 2226 } | 2324 } |
| 2227 return false; | 2325 return false; |
| 2228 } | 2326 } |
| 2229 | 2327 |
| 2230 | 2328 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2271 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); | 2369 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); |
| 2272 // Result is in EAX. | 2370 // Result is in EAX. |
| 2273 if (IsResultNeeded(node)) { | 2371 if (IsResultNeeded(node)) { |
| 2274 __ pushl(EAX); | 2372 __ pushl(EAX); |
| 2275 } | 2373 } |
| 2276 } | 2374 } |
| 2277 | 2375 |
| 2278 } // namespace dart | 2376 } // namespace dart |
| 2279 | 2377 |
| 2280 #endif // defined TARGET_ARCH_IA32 | 2378 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |