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

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) {
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
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 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
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
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
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
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
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
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