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

Side by Side Diff: runtime/vm/opt_code_generator_ia32.cc

Issue 8439059: Restructure instance setter and finish the last 1/3 of increment instance field optimization. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
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 | « runtime/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 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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 (int i = 0; i < a.NumberOfChecks(); i++) {
siva 2011/11/03 17:02:29 In the loop above (printCollectedClassesAtId(...)
srdjan 2011/11/03 18:36:13 Done.
1135 a.GetOneClassCheckAt(i, &a_class, &a_target);
1136 bool found = false;
1137 for (int n = 0; n < b.NumberOfChecks(); n++) {
siva 2011/11/03 17:02:29 Ditto comment regarding intptr_t
srdjan 2011/11/03 18:36:13 Done.
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
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
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
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
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 // Returns stored value in 'value_reg'.
siva 2011/11/03 17:02:29 Should the comment say 'recv_reg' and 'value_reg'
srdjan 2011/11/03 18:36:13 Added Clobber EBX, 'value_reg' untouched. Don't ca
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 if ((recv_reg != EDX) || (value_reg != EAX)) {
1451 // TODO(srdjan): Do not hardwire register.
1452 UNIMPLEMENTED();
1453 }
siva 2011/11/03 17:02:29 Instead of this unimplemented why not just assert
srdjan 2011/11/03 18:36:13 Done.
1454 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EAX);
1455 if (NodeMayBeSmi(receiver)) {
1456 __ testl(EDX, Immediate(kSmiTagMask));
1457 __ j(ZERO, deopt_blob->label());
1458 }
1459 __ movl(EBX, FieldAddress(EDX, Object::class_offset()));
1460 const ICData& ic_data = node->ICDataAtId(id);
1461 Function& target = Function::Handle();
1462 Label store_field;
1463 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
1464 Class& cls = Class::ZoneHandle();
1465 ic_data.GetOneClassCheckAt(i, &cls, &target);
1466 __ CompareObject(EBX, cls);
1467 if (i == (ic_data.NumberOfChecks() - 1)) {
1468 __ j(NOT_EQUAL, deopt_blob->label());
1469 } else {
1470 __ j(EQUAL, &store_field, Assembler::kNearJump);
1471 }
1472 }
1473 Class& cls = Class::Handle();
1474 ic_data.GetOneClassCheckAt(0, &cls, &target);
1475
1476 __ Bind(&store_field);
1477 // EDX: receiver.
1478 // EAX: value
1479 ASSERT(target.kind() == RawFunction::kImplicitSetter);
1480 intptr_t field_offset = GetFieldOffset(cls, field_name);
1481 ASSERT(field_offset >= 0);
1482 __ StoreIntoObject(EDX, FieldAddress(EDX, field_offset), EAX);
1483 }
1484
1485
1486 // Returns value in 'value_reg'.
1487 void OptimizingCodeGenerator::InlineInstanceSetter(AstNode* node,
1488 intptr_t id,
1489 AstNode* receiver,
1490 const String& field_name,
1491 Register recv_reg,
1492 Register value_reg) {
1493 if (ICDataToSameInlineableInstanceSetter(node->ICDataAtId(id))) {
1494 InlineInstanceSettersWithSameTarget(node,
1495 id,
1496 receiver,
1497 field_name,
1498 recv_reg,
1499 value_reg);
1500 } else {
1501 UNIMPLEMENTED();
1502 }
1503 }
1504
1505
1384 // The call to the instance setter implements the assignment to a field. 1506 // 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. 1507 // The result of the assignment to a field is the value being stored.
1386 void OptimizingCodeGenerator::VisitInstanceSetterNode( 1508 void OptimizingCodeGenerator::VisitInstanceSetterNode(
1387 InstanceSetterNode* node) { 1509 InstanceSetterNode* node) {
1388 if (FLAG_enable_type_checks) { 1510 // TODO(srdjan): inline setters to different targets as well.
1511 if (FLAG_enable_type_checks ||
1512 !ICDataToSameInlineableInstanceSetter(node->ICDataAtId(node->id()))) {
1389 CodeGenerator::VisitInstanceSetterNode(node); 1513 CodeGenerator::VisitInstanceSetterNode(node);
1390 return; 1514 return;
1391 } 1515 }
1392 const char* kMessage = "Inline instance setter"; 1516 VisitLoadTwo(node->receiver(), node->value(), EDX, EAX);
1393 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); 1517 const ICData& ic_data = node->ICDataAtId(node->id());
1394 if ((classes == NULL) || classes->is_empty()) { 1518 if (ic_data.NumberOfChecks() == 0) {
1395 // Type feedback not yet collected. 1519 DeoptimizationBlob* deopt_blob = AddDeoptimizationBlob(node, EDX, EAX);
1396 TraceNotOpt(node, kMessage); 1520 __ jmp(deopt_blob->label());
1397 CodeGenerator::VisitInstanceSetterNode(node);
1398 return; 1521 return;
1399 } 1522 }
1400 const int num_classes = classes->length(); 1523 // Value in EAX survives and will be stored on stack if result is needed.
1401 bool all_inlineable = true; 1524 InlineInstanceSetter(node,
1402 const String& setter_name = 1525 node->id(),
1403 String::Handle(Field::SetterName(node->field_name())); 1526 node->receiver(),
1404 if (FLAG_trace_optimization) { 1527 node->field_name(),
1405 OS::Print("Setter: %s ", setter_name.ToCString()); 1528 EDX,
1406 } 1529 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 1530
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)) { 1531 if (CodeGenerator::IsResultNeeded(node)) {
1466 __ pushl(EDX); 1532 __ pushl(EAX);
1467 } 1533 }
1468 } 1534 }
1469 1535
1470 1536
1471
1472 // Return false if condition is not supported. 1537 // Return false if condition is not supported.
1473 static bool SupportedTokenKindToSmiCondition(Token::Kind kind, 1538 static bool SupportedTokenKindToSmiCondition(Token::Kind kind,
1474 Condition* condition) { 1539 Condition* condition) {
1475 switch (kind) { 1540 switch (kind) {
1476 case Token::kEQ: 1541 case Token::kEQ:
1477 *condition = EQUAL; 1542 *condition = EQUAL;
1478 return true; 1543 return true;
1479 case Token::kNE: 1544 case Token::kNE:
1480 *condition = NOT_EQUAL; 1545 *condition = NOT_EQUAL;
1481 return true; 1546 return true;
(...skipping 896 matching lines...) Expand 10 before | Expand all | Expand 10 after
2378 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); 2443 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize));
2379 // Result is in EAX. 2444 // Result is in EAX.
2380 if (IsResultNeeded(node)) { 2445 if (IsResultNeeded(node)) {
2381 __ pushl(EAX); 2446 __ pushl(EAX);
2382 } 2447 }
2383 } 2448 }
2384 2449
2385 } // namespace dart 2450 } // namespace dart
2386 2451
2387 #endif // defined TARGET_ARCH_IA32 2452 #endif // defined TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « runtime/vm/opt_code_generator_ia32.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698