| 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 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 if (node->info() != NULL) { | 556 if (node->info() != NULL) { |
| 557 const Class* cls = NULL; | 557 const Class* cls = NULL; |
| 558 classes_for_locals_->GetLocalClass(node->local(), &cls); | 558 classes_for_locals_->GetLocalClass(node->local(), &cls); |
| 559 if (cls != NULL) { | 559 if (cls != NULL) { |
| 560 node->info()->set_is_class(cls); | 560 node->info()->set_is_class(cls); |
| 561 } | 561 } |
| 562 } | 562 } |
| 563 } | 563 } |
| 564 | 564 |
| 565 | 565 |
| 566 void OptimizingCodeGenerator::HandleResult(AstNode* node, Register result_reg) { |
| 567 if (CodeGenerator::IsResultNeeded(node)) { |
| 568 if (IsResultInEaxRequested(node)) { |
| 569 if (result_reg != EAX) { |
| 570 __ movl(EAX, result_reg); |
| 571 } |
| 572 node->info()->set_result_returned_in_eax(true); |
| 573 } else { |
| 574 __ pushl(result_reg); |
| 575 } |
| 576 } |
| 577 } |
| 578 |
| 579 |
| 566 void OptimizingCodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { | 580 void OptimizingCodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { |
| 567 if (FLAG_enable_type_checks) { | 581 if (FLAG_enable_type_checks) { |
| 568 CodeGenerator::VisitStoreLocalNode(node); | 582 CodeGenerator::VisitStoreLocalNode(node); |
| 569 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); | 583 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
| 570 return; | 584 return; |
| 571 } | 585 } |
| 572 CodeGenInfo value_info(node->value()); | 586 CodeGenInfo value_info(node->value()); |
| 573 value_info.set_request_result_in_eax(true); | 587 value_info.set_request_result_in_eax(true); |
| 574 node->value()->Visit(this); | 588 node->value()->Visit(this); |
| 575 if (value_info.is_temp()) { | 589 if (value_info.is_temp()) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 588 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); | 602 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); |
| 589 } else { | 603 } else { |
| 590 UNIMPLEMENTED(); // Cannot handle other temporary types yet. | 604 UNIMPLEMENTED(); // Cannot handle other temporary types yet. |
| 591 } | 605 } |
| 592 } else { | 606 } else { |
| 593 if (!value_info.result_returned_in_eax()) { | 607 if (!value_info.result_returned_in_eax()) { |
| 594 __ popl(EAX); | 608 __ popl(EAX); |
| 595 } | 609 } |
| 596 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); | 610 CodeGenerator::GenerateStoreVariable(node->local(), EAX, EDX); |
| 597 } | 611 } |
| 598 if (IsResultNeeded(node)) { | 612 HandleResult(node, EAX); |
| 599 __ pushl(EAX); | |
| 600 } | |
| 601 classes_for_locals_->SetLocalType(node->local(), *value_info.is_class()); | 613 classes_for_locals_->SetLocalType(node->local(), *value_info.is_class()); |
| 602 } | 614 } |
| 603 | 615 |
| 604 | 616 |
| 605 static bool NodeHasBothReceiverClasses(AstNode* node, | 617 static bool NodeHasBothReceiverClasses(AstNode* node, |
| 606 const Class& cls1, | 618 const Class& cls1, |
| 607 const Class& cls2) { | 619 const Class& cls2) { |
| 608 ASSERT(node != NULL); | 620 ASSERT(node != NULL); |
| 609 ASSERT(!cls1.IsNull() && !cls2.IsNull()); | 621 ASSERT(!cls1.IsNull() && !cls2.IsNull()); |
| 610 const ICData& ic_data = node->ICDataAtId(node->id()); | 622 const ICData& ic_data = node->ICDataAtId(node->id()); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 802 __ testl(EAX, Immediate(kSmiTagMask)); | 814 __ testl(EAX, Immediate(kSmiTagMask)); |
| 803 __ j(NOT_ZERO, deopt_blob->label()); | 815 __ j(NOT_ZERO, deopt_blob->label()); |
| 804 if (node->kind() == Token::kSUB) { | 816 if (node->kind() == Token::kSUB) { |
| 805 __ negl(EAX); | 817 __ negl(EAX); |
| 806 __ j(OVERFLOW, deopt_blob->label()); | 818 __ j(OVERFLOW, deopt_blob->label()); |
| 807 } else { | 819 } else { |
| 808 ASSERT(node->kind() == Token::kBIT_NOT); | 820 ASSERT(node->kind() == Token::kBIT_NOT); |
| 809 __ notl(EAX); | 821 __ notl(EAX); |
| 810 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. | 822 __ andl(EAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag. |
| 811 } | 823 } |
| 812 if (CodeGenerator::IsResultNeeded(node)) { | 824 HandleResult(node, EAX); |
| 813 if (IsResultInEaxRequested(node)) { | |
| 814 node->info()->set_result_returned_in_eax(true); | |
| 815 } else { | |
| 816 __ pushl(EAX); | |
| 817 } | |
| 818 } | |
| 819 } | 825 } |
| 820 | 826 |
| 821 | 827 |
| 822 void OptimizingCodeGenerator::GenerateDoubleUnaryOp(UnaryOpNode* node) { | 828 void OptimizingCodeGenerator::GenerateDoubleUnaryOp(UnaryOpNode* node) { |
| 823 const Register kOperandRegister = ECX; | 829 const Register kOperandRegister = ECX; |
| 824 const Register kTempRegister = EBX; | 830 const Register kTempRegister = EBX; |
| 825 const Register kResultRegister = EAX; | 831 const Register kResultRegister = EAX; |
| 826 const ICData& ic_data = node->ICDataAtId(node->id()); | 832 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 827 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? | 833 DeoptReasonId deopt_reason_id = ic_data.NumberOfChecks() == 0 ? |
| 828 kDeoptNoTypeFeedback : kDeoptUnaryOp; | 834 kDeoptNoTypeFeedback : kDeoptUnaryOp; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 851 __ popl(kOperandRegister); | 857 __ popl(kOperandRegister); |
| 852 __ movsd(XMM0, FieldAddress(kOperandRegister, Double::value_offset())); | 858 __ movsd(XMM0, FieldAddress(kOperandRegister, Double::value_offset())); |
| 853 __ xorps(XMM1, XMM1); // 0.0 -> XMM1. | 859 __ xorps(XMM1, XMM1); // 0.0 -> XMM1. |
| 854 __ subsd(XMM1, XMM0); | 860 __ subsd(XMM1, XMM0); |
| 855 __ movsd(FieldAddress(kResultRegister, Double::value_offset()), XMM1); | 861 __ movsd(FieldAddress(kResultRegister, Double::value_offset()), XMM1); |
| 856 if (CodeGenerator::IsResultNeeded(node)) { | 862 if (CodeGenerator::IsResultNeeded(node)) { |
| 857 if (node->info() != NULL) { | 863 if (node->info() != NULL) { |
| 858 node->info()->set_is_temp(true); | 864 node->info()->set_is_temp(true); |
| 859 node->info()->set_is_class(&double_class_); | 865 node->info()->set_is_class(&double_class_); |
| 860 } | 866 } |
| 861 if (IsResultInEaxRequested(node)) { | 867 HandleResult(node, kResultRegister); |
| 862 ASSERT(kResultRegister == EAX); | |
| 863 node->info()->set_result_returned_in_eax(true); | |
| 864 } else { | |
| 865 __ pushl(kResultRegister); | |
| 866 } | |
| 867 } | 868 } |
| 868 } | 869 } |
| 869 | 870 |
| 870 | 871 |
| 871 // Handles only Smi & Smi. | 872 // Handles only Smi & Smi. |
| 872 // TODO(srdjan): Certain operations always overflow, and thus cause | 873 // TODO(srdjan): Certain operations always overflow, and thus cause |
| 873 // deoptimization. We need to mark those places and handle them. | 874 // deoptimization. We need to mark those places and handle them. |
| 874 void OptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node) { | 875 void OptimizingCodeGenerator::GenerateSmiBinaryOp(BinaryOpNode* node) { |
| 875 const char* kOptMessage = "Inlines BinaryOp for Smi"; | 876 const char* kOptMessage = "Inlines BinaryOp for Smi"; |
| 876 Label done; | 877 Label done; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 982 } else { | 983 } else { |
| 983 // Unhandled node kind. | 984 // Unhandled node kind. |
| 984 TraceNotOpt(node, kOptMessage); | 985 TraceNotOpt(node, kOptMessage); |
| 985 node->left()->Visit(this); | 986 node->left()->Visit(this); |
| 986 node->right()->Visit(this); | 987 node->right()->Visit(this); |
| 987 CodeGenerator::GenerateBinaryOperatorCall(node->id(), | 988 CodeGenerator::GenerateBinaryOperatorCall(node->id(), |
| 988 node->token_index(), | 989 node->token_index(), |
| 989 node->Name()); | 990 node->Name()); |
| 990 } | 991 } |
| 991 __ Bind(&done); | 992 __ Bind(&done); |
| 992 if (CodeGenerator::IsResultNeeded(node)) { | 993 HandleResult(node, EAX); |
| 993 if (IsResultInEaxRequested(node)) { | |
| 994 node->info()->set_result_returned_in_eax(true); | |
| 995 } else { | |
| 996 __ pushl(EAX); | |
| 997 } | |
| 998 } | |
| 999 } | 994 } |
| 1000 | 995 |
| 1001 | 996 |
| 1002 // Supports some mixed Smi/Mint operations. | 997 // Supports some mixed Smi/Mint operations. |
| 1003 // For BIT_AND operation with one operand being Smi, we can throw away | 998 // For BIT_AND operation with one operand being Smi, we can throw away |
| 1004 // any Mint bits above the Smi range. | 999 // any Mint bits above the Smi range. |
| 1005 // 'allow_smi' is true if Smi and Mint classes have been encountered. | 1000 // 'allow_smi' is true if Smi and Mint classes have been encountered. |
| 1006 void OptimizingCodeGenerator::GenerateMintBinaryOp(BinaryOpNode* node, | 1001 void OptimizingCodeGenerator::GenerateMintBinaryOp(BinaryOpNode* node, |
| 1007 bool allow_smi) { | 1002 bool allow_smi) { |
| 1008 const char* kOptMessage = "Inline Mint binop."; | 1003 const char* kOptMessage = "Inline Mint binop."; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1037 __ pushl(EDX); | 1032 __ pushl(EDX); |
| 1038 const int number_of_arguments = 2; | 1033 const int number_of_arguments = 2; |
| 1039 const Array& no_optional_argument_names = Array::Handle(); | 1034 const Array& no_optional_argument_names = Array::Handle(); |
| 1040 GenerateCheckedInstanceCalls(node, | 1035 GenerateCheckedInstanceCalls(node, |
| 1041 node->left(), | 1036 node->left(), |
| 1042 node->id(), | 1037 node->id(), |
| 1043 node->token_index(), | 1038 node->token_index(), |
| 1044 number_of_arguments, | 1039 number_of_arguments, |
| 1045 no_optional_argument_names); | 1040 no_optional_argument_names); |
| 1046 __ Bind(&done); | 1041 __ Bind(&done); |
| 1047 if (CodeGenerator::IsResultNeeded(node)) { | 1042 HandleResult(node, EAX); |
| 1048 __ pushl(EAX); | |
| 1049 } | |
| 1050 return; | 1043 return; |
| 1051 } | 1044 } |
| 1052 if ((kind == Token::kSHL) && allow_smi) { | 1045 if ((kind == Token::kSHL) && allow_smi) { |
| 1053 GenerateSmiShiftBinaryOp(node); | 1046 GenerateSmiShiftBinaryOp(node); |
| 1054 if (CodeGenerator::IsResultNeeded(node)) { | 1047 HandleResult(node, EAX); |
| 1055 __ pushl(EAX); | |
| 1056 } | |
| 1057 return; | 1048 return; |
| 1058 } | 1049 } |
| 1059 TraceNotOpt(node, kOptMessage); | 1050 TraceNotOpt(node, kOptMessage); |
| 1060 CodeGenerator::VisitBinaryOpNode(node); | 1051 CodeGenerator::VisitBinaryOpNode(node); |
| 1061 } | 1052 } |
| 1062 | 1053 |
| 1063 | 1054 |
| 1064 // Conservative approach: | 1055 // Conservative approach: |
| 1065 // - true if both nodes are LoadLocalNodes with the same index. | 1056 // - true if both nodes are LoadLocalNodes with the same index. |
| 1066 static bool AreNodesOfSameType(AstNode* a, AstNode* b) { | 1057 static bool AreNodesOfSameType(AstNode* a, AstNode* b) { |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1194 case Token::kMUL: __ mulsd(XMM0, XMM1); break; | 1185 case Token::kMUL: __ mulsd(XMM0, XMM1); break; |
| 1195 case Token::kDIV: __ divsd(XMM0, XMM1); break; | 1186 case Token::kDIV: __ divsd(XMM0, XMM1); break; |
| 1196 default: UNREACHABLE(); | 1187 default: UNREACHABLE(); |
| 1197 } | 1188 } |
| 1198 __ movsd(FieldAddress(result_register, Double::value_offset()), XMM0); | 1189 __ movsd(FieldAddress(result_register, Double::value_offset()), XMM0); |
| 1199 if (CodeGenerator::IsResultNeeded(node)) { | 1190 if (CodeGenerator::IsResultNeeded(node)) { |
| 1200 if (node->info() != NULL) { | 1191 if (node->info() != NULL) { |
| 1201 node->info()->set_is_temp(true); | 1192 node->info()->set_is_temp(true); |
| 1202 node->info()->set_is_class(&double_class_); | 1193 node->info()->set_is_class(&double_class_); |
| 1203 } | 1194 } |
| 1204 if (IsResultInEaxRequested(node)) { | 1195 HandleResult(node, result_register); |
| 1205 __ movl(EAX, result_register); | |
| 1206 node->info()->set_result_returned_in_eax(true); | |
| 1207 } else { | |
| 1208 __ pushl(result_register); | |
| 1209 } | |
| 1210 } | 1196 } |
| 1211 return; | 1197 return; |
| 1212 } | 1198 } |
| 1213 | 1199 |
| 1214 TraceNotOpt(node, kOptMessage); | 1200 TraceNotOpt(node, kOptMessage); |
| 1215 CodeGenerator::VisitBinaryOpNode(node); | 1201 CodeGenerator::VisitBinaryOpNode(node); |
| 1216 } | 1202 } |
| 1217 | 1203 |
| 1218 | 1204 |
| 1219 static bool NodeInfoHasLabels(AstNode* node) { | 1205 static bool NodeInfoHasLabels(AstNode* node) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1282 if (NodeInfoHasLabels(node)) { | 1268 if (NodeInfoHasLabels(node)) { |
| 1283 node->info()->set_labels_used(true); | 1269 node->info()->set_labels_used(true); |
| 1284 } else { | 1270 } else { |
| 1285 Label done; | 1271 Label done; |
| 1286 __ Bind(&return_true_object); | 1272 __ Bind(&return_true_object); |
| 1287 __ LoadObject(EAX, bool_true); | 1273 __ LoadObject(EAX, bool_true); |
| 1288 __ jmp(&done, Assembler::kNearJump); | 1274 __ jmp(&done, Assembler::kNearJump); |
| 1289 __ Bind(&return_false_object); | 1275 __ Bind(&return_false_object); |
| 1290 __ LoadObject(EAX, bool_false); | 1276 __ LoadObject(EAX, bool_false); |
| 1291 __ Bind(&done); | 1277 __ Bind(&done); |
| 1292 if (IsResultNeeded(node)) { | 1278 HandleResult(node, EAX); |
| 1293 __ pushl(EAX); | |
| 1294 } | |
| 1295 } | 1279 } |
| 1296 } | 1280 } |
| 1297 | 1281 |
| 1298 | 1282 |
| 1299 void OptimizingCodeGenerator::VisitBinaryOpNode(BinaryOpNode* node) { | 1283 void OptimizingCodeGenerator::VisitBinaryOpNode(BinaryOpNode* node) { |
| 1300 // Operators "&&" and "||" cannot be overloaded, therefore inline them | 1284 // Operators "&&" and "||" cannot be overloaded, therefore inline them |
| 1301 // instead of calling the operator. | 1285 // instead of calling the operator. |
| 1302 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { | 1286 if ((node->kind() == Token::kAND) || (node->kind() == Token::kOR)) { |
| 1303 if (FLAG_enable_type_checks) { | 1287 if (FLAG_enable_type_checks) { |
| 1304 CodeGenerator::VisitBinaryOpNode(node); | 1288 CodeGenerator::VisitBinaryOpNode(node); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1353 node->left()->Visit(this); | 1337 node->left()->Visit(this); |
| 1354 node->right()->Visit(this); | 1338 node->right()->Visit(this); |
| 1355 const int number_of_arguments = 2; | 1339 const int number_of_arguments = 2; |
| 1356 const Array& no_optional_argument_names = Array::Handle(); | 1340 const Array& no_optional_argument_names = Array::Handle(); |
| 1357 GenerateCheckedInstanceCalls(node, | 1341 GenerateCheckedInstanceCalls(node, |
| 1358 node->left(), | 1342 node->left(), |
| 1359 node->id(), | 1343 node->id(), |
| 1360 node->token_index(), | 1344 node->token_index(), |
| 1361 number_of_arguments, | 1345 number_of_arguments, |
| 1362 no_optional_argument_names); | 1346 no_optional_argument_names); |
| 1363 if (IsResultNeeded(node)) { | 1347 HandleResult(node, EAX); |
| 1364 __ pushl(EAX); | |
| 1365 } | |
| 1366 return; | 1348 return; |
| 1367 } | 1349 } |
| 1368 | 1350 |
| 1369 | 1351 |
| 1370 void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { | 1352 void OptimizingCodeGenerator::VisitIncrOpLocalNode(IncrOpLocalNode* node) { |
| 1371 if (FLAG_enable_type_checks) { | 1353 if (FLAG_enable_type_checks) { |
| 1372 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); | 1354 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
| 1373 CodeGenerator::VisitIncrOpLocalNode(node); | 1355 CodeGenerator::VisitIncrOpLocalNode(node); |
| 1374 return; | 1356 return; |
| 1375 } | 1357 } |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1732 return; | 1714 return; |
| 1733 } | 1715 } |
| 1734 | 1716 |
| 1735 VisitLoadOne(node->receiver(), EBX); | 1717 VisitLoadOne(node->receiver(), EBX); |
| 1736 InlineInstanceGetter(node, | 1718 InlineInstanceGetter(node, |
| 1737 node->id(), | 1719 node->id(), |
| 1738 node->receiver(), | 1720 node->receiver(), |
| 1739 node->field_name(), | 1721 node->field_name(), |
| 1740 EBX); | 1722 EBX); |
| 1741 // Result is in EAX. | 1723 // Result is in EAX. |
| 1742 if (CodeGenerator::IsResultNeeded(node)) { | 1724 HandleResult(node, EAX); |
| 1743 __ pushl(EAX); | |
| 1744 } | |
| 1745 } | 1725 } |
| 1746 | 1726 |
| 1747 | 1727 |
| 1748 // Helper struct to pass arguments to 'GenerateInstanceSetter'. | 1728 // Helper struct to pass arguments to 'GenerateInstanceSetter'. |
| 1749 struct InstanceSetterArgs { | 1729 struct InstanceSetterArgs { |
| 1750 const Class* cls; | 1730 const Class* cls; |
| 1751 const Function* target; | 1731 const Function* target; |
| 1752 const String* field_name; | 1732 const String* field_name; |
| 1753 Register recv_reg; | 1733 Register recv_reg; |
| 1754 Register value_reg; | 1734 Register value_reg; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1879 return; | 1859 return; |
| 1880 } | 1860 } |
| 1881 // Value in EAX survives and will be stored on stack if result is needed. | 1861 // Value in EAX survives and will be stored on stack if result is needed. |
| 1882 InlineInstanceSetter(node, | 1862 InlineInstanceSetter(node, |
| 1883 node->id(), | 1863 node->id(), |
| 1884 node->receiver(), | 1864 node->receiver(), |
| 1885 node->field_name(), | 1865 node->field_name(), |
| 1886 EDX, | 1866 EDX, |
| 1887 EAX); | 1867 EAX); |
| 1888 | 1868 |
| 1889 if (CodeGenerator::IsResultNeeded(node)) { | 1869 HandleResult(node, EAX); |
| 1890 __ pushl(EAX); | |
| 1891 } | |
| 1892 } | 1870 } |
| 1893 | 1871 |
| 1894 | 1872 |
| 1895 // Return false if condition is not supported. | 1873 // Return false if condition is not supported. |
| 1896 static bool SupportedTokenKindToSmiCondition(Token::Kind kind, | 1874 static bool SupportedTokenKindToSmiCondition(Token::Kind kind, |
| 1897 Condition* condition) { | 1875 Condition* condition) { |
| 1898 switch (kind) { | 1876 switch (kind) { |
| 1899 case Token::kEQ: | 1877 case Token::kEQ: |
| 1900 *condition = EQUAL; | 1878 *condition = EQUAL; |
| 1901 return true; | 1879 return true; |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2366 | 2344 |
| 2367 // Type check of index. | 2345 // Type check of index. |
| 2368 __ testl(EDX, Immediate(kSmiTagMask)); | 2346 __ testl(EDX, Immediate(kSmiTagMask)); |
| 2369 __ j(NOT_ZERO, deopt_blob->label()); | 2347 __ j(NOT_ZERO, deopt_blob->label()); |
| 2370 // Range check. | 2348 // Range check. |
| 2371 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); | 2349 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); |
| 2372 __ j(ABOVE_EQUAL, deopt_blob->label()); | 2350 __ j(ABOVE_EQUAL, deopt_blob->label()); |
| 2373 // Note that EDX is Smi, i.e, times 2. | 2351 // Note that EDX is Smi, i.e, times 2. |
| 2374 ASSERT(kSmiTagShift == 1); | 2352 ASSERT(kSmiTagShift == 1); |
| 2375 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); | 2353 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); |
| 2376 if (CodeGenerator::IsResultNeeded(node)) { | 2354 HandleResult(node, EAX); |
| 2377 __ pushl(EAX); | |
| 2378 } | |
| 2379 TraceOpt(node, kMessage); | 2355 TraceOpt(node, kMessage); |
| 2380 return; | 2356 return; |
| 2381 } | 2357 } |
| 2382 | 2358 |
| 2383 const String& growable_object_array_class_name = String::Handle( | 2359 const String& growable_object_array_class_name = String::Handle( |
| 2384 String::NewSymbol(kGrowableArrayClassName)); | 2360 String::NewSymbol(kGrowableArrayClassName)); |
| 2385 const Class& growable_array_class = Class::ZoneHandle( | 2361 const Class& growable_array_class = Class::ZoneHandle( |
| 2386 Library::Handle(Library::CoreImplLibrary()). | 2362 Library::Handle(Library::CoreImplLibrary()). |
| 2387 LookupClass(growable_object_array_class_name)); | 2363 LookupClass(growable_object_array_class_name)); |
| 2388 ASSERT(!growable_array_class.IsNull()); | 2364 ASSERT(!growable_array_class.IsNull()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2407 __ movl(EBX, FieldAddress(EDX, Object::class_offset())); | 2383 __ movl(EBX, FieldAddress(EDX, Object::class_offset())); |
| 2408 __ CompareObject(EBX, growable_array_class); | 2384 __ CompareObject(EBX, growable_array_class); |
| 2409 __ j(NOT_EQUAL, deopt_blob->label()); // Array is not GrowableObjectArray. | 2385 __ j(NOT_EQUAL, deopt_blob->label()); // Array is not GrowableObjectArray. |
| 2410 // Range check: deoptimize if out of bounds. | 2386 // Range check: deoptimize if out of bounds. |
| 2411 __ cmpl(EAX, FieldAddress(EDX, length_offset)); | 2387 __ cmpl(EAX, FieldAddress(EDX, length_offset)); |
| 2412 __ j(ABOVE_EQUAL, deopt_blob->label()); | 2388 __ j(ABOVE_EQUAL, deopt_blob->label()); |
| 2413 __ movl(EDX, FieldAddress(EDX, array_offset)); // backingArray. | 2389 __ movl(EDX, FieldAddress(EDX, array_offset)); // backingArray. |
| 2414 // Note that EAX is Smi, i.e, times 2. | 2390 // Note that EAX is Smi, i.e, times 2. |
| 2415 ASSERT(kSmiTagShift == 1); | 2391 ASSERT(kSmiTagShift == 1); |
| 2416 __ movl(EAX, FieldAddress(EDX, EAX, TIMES_2, sizeof(RawArray))); | 2392 __ movl(EAX, FieldAddress(EDX, EAX, TIMES_2, sizeof(RawArray))); |
| 2417 if (CodeGenerator::IsResultNeeded(node)) { | 2393 HandleResult(node, EAX); |
| 2418 __ pushl(EAX); | |
| 2419 } | |
| 2420 return; | 2394 return; |
| 2421 } else { | 2395 } else { |
| 2422 // E.g., HashMap. | 2396 // E.g., HashMap. |
| 2423 TraceNotOpt(node, kMessage); | 2397 TraceNotOpt(node, kMessage); |
| 2424 } | 2398 } |
| 2425 CodeGenerator::VisitLoadIndexedNode(node); | 2399 CodeGenerator::VisitLoadIndexedNode(node); |
| 2426 } | 2400 } |
| 2427 | 2401 |
| 2428 | 2402 |
| 2429 void OptimizingCodeGenerator::VisitStoreIndexedNode(StoreIndexedNode* node) { | 2403 void OptimizingCodeGenerator::VisitStoreIndexedNode(StoreIndexedNode* node) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2460 // Check class of index. | 2434 // Check class of index. |
| 2461 __ testl(EBX, Immediate(kSmiTagMask)); | 2435 __ testl(EBX, Immediate(kSmiTagMask)); |
| 2462 __ j(NOT_ZERO, deopt_blob->label()); // Index not Smi -> deopt. | 2436 __ j(NOT_ZERO, deopt_blob->label()); // Index not Smi -> deopt. |
| 2463 // Range check. | 2437 // Range check. |
| 2464 __ cmpl(EBX, FieldAddress(EAX, Array::length_offset())); | 2438 __ cmpl(EBX, FieldAddress(EAX, Array::length_offset())); |
| 2465 __ j(ABOVE_EQUAL, deopt_blob->label()); // Range error -> deopt. | 2439 __ j(ABOVE_EQUAL, deopt_blob->label()); // Range error -> deopt. |
| 2466 ASSERT(kSmiTagShift == 1); | 2440 ASSERT(kSmiTagShift == 1); |
| 2467 __ StoreIntoObject(EAX, | 2441 __ StoreIntoObject(EAX, |
| 2468 FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray)), | 2442 FieldAddress(EAX, EBX, TIMES_2, sizeof(RawArray)), |
| 2469 ECX); | 2443 ECX); |
| 2470 if (CodeGenerator::IsResultNeeded(node)) { | 2444 HandleResult(node, ECX); |
| 2471 __ pushl(ECX); | |
| 2472 } | |
| 2473 return; | 2445 return; |
| 2474 } | 2446 } |
| 2475 | 2447 |
| 2476 const String& growable_object_array_class_name = String::Handle( | 2448 const String& growable_object_array_class_name = String::Handle( |
| 2477 String::NewSymbol(kGrowableArrayClassName)); | 2449 String::NewSymbol(kGrowableArrayClassName)); |
| 2478 const Class& growable_array_class = Class::ZoneHandle( | 2450 const Class& growable_array_class = Class::ZoneHandle( |
| 2479 Library::Handle(Library::CoreImplLibrary()). | 2451 Library::Handle(Library::CoreImplLibrary()). |
| 2480 LookupClass(growable_object_array_class_name)); | 2452 LookupClass(growable_object_array_class_name)); |
| 2481 ASSERT(!growable_array_class.IsNull()); | 2453 ASSERT(!growable_array_class.IsNull()); |
| 2482 if (AtIdNodeHasReceiverClass(node, node->id(), growable_array_class)) { | 2454 if (AtIdNodeHasReceiverClass(node, node->id(), growable_array_class)) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2504 __ j(NOT_ZERO, deopt_blob->label()); // Index not Smi -> deopt. | 2476 __ j(NOT_ZERO, deopt_blob->label()); // Index not Smi -> deopt. |
| 2505 // Range check: deoptimize if out of bounds. | 2477 // Range check: deoptimize if out of bounds. |
| 2506 __ cmpl(EBX, FieldAddress(EAX, length_offset)); | 2478 __ cmpl(EBX, FieldAddress(EAX, length_offset)); |
| 2507 __ j(ABOVE_EQUAL, deopt_blob->label()); | 2479 __ j(ABOVE_EQUAL, deopt_blob->label()); |
| 2508 __ movl(EDX, FieldAddress(EAX, array_offset)); // backingArray. | 2480 __ movl(EDX, FieldAddress(EAX, array_offset)); // backingArray. |
| 2509 // Note that EAX is Smi, i.e, times 2. | 2481 // Note that EAX is Smi, i.e, times 2. |
| 2510 ASSERT(kSmiTagShift == 1); | 2482 ASSERT(kSmiTagShift == 1); |
| 2511 __ StoreIntoObject(EDX, | 2483 __ StoreIntoObject(EDX, |
| 2512 FieldAddress(EDX, EBX, TIMES_2, sizeof(RawArray)), | 2484 FieldAddress(EDX, EBX, TIMES_2, sizeof(RawArray)), |
| 2513 ECX); | 2485 ECX); |
| 2514 if (CodeGenerator::IsResultNeeded(node)) { | 2486 HandleResult(node, ECX); |
| 2515 __ pushl(ECX); | |
| 2516 } | |
| 2517 return; | 2487 return; |
| 2518 } | 2488 } |
| 2519 node->index_expr()->Visit(this); | 2489 node->index_expr()->Visit(this); |
| 2520 node->value()->Visit(this); | 2490 node->value()->Visit(this); |
| 2521 GenerateStoreIndexed(node->id(), node->token_index(), IsResultNeeded(node)); | 2491 GenerateStoreIndexed(node->id(), node->token_index(), IsResultNeeded(node)); |
| 2522 } | 2492 } |
| 2523 | 2493 |
| 2524 | 2494 |
| 2525 void OptimizingCodeGenerator::VisitForNode(ForNode* node) { | 2495 void OptimizingCodeGenerator::VisitForNode(ForNode* node) { |
| 2526 if (FLAG_enable_type_checks) { | 2496 if (FLAG_enable_type_checks) { |
| (...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2849 // Instance call is inlined. | 2819 // Instance call is inlined. |
| 2850 } else { | 2820 } else { |
| 2851 GenerateCheckedInstanceCalls(node, | 2821 GenerateCheckedInstanceCalls(node, |
| 2852 node->receiver(), | 2822 node->receiver(), |
| 2853 node->id(), | 2823 node->id(), |
| 2854 node->token_index(), | 2824 node->token_index(), |
| 2855 number_of_arguments, | 2825 number_of_arguments, |
| 2856 node->arguments()->names()); | 2826 node->arguments()->names()); |
| 2857 } | 2827 } |
| 2858 // Result is in EAX. | 2828 // Result is in EAX. |
| 2859 if (IsResultNeeded(node)) { | 2829 HandleResult(node, EAX); |
| 2860 __ pushl(EAX); | |
| 2861 } | |
| 2862 } | 2830 } |
| 2863 | 2831 |
| 2864 | 2832 |
| 2865 // Returns true if an instance call was replaced with its intrinsic. | 2833 // Returns true if an instance call was replaced with its intrinsic. |
| 2866 // Returns result in EAX. | 2834 // Returns result in EAX. |
| 2867 bool OptimizingCodeGenerator::TryInlineInstanceCall(InstanceCallNode* node) { | 2835 bool OptimizingCodeGenerator::TryInlineInstanceCall(InstanceCallNode* node) { |
| 2868 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); | 2836 const ZoneGrowableArray<const Class*>* classes = CollectedClassesAtNode(node); |
| 2869 if ((classes != NULL) && (classes->length() == 1)) { | 2837 if ((classes != NULL) && (classes->length() == 1)) { |
| 2870 const int num_arguments = node->arguments()->length() + 1; | 2838 const int num_arguments = node->arguments()->length() + 1; |
| 2871 const int num_named_arguments = node->arguments()->names().IsNull() ? | 2839 const int num_named_arguments = node->arguments()->names().IsNull() ? |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2949 if (TryInlineStaticCall(node)) { | 2917 if (TryInlineStaticCall(node)) { |
| 2950 // Static method is inlined, result is in EAX. | 2918 // Static method is inlined, result is in EAX. |
| 2951 } else { | 2919 } else { |
| 2952 __ LoadObject(ECX, node->function()); | 2920 __ LoadObject(ECX, node->function()); |
| 2953 __ LoadObject(EDX, ArgumentsDescriptor(node->arguments()->length(), | 2921 __ LoadObject(EDX, ArgumentsDescriptor(node->arguments()->length(), |
| 2954 node->arguments()->names())); | 2922 node->arguments()->names())); |
| 2955 GenerateCall(node->token_index(), &StubCode::CallStaticFunctionLabel()); | 2923 GenerateCall(node->token_index(), &StubCode::CallStaticFunctionLabel()); |
| 2956 } | 2924 } |
| 2957 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); | 2925 __ addl(ESP, Immediate(node->arguments()->length() * kWordSize)); |
| 2958 // Result is in EAX. | 2926 // Result is in EAX. |
| 2959 if (IsResultNeeded(node)) { | 2927 HandleResult(node, EAX); |
| 2960 __ pushl(EAX); | |
| 2961 } | |
| 2962 } | 2928 } |
| 2963 | 2929 |
| 2964 | 2930 |
| 2965 void OptimizingCodeGenerator::VisitReturnNode(ReturnNode* node) { | 2931 void OptimizingCodeGenerator::VisitReturnNode(ReturnNode* node) { |
| 2966 if ((node->inlined_finally_list_length() > 0) || FLAG_enable_type_checks) { | 2932 if ((node->inlined_finally_list_length() > 0) || FLAG_enable_type_checks) { |
| 2967 CodeGenerator::VisitReturnNode(node); | 2933 CodeGenerator::VisitReturnNode(node); |
| 2968 return; | 2934 return; |
| 2969 } | 2935 } |
| 2970 ASSERT(!IsResultNeeded(node)); | 2936 ASSERT(!IsResultNeeded(node)); |
| 2971 ASSERT(node->value() != NULL); | 2937 ASSERT(node->value() != NULL); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 3001 | 2967 |
| 3002 | 2968 |
| 3003 void OptimizingCodeGenerator::VisitStoreInstanceFieldNode( | 2969 void OptimizingCodeGenerator::VisitStoreInstanceFieldNode( |
| 3004 StoreInstanceFieldNode* node) { | 2970 StoreInstanceFieldNode* node) { |
| 3005 if (FLAG_enable_type_checks) { | 2971 if (FLAG_enable_type_checks) { |
| 3006 CodeGenerator::VisitStoreInstanceFieldNode(node); | 2972 CodeGenerator::VisitStoreInstanceFieldNode(node); |
| 3007 return; | 2973 return; |
| 3008 } | 2974 } |
| 3009 VisitLoadTwo(node->instance(), node->value(), EDX, EAX); | 2975 VisitLoadTwo(node->instance(), node->value(), EDX, EAX); |
| 3010 __ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX); | 2976 __ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX); |
| 3011 if (IsResultNeeded(node)) { | 2977 // The result is the input value. |
| 3012 // The result is the input value. | 2978 HandleResult(node, EAX); |
| 3013 __ pushl(EAX); | |
| 3014 } | |
| 3015 } | 2979 } |
| 3016 | 2980 |
| 3017 | 2981 |
| 3018 void OptimizingCodeGenerator::VisitCatchClauseNode(CatchClauseNode* node) { | 2982 void OptimizingCodeGenerator::VisitCatchClauseNode(CatchClauseNode* node) { |
| 3019 // TODO(srdjan): Set classes for locals. | 2983 // TODO(srdjan): Set classes for locals. |
| 3020 classes_for_locals_->Clear(); | 2984 classes_for_locals_->Clear(); |
| 3021 CodeGenerator::VisitCatchClauseNode(node); | 2985 CodeGenerator::VisitCatchClauseNode(node); |
| 3022 } | 2986 } |
| 3023 | 2987 |
| 3024 | 2988 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3038 if (node->kind() == Token::kNOT) { | 3002 if (node->kind() == Token::kNOT) { |
| 3039 // Only a true bool returns false, everything else is true. | 3003 // Only a true bool returns false, everything else is true. |
| 3040 CodeGenInfo info(node->operand()); | 3004 CodeGenInfo info(node->operand()); |
| 3041 VisitLoadOne(node->operand(), EDX); | 3005 VisitLoadOne(node->operand(), EDX); |
| 3042 Label done; | 3006 Label done; |
| 3043 __ LoadObject(EAX, Bool::ZoneHandle(Bool::True())); | 3007 __ LoadObject(EAX, Bool::ZoneHandle(Bool::True())); |
| 3044 __ cmpl(EDX, EAX); | 3008 __ cmpl(EDX, EAX); |
| 3045 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 3009 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 3046 __ LoadObject(EAX, Bool::ZoneHandle(Bool::False())); | 3010 __ LoadObject(EAX, Bool::ZoneHandle(Bool::False())); |
| 3047 __ Bind(&done); | 3011 __ Bind(&done); |
| 3048 if (CodeGenerator::IsResultNeeded(node)) { | 3012 HandleResult(node, EAX); |
| 3049 if (IsResultInEaxRequested(node)) { | |
| 3050 node->info()->set_result_returned_in_eax(true); | |
| 3051 } else { | |
| 3052 __ pushl(EAX); | |
| 3053 } | |
| 3054 } | |
| 3055 return; | 3013 return; |
| 3056 } | 3014 } |
| 3057 | 3015 |
| 3058 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) { | 3016 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) { |
| 3059 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { | 3017 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { |
| 3060 const ICData& ic_data = node->ICDataAtId(node->id()); | 3018 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 3061 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); | 3019 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 3062 GenerateSmiUnaryOp(node); | 3020 GenerateSmiUnaryOp(node); |
| 3063 return; | 3021 return; |
| 3064 } | 3022 } |
| 3065 } | 3023 } |
| 3066 if (node->kind() == Token::kSUB) { | 3024 if (node->kind() == Token::kSUB) { |
| 3067 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { | 3025 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { |
| 3068 const ICData& ic_data = node->ICDataAtId(node->id()); | 3026 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 3069 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); | 3027 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 3070 GenerateDoubleUnaryOp(node); | 3028 GenerateDoubleUnaryOp(node); |
| 3071 return; | 3029 return; |
| 3072 } | 3030 } |
| 3073 } | 3031 } |
| 3074 // TODO(srdjan): Implement unary kSUB (negate) Mint. | 3032 // TODO(srdjan): Implement unary kSUB (negate) Mint. |
| 3075 CodeGenerator::VisitUnaryOpNode(node); | 3033 CodeGenerator::VisitUnaryOpNode(node); |
| 3076 } | 3034 } |
| 3077 | 3035 |
| 3078 | 3036 |
| 3079 } // namespace dart | 3037 } // namespace dart |
| 3080 | 3038 |
| 3081 #endif // defined TARGET_ARCH_IA32 | 3039 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |