| 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 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 282 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 283 Class& cls = Class::ZoneHandle(); | 283 Class& cls = Class::ZoneHandle(); |
| 284 ic_data.GetOneClassCheckAt(i, &cls, &target); | 284 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 285 result->Add(&cls); | 285 result->Add(&cls); |
| 286 } | 286 } |
| 287 return result; | 287 return result; |
| 288 } | 288 } |
| 289 | 289 |
| 290 | 290 |
| 291 // Debugging helper function. | 291 // Debugging helper function. |
| 292 void OptimizingCodeGenerator::PrintCollectedClasses(AstNode* node) { | 292 void OptimizingCodeGenerator::PrintCollectedClassesAtId(AstNode* node, |
| 293 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); | 293 intptr_t id) { |
| 294 for (intptr_t i = 0; i < classes->length(); i++) { | 294 const ICData& ic_data = node->ICDataAtId(id); |
| 295 OS::Print("- %s\n", (*classes)[i]->ToCString()); | 295 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 296 Function& target = Function::Handle(); |
| 297 Class& cls = Class::Handle(); |
| 298 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 299 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 300 OS::Print("- %s -> %s\n", cls.ToCString(), |
| 301 target.ToFullyQualifiedCString()); |
| 296 } | 302 } |
| 297 } | 303 } |
| 298 | 304 |
| 299 | 305 |
| 300 void OptimizingCodeGenerator::TraceOpt(AstNode* node, const char* message) { | 306 void OptimizingCodeGenerator::TraceOpt(AstNode* node, const char* message) { |
| 301 if (FLAG_trace_optimization) { | 307 if (FLAG_trace_optimization) { |
| 302 OS::Print("Opt node ix: %d; %s\n", node->token_index(), message); | 308 OS::Print("Opt node ix: %d; %s\n", node->token_index(), message); |
| 303 } | 309 } |
| 304 } | 310 } |
| 305 | 311 |
| (...skipping 795 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1101 } | 1107 } |
| 1102 if (node->prefix()) { | 1108 if (node->prefix()) { |
| 1103 __ pushl(EAX); | 1109 __ pushl(EAX); |
| 1104 } else { | 1110 } else { |
| 1105 __ pushl(ECX); | 1111 __ pushl(ECX); |
| 1106 } | 1112 } |
| 1107 } | 1113 } |
| 1108 } | 1114 } |
| 1109 | 1115 |
| 1110 | 1116 |
| 1117 // Debugging helper method, used in assert only. |
| 1118 static bool HaveSameClassesInICData(const ICData& a, const ICData& b) { |
| 1119 if (a.NumberOfChecks() != b.NumberOfChecks()) { |
| 1120 return false; |
| 1121 } |
| 1122 if (a.NumberOfChecks() == 0) { |
| 1123 return true; |
| 1124 } |
| 1125 if (a.NumberOfArgumentsChecked() != b.NumberOfArgumentsChecked()) { |
| 1126 return false; |
| 1127 } |
| 1128 // Only one-argument checks implemented. |
| 1129 ASSERT(a.NumberOfArgumentsChecked() == 1); |
| 1130 Function& a_target = Function::Handle(); |
| 1131 Function& b_target = Function::Handle(); |
| 1132 Class& a_class = Class::Handle(); |
| 1133 Class& b_class = Class::Handle(); |
| 1134 for (intptr_t i = 0; i < a.NumberOfChecks(); i++) { |
| 1135 a.GetOneClassCheckAt(i, &a_class, &a_target); |
| 1136 bool found = false; |
| 1137 for (intptr_t n = 0; n < b.NumberOfChecks(); n++) { |
| 1138 b.GetOneClassCheckAt(n, &b_class, &b_target); |
| 1139 if ((a_class.raw() == b_class.raw())) { |
| 1140 found = true; |
| 1141 break; |
| 1142 } |
| 1143 } |
| 1144 if (!found) { |
| 1145 return false; |
| 1146 } |
| 1147 } |
| 1148 return true; |
| 1149 } |
| 1150 |
| 1151 |
| 1111 void OptimizingCodeGenerator::VisitIncrOpInstanceFieldNode( | 1152 void OptimizingCodeGenerator::VisitIncrOpInstanceFieldNode( |
| 1112 IncrOpInstanceFieldNode* node) { | 1153 IncrOpInstanceFieldNode* node) { |
| 1113 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); | 1154 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); |
| 1114 VisitLoadOne(node->receiver(), EBX); | 1155 VisitLoadOne(node->receiver(), EBX); |
| 1115 __ pushl(EBX); // Duplicate receiver (preserve for setter). | 1156 __ pushl(EBX); // Duplicate receiver (preserve for setter). |
| 1116 const ICData& ic_data = node->ICDataAtId(node->id()); | 1157 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1117 if (ic_data.NumberOfChecks() == 0) { | 1158 if (ic_data.NumberOfChecks() == 0) { |
| 1118 // Deoptimization point for this node is after receiver has been | 1159 // Deoptimization point for this node is after receiver has been |
| 1119 // pushed twice on stack and before the getter (above) was executed. | 1160 // pushed twice on stack and before the getter (above) was executed. |
| 1120 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); | 1161 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1166 operator_name); | 1207 operator_name); |
| 1167 __ popl(EDX); // Restore receiver. | 1208 __ popl(EDX); // Restore receiver. |
| 1168 } | 1209 } |
| 1169 // EAX: Result of binary operation. | 1210 // EAX: Result of binary operation. |
| 1170 // EDX: receiver | 1211 // EDX: receiver |
| 1171 if (IsResultNeeded(node) && node->prefix()) { | 1212 if (IsResultNeeded(node) && node->prefix()) { |
| 1172 // Value stored into field is the result. | 1213 // Value stored into field is the result. |
| 1173 __ pushl(EAX); | 1214 __ pushl(EAX); |
| 1174 } | 1215 } |
| 1175 | 1216 |
| 1176 // TODO(srdjan): Inline instance setter. | 1217 // This can never deoptimize since the checks are the same as in getter. |
| 1177 __ pushl(EDX); // Receiver. | 1218 ASSERT(HaveSameClassesInICData(node->ICDataAtId(node->getter_id()), |
| 1178 __ pushl(EAX); // Value. | 1219 node->ICDataAtId(node->setter_id()))); |
| 1179 // It is not necessary to generate a type test of the assigned value here, | 1220 InlineInstanceSetter(node, |
| 1180 // because the setter will check the type of its incoming arguments. | 1221 node->setter_id(), |
| 1181 GenerateInstanceSetterCall(node->setter_id(), | 1222 node->receiver(), |
| 1182 node->token_index(), | 1223 node->field_name(), |
| 1183 node->field_name()); | 1224 EDX, // receiver |
| 1225 EAX); // value. |
| 1184 } | 1226 } |
| 1185 | 1227 |
| 1186 | 1228 |
| 1187 | 1229 |
| 1188 | 1230 |
| 1189 | 1231 |
| 1190 // Return offset of a field or -1 if field is not found. | 1232 // Return offset of a field or -1 if field is not found. |
| 1191 static intptr_t GetFieldOffset(const Class& field_class, | 1233 static intptr_t GetFieldOffset(const Class& field_class, |
| 1192 const String& field_name) { | 1234 const String& field_name) { |
| 1193 Class& cls = Class::Handle(field_class.raw()); | 1235 Class& cls = Class::Handle(field_class.raw()); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1229 return true; | 1271 return true; |
| 1230 } | 1272 } |
| 1231 | 1273 |
| 1232 | 1274 |
| 1233 // Emits code for an instance getter that has one or more collected classes, | 1275 // Emits code for an instance getter that has one or more collected classes, |
| 1234 // all with the same target. Deoptimizes for Smi or unexpected class. | 1276 // all with the same target. Deoptimizes for Smi or unexpected class. |
| 1235 // EBX: loaded receiver. | 1277 // EBX: loaded receiver. |
| 1236 // Result is returned in EAX. | 1278 // Result is returned in EAX. |
| 1237 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( | 1279 void OptimizingCodeGenerator::InlineInstanceGettersWithSameTarget( |
| 1238 AstNode* node, | 1280 AstNode* node, |
| 1281 intptr_t id, |
| 1239 AstNode* receiver, | 1282 AstNode* receiver, |
| 1240 const String& field_name, | 1283 const String& field_name, |
| 1241 Register recv_reg) { | 1284 Register recv_reg) { |
| 1242 if (recv_reg != EBX) { | 1285 if (recv_reg != EBX) { |
| 1243 // TODO(srdjan): Do not hardwire register. | 1286 // TODO(srdjan): Do not hardwire register. |
| 1244 UNIMPLEMENTED(); | 1287 UNIMPLEMENTED(); |
| 1245 } | 1288 } |
| 1246 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); | 1289 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EBX); |
| 1247 if (NodeMayBeSmi(receiver)) { | 1290 if (NodeMayBeSmi(receiver)) { |
| 1248 __ testl(EBX, Immediate(kSmiTagMask)); | 1291 __ testl(EBX, Immediate(kSmiTagMask)); |
| 1249 __ j(ZERO, deopt_blob->label()); | 1292 __ j(ZERO, deopt_blob->label()); |
| 1250 } | 1293 } |
| 1251 | 1294 |
| 1252 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 1295 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 1253 const ICData& ic_data = node->ICDataAtId(node->id()); | 1296 const ICData& ic_data = node->ICDataAtId(id); |
| 1254 Function& target = Function::Handle(); | 1297 Function& target = Function::Handle(); |
| 1255 Label load_field; | 1298 Label load_field; |
| 1256 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 1299 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 1257 Class& cls = Class::ZoneHandle(); | 1300 Class& cls = Class::ZoneHandle(); |
| 1258 ic_data.GetOneClassCheckAt(i, &cls, &target); | 1301 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 1259 __ CompareObject(EAX, cls); | 1302 __ CompareObject(EAX, cls); |
| 1260 if (i == (ic_data.NumberOfChecks() - 1)) { | 1303 if (i == (ic_data.NumberOfChecks() - 1)) { |
| 1261 __ j(NOT_EQUAL, deopt_blob->label()); | 1304 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1262 } else { | 1305 } else { |
| 1263 __ j(EQUAL, &load_field, Assembler::kNearJump); | 1306 __ j(EQUAL, &load_field, Assembler::kNearJump); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1287 TraceOpt(node, "Inlines GrowableObjectArray.length"); | 1330 TraceOpt(node, "Inlines GrowableObjectArray.length"); |
| 1288 intptr_t field_offset = GetFieldOffset( | 1331 intptr_t field_offset = GetFieldOffset( |
| 1289 cls, | 1332 cls, |
| 1290 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName))); | 1333 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName))); |
| 1291 __ movl(EAX, FieldAddress(EBX, field_offset)); | 1334 __ movl(EAX, FieldAddress(EBX, field_offset)); |
| 1292 return; | 1335 return; |
| 1293 } | 1336 } |
| 1294 default: | 1337 default: |
| 1295 UNIMPLEMENTED(); | 1338 UNIMPLEMENTED(); |
| 1296 } | 1339 } |
| 1340 UNREACHABLE(); |
| 1297 } | 1341 } |
| 1298 | 1342 |
| 1299 | 1343 |
| 1300 bool OptimizingCodeGenerator::IsInlineableInstanceGetter( | 1344 static bool IsInlineableInstanceGetter(const Function& function) { |
| 1301 const Function& function) { | |
| 1302 if (function.kind() == RawFunction::kImplicitGetter) { | 1345 if (function.kind() == RawFunction::kImplicitGetter) { |
| 1303 return true; | 1346 return true; |
| 1304 } | 1347 } |
| 1305 Recognizer::Kind recognized = Recognizer::RecognizeKind(function); | 1348 Recognizer::Kind recognized = Recognizer::RecognizeKind(function); |
| 1306 if ((recognized == Recognizer::kObjectArrayLength) || | 1349 if ((recognized == Recognizer::kObjectArrayLength) || |
| 1307 (recognized == Recognizer::kGrowableArrayLength)) { | 1350 (recognized == Recognizer::kGrowableArrayLength)) { |
| 1308 return true; | 1351 return true; |
| 1309 } | 1352 } |
| 1310 return false; | 1353 return false; |
| 1311 } | 1354 } |
| 1312 | 1355 |
| 1313 | 1356 |
| 1314 // Return true if all targets in 'ic_data' point to same | 1357 // Return the unique target of all checks or null. |
| 1315 // inlineable getter target. | 1358 static RawFunction* GetUniqueTarget(const ICData& ic_data) { |
| 1316 bool OptimizingCodeGenerator::ICDataToSameInlineableInstanceGetter( | |
| 1317 const ICData& ic_data) { | |
| 1318 Function& prev_target = Function::Handle(); | 1359 Function& prev_target = Function::Handle(); |
| 1319 Function& target = Function::Handle(); | 1360 Function& target = Function::Handle(); |
| 1320 Class& cls = Class::Handle(); | 1361 Class& cls = Class::Handle(); |
| 1321 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 1362 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 1322 ic_data.GetOneClassCheckAt(i, &cls, &target); | 1363 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 1323 ASSERT(!target.IsNull()); | 1364 ASSERT(!target.IsNull()); |
| 1324 if (!prev_target.IsNull() && (prev_target.raw() != target.raw())) { | 1365 if (!prev_target.IsNull() && (prev_target.raw() != target.raw())) { |
| 1325 return false; | 1366 return Function::null(); |
| 1326 } | 1367 } |
| 1327 prev_target = target.raw(); | 1368 prev_target = target.raw(); |
| 1328 if (!IsInlineableInstanceGetter(target)) { | |
| 1329 return false; | |
| 1330 } | |
| 1331 } | 1369 } |
| 1332 return true; | 1370 return target.raw(); |
| 1371 } |
| 1372 |
| 1373 |
| 1374 // Return true if all targets in 'ic_data' point to same |
| 1375 // inlineable getter target. |
| 1376 static bool ICDataToSameInlineableInstanceGetter(const ICData& ic_data) { |
| 1377 const Function& target = Function::Handle(GetUniqueTarget(ic_data)); |
| 1378 return !target.IsNull() && IsInlineableInstanceGetter(target); |
| 1379 } |
| 1380 |
| 1381 |
| 1382 // Return true if all targets in 'ic_data' point to same |
| 1383 // inlineable getter target. |
| 1384 static bool ICDataToSameInlineableInstanceSetter(const ICData& ic_data) { |
| 1385 const Function& target = Function::Handle(GetUniqueTarget(ic_data)); |
| 1386 return !target.IsNull() && (target.kind() == RawFunction::kImplicitSetter); |
| 1333 } | 1387 } |
| 1334 | 1388 |
| 1335 | 1389 |
| 1336 void OptimizingCodeGenerator::InlineInstanceGetter(AstNode* node, | 1390 void OptimizingCodeGenerator::InlineInstanceGetter(AstNode* node, |
| 1337 intptr_t id, | 1391 intptr_t id, |
| 1338 AstNode* receiver, | 1392 AstNode* receiver, |
| 1339 const String& field_name, | 1393 const String& field_name, |
| 1340 Register recv_reg) { | 1394 Register recv_reg) { |
| 1341 if (ICDataToSameInlineableInstanceGetter(node->ICDataAtId(id))) { | 1395 if (ICDataToSameInlineableInstanceGetter(node->ICDataAtId(id))) { |
| 1342 InlineInstanceGettersWithSameTarget(node, receiver, field_name, recv_reg); | 1396 InlineInstanceGettersWithSameTarget(node, |
| 1397 id, |
| 1398 receiver, |
| 1399 field_name, |
| 1400 recv_reg); |
| 1343 } else { | 1401 } else { |
| 1344 // TODO(srdjan): Inline access. | 1402 // TODO(srdjan): Inline access. |
| 1345 __ pushl(recv_reg); | 1403 __ pushl(recv_reg); |
| 1346 const int kNumberOfArguments = 1; | 1404 const int kNumberOfArguments = 1; |
| 1347 const Array& kNoArgumentNames = Array::Handle(); | 1405 const Array& kNoArgumentNames = Array::Handle(); |
| 1348 GenerateCheckedInstanceCalls(node, | 1406 GenerateCheckedInstanceCalls(node, |
| 1349 receiver, | 1407 receiver, |
| 1350 node->id(), | 1408 id, |
| 1351 node->token_index(), | 1409 node->token_index(), |
| 1352 kNumberOfArguments, | 1410 kNumberOfArguments, |
| 1353 kNoArgumentNames); | 1411 kNoArgumentNames); |
| 1354 } | 1412 } |
| 1355 } | 1413 } |
| 1356 | 1414 |
| 1357 | 1415 |
| 1358 // TODO(srdjan): Implement for multiple getter targets. | 1416 // TODO(srdjan): Implement for multiple getter targets. |
| 1359 // For every class inline its implicit getter, or call the instance getter. | 1417 // For every class inline its implicit getter, or call the instance getter. |
| 1360 void OptimizingCodeGenerator::VisitInstanceGetterNode( | 1418 void OptimizingCodeGenerator::VisitInstanceGetterNode( |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1374 node->receiver(), | 1432 node->receiver(), |
| 1375 node->field_name(), | 1433 node->field_name(), |
| 1376 EBX); | 1434 EBX); |
| 1377 // Result is in EAX. | 1435 // Result is in EAX. |
| 1378 if (CodeGenerator::IsResultNeeded(node)) { | 1436 if (CodeGenerator::IsResultNeeded(node)) { |
| 1379 __ pushl(EAX); | 1437 __ pushl(EAX); |
| 1380 } | 1438 } |
| 1381 } | 1439 } |
| 1382 | 1440 |
| 1383 | 1441 |
| 1442 // Clobber EBX leave 'value_reg' untouched. |
| 1443 void OptimizingCodeGenerator::InlineInstanceSettersWithSameTarget( |
| 1444 AstNode* node, |
| 1445 intptr_t id, |
| 1446 AstNode* receiver, |
| 1447 const String& field_name, |
| 1448 Register recv_reg, |
| 1449 Register value_reg) { |
| 1450 ASSERT((recv_reg != EBX) && (value_reg != EBX)); |
| 1451 DeoptimizationBlob* deopt_blob = |
| 1452 AddDeoptimizationBlob(node, recv_reg, value_reg); |
| 1453 if (NodeMayBeSmi(receiver)) { |
| 1454 __ testl(recv_reg, Immediate(kSmiTagMask)); |
| 1455 __ j(ZERO, deopt_blob->label()); |
| 1456 } |
| 1457 __ movl(EBX, FieldAddress(recv_reg, Object::class_offset())); |
| 1458 const ICData& ic_data = node->ICDataAtId(id); |
| 1459 Function& target = Function::Handle(); |
| 1460 Label store_field; |
| 1461 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 1462 Class& cls = Class::ZoneHandle(); |
| 1463 ic_data.GetOneClassCheckAt(i, &cls, &target); |
| 1464 __ CompareObject(EBX, cls); |
| 1465 if (i == (ic_data.NumberOfChecks() - 1)) { |
| 1466 __ j(NOT_EQUAL, deopt_blob->label()); |
| 1467 } else { |
| 1468 __ j(EQUAL, &store_field, Assembler::kNearJump); |
| 1469 } |
| 1470 } |
| 1471 Class& cls = Class::Handle(); |
| 1472 ic_data.GetOneClassCheckAt(0, &cls, &target); |
| 1473 |
| 1474 __ Bind(&store_field); |
| 1475 ASSERT(target.kind() == RawFunction::kImplicitSetter); |
| 1476 intptr_t field_offset = GetFieldOffset(cls, field_name); |
| 1477 ASSERT(field_offset >= 0); |
| 1478 __ StoreIntoObject(recv_reg, FieldAddress(recv_reg, field_offset), value_reg); |
| 1479 } |
| 1480 |
| 1481 |
| 1482 // Returns value in 'value_reg'. |
| 1483 void OptimizingCodeGenerator::InlineInstanceSetter(AstNode* node, |
| 1484 intptr_t id, |
| 1485 AstNode* receiver, |
| 1486 const String& field_name, |
| 1487 Register recv_reg, |
| 1488 Register value_reg) { |
| 1489 if (ICDataToSameInlineableInstanceSetter(node->ICDataAtId(id))) { |
| 1490 InlineInstanceSettersWithSameTarget(node, |
| 1491 id, |
| 1492 receiver, |
| 1493 field_name, |
| 1494 recv_reg, |
| 1495 value_reg); |
| 1496 } else { |
| 1497 UNIMPLEMENTED(); |
| 1498 } |
| 1499 } |
| 1500 |
| 1501 |
| 1384 // The call to the instance setter implements the assignment to a field. | 1502 // The call to the instance setter implements the assignment to a field. |
| 1385 // The result of the assignment to a field is the value being stored. | 1503 // The result of the assignment to a field is the value being stored. |
| 1386 void OptimizingCodeGenerator::VisitInstanceSetterNode( | 1504 void OptimizingCodeGenerator::VisitInstanceSetterNode( |
| 1387 InstanceSetterNode* node) { | 1505 InstanceSetterNode* node) { |
| 1388 if (FLAG_enable_type_checks) { | 1506 // TODO(srdjan): inline setters to different targets as well. |
| 1507 if (FLAG_enable_type_checks || |
| 1508 !ICDataToSameInlineableInstanceSetter(node->ICDataAtId(node->id()))) { |
| 1389 CodeGenerator::VisitInstanceSetterNode(node); | 1509 CodeGenerator::VisitInstanceSetterNode(node); |
| 1390 return; | 1510 return; |
| 1391 } | 1511 } |
| 1392 const char* kMessage = "Inline instance setter"; | 1512 VisitLoadTwo(node->receiver(), node->value(), EDX, EAX); |
| 1393 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); | 1513 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1394 if ((classes == NULL) || classes->is_empty()) { | 1514 if (ic_data.NumberOfChecks() == 0) { |
| 1395 // Type feedback not yet collected. | 1515 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EAX); |
| 1396 TraceNotOpt(node, kMessage); | 1516 __ jmp(deopt_blob->label()); |
| 1397 CodeGenerator::VisitInstanceSetterNode(node); | |
| 1398 return; | 1517 return; |
| 1399 } | 1518 } |
| 1400 const int num_classes = classes->length(); | 1519 // Value in EAX survives and will be stored on stack if result is needed. |
| 1401 bool all_inlineable = true; | 1520 InlineInstanceSetter(node, |
| 1402 const String& setter_name = | 1521 node->id(), |
| 1403 String::Handle(Field::SetterName(node->field_name())); | 1522 node->receiver(), |
| 1404 if (FLAG_trace_optimization) { | 1523 node->field_name(), |
| 1405 OS::Print("Setter: %s ", setter_name.ToCString()); | 1524 EDX, |
| 1406 } | 1525 EAX); |
| 1407 // TODO(srdjan): Replace simple heuristic expecting that all setters | |
| 1408 // for a call-site must be inlineable or none will be inlined. | |
| 1409 for (intptr_t i = 0; i < num_classes; i++) { | |
| 1410 const Class& cls = *(*classes)[i]; | |
| 1411 const int kNumArguments = 2; | |
| 1412 const int kNumNamedArguments = 0; | |
| 1413 const Function& target = Function::ZoneHandle( | |
| 1414 Resolver::ResolveDynamicForReceiverClass(cls, | |
| 1415 setter_name, | |
| 1416 kNumArguments, | |
| 1417 kNumNamedArguments)); | |
| 1418 ASSERT(!target.IsNull()); | |
| 1419 if (target.kind() != RawFunction::kImplicitSetter) { | |
| 1420 all_inlineable = false; | |
| 1421 break; | |
| 1422 } | |
| 1423 } | |
| 1424 | 1526 |
| 1425 // TODO(srdjan): Add an upper limit to number of class tests. | |
| 1426 if ((classes == NULL) || (num_classes == 0) || !all_inlineable) { | |
| 1427 TraceNotOpt(node, kMessage); | |
| 1428 CodeGenerator::VisitInstanceSetterNode(node); | |
| 1429 return; | |
| 1430 } | |
| 1431 | |
| 1432 TraceOpt(node, kMessage); | |
| 1433 // Inline setter(s). | |
| 1434 VisitLoadTwo(node->receiver(), node->value(), EAX, EDX); | |
| 1435 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EAX, EDX); | |
| 1436 // Smi causes deoptimization. | |
| 1437 if (NodeMayBeSmi(node->receiver())) { | |
| 1438 __ testl(EAX, Immediate(kSmiTagMask)); | |
| 1439 __ j(ZERO, deopt_blob->label()); | |
| 1440 } | |
| 1441 __ movl(EBX, FieldAddress(EAX, Object::class_offset())); | |
| 1442 // EAX: receiver, EBX: receiver's class, EDX: value. | |
| 1443 | |
| 1444 | |
| 1445 Label done; | |
| 1446 for (int i = 0; i < num_classes; i++) { | |
| 1447 intptr_t field_offset = GetFieldOffset(*(*classes)[i], | |
| 1448 node->field_name()); | |
| 1449 ASSERT(field_offset >= 0); | |
| 1450 const Class& cls = *(*classes)[i]; | |
| 1451 __ CompareObject(EBX, cls); | |
| 1452 if (i != (num_classes - 1)) { | |
| 1453 Label next_test; | |
| 1454 __ j(NOT_EQUAL, &next_test); | |
| 1455 __ StoreIntoObject(EAX, FieldAddress(EAX, field_offset), EDX); | |
| 1456 __ jmp(&done); | |
| 1457 __ Bind(&next_test); | |
| 1458 } else { | |
| 1459 // If last check fails deoptimize, otherwise store and fall through. | |
| 1460 __ j(NOT_EQUAL, deopt_blob->label()); | |
| 1461 __ StoreIntoObject(EAX, FieldAddress(EAX, field_offset), EDX); | |
| 1462 } | |
| 1463 } | |
| 1464 __ Bind(&done); | |
| 1465 if (CodeGenerator::IsResultNeeded(node)) { | 1527 if (CodeGenerator::IsResultNeeded(node)) { |
| 1466 __ pushl(EDX); | 1528 __ pushl(EAX); |
| 1467 } | 1529 } |
| 1468 } | 1530 } |
| 1469 | 1531 |
| 1470 | 1532 |
| 1471 | |
| 1472 // Return false if condition is not supported. | 1533 // Return false if condition is not supported. |
| 1473 static bool SupportedTokenKindToSmiCondition(Token::Kind kind, | 1534 static bool SupportedTokenKindToSmiCondition(Token::Kind kind, |
| 1474 Condition* condition) { | 1535 Condition* condition) { |
| 1475 switch (kind) { | 1536 switch (kind) { |
| 1476 case Token::kEQ: | 1537 case Token::kEQ: |
| 1477 *condition = EQUAL; | 1538 *condition = EQUAL; |
| 1478 return true; | 1539 return true; |
| 1479 case Token::kNE: | 1540 case Token::kNE: |
| 1480 *condition = NOT_EQUAL; | 1541 *condition = NOT_EQUAL; |
| 1481 return true; | 1542 return true; |
| (...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2378 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); | 2439 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); |
| 2379 // Result is in EAX. | 2440 // Result is in EAX. |
| 2380 if (IsResultNeeded(node)) { | 2441 if (IsResultNeeded(node)) { |
| 2381 __ pushl(EAX); | 2442 __ pushl(EAX); |
| 2382 } | 2443 } |
| 2383 } | 2444 } |
| 2384 | 2445 |
| 2385 } // namespace dart | 2446 } // namespace dart |
| 2386 | 2447 |
| 2387 #endif // defined TARGET_ARCH_IA32 | 2448 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |