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

Side by Side Diff: vm/opt_code_generator_ia32.cc

Issue 8439023: Optimize 2/3 of instance field increment operation. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
Patch Set: '' Created 9 years, 1 month 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 | « vm/opt_code_generator_ia32.h ('k') | no next file » | 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) 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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « vm/opt_code_generator_ia32.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698