| 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 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 637 return true; | 637 return true; |
| 638 } | 638 } |
| 639 } | 639 } |
| 640 } | 640 } |
| 641 return false; | 641 return false; |
| 642 } | 642 } |
| 643 | 643 |
| 644 | 644 |
| 645 // Look only at the first class in all check groups. Returns true if all | 645 // Look only at the first class in all check groups. Returns true if all |
| 646 // receiver classes are 'cls'. | 646 // receiver classes are 'cls'. |
| 647 static bool AtIdNodeHasReceiverClass(AstNode* node, | 647 static bool AtIdNodeHasClassAt(AstNode* node, |
| 648 intptr_t id, | 648 intptr_t id, |
| 649 const Class& cls) { | 649 const Class& cls, |
| 650 intptr_t arg_index) { |
| 650 ASSERT(node != NULL); | 651 ASSERT(node != NULL); |
| 651 ASSERT(!cls.IsNull()); | 652 ASSERT(!cls.IsNull()); |
| 652 const ICData& ic_data = node->ICDataAtId(id); | 653 const ICData& ic_data = node->ICDataAtId(id); |
| 653 if (ic_data.NumberOfChecks() == 0) { | 654 if (ic_data.NumberOfChecks() == 0) { |
| 654 return false; | 655 return false; |
| 655 } | 656 } |
| 657 ASSERT(ic_data.NumberOfArgumentsChecked() > arg_index); |
| 656 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { | 658 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) { |
| 657 GrowableArray<const Class*> classes; | 659 GrowableArray<const Class*> classes; |
| 658 Function& target = Function::Handle(); | 660 Function& target = Function::Handle(); |
| 659 ic_data.GetCheckAt(i, &classes, &target); | 661 ic_data.GetCheckAt(i, &classes, &target); |
| 660 if (classes.is_empty()) { | 662 if (classes.is_empty()) { |
| 661 return false; | 663 return false; |
| 662 } | 664 } |
| 663 if (classes[0]->raw() != cls.raw()) { | 665 if (classes[arg_index]->raw() != cls.raw()) { |
| 664 return false; | 666 return false; |
| 665 } | 667 } |
| 666 } | 668 } |
| 667 return true; | 669 return true; |
| 668 } | 670 } |
| 669 | 671 |
| 670 | 672 |
| 671 // IC data may have only one check, and it has to contain the two classes in | 673 // IC data may have only one check, and it has to contain the two classes in |
| 672 // specified order. | 674 // specified order. |
| 673 static bool AtIdNodeHasTwoClasses(AstNode* node, | 675 static bool AtIdNodeHasTwoClasses(AstNode* node, |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 839 if (ic_data.NumberOfChecks() == 0) { | 841 if (ic_data.NumberOfChecks() == 0) { |
| 840 // No type feedback. | 842 // No type feedback. |
| 841 __ jmp(deopt_blob->label()); | 843 __ jmp(deopt_blob->label()); |
| 842 return; | 844 return; |
| 843 } | 845 } |
| 844 ASSERT(ic_data.NumberOfChecks() == 1); | 846 ASSERT(ic_data.NumberOfChecks() == 1); |
| 845 CheckIfDoubleOrSmi(kOperandRegister, | 847 CheckIfDoubleOrSmi(kOperandRegister, |
| 846 kTempRegister, | 848 kTempRegister, |
| 847 deopt_blob->label(), | 849 deopt_blob->label(), |
| 848 deopt_blob->label()); | 850 deopt_blob->label()); |
| 851 PropagateBackLocalClass(node->operand(), double_class_); |
| 849 // TODO(srdjan): check if we could reuse a temporary object instead of | 852 // TODO(srdjan): check if we could reuse a temporary object instead of |
| 850 // allocating a new one. | 853 // allocating a new one. |
| 851 const Code& stub = | 854 const Code& stub = |
| 852 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 855 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 853 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 856 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 854 __ pushl(kOperandRegister); | 857 __ pushl(kOperandRegister); |
| 855 GenerateCall(node->token_index(), &label); | 858 GenerateCall(node->token_index(), &label); |
| 856 ASSERT(kResultRegister == EAX); | 859 ASSERT(kResultRegister == EAX); |
| 857 __ popl(kOperandRegister); | 860 __ popl(kOperandRegister); |
| 858 __ movsd(XMM0, FieldAddress(kOperandRegister, Double::value_offset())); | 861 __ movsd(XMM0, FieldAddress(kOperandRegister, Double::value_offset())); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 896 (classes[1]->raw() == smi_class_.raw())); | 899 (classes[1]->raw() == smi_class_.raw())); |
| 897 CodeGenInfo left_info(node->left()); | 900 CodeGenInfo left_info(node->left()); |
| 898 CodeGenInfo right_info(node->right()); | 901 CodeGenInfo right_info(node->right()); |
| 899 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 902 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 900 Label two_smis, call_operator; | 903 Label two_smis, call_operator; |
| 901 DeoptimizationBlob* deopt_blob = | 904 DeoptimizationBlob* deopt_blob = |
| 902 AddDeoptimizationBlob(node, ECX, EDX, kDeoptSmiBinaryOp); | 905 AddDeoptimizationBlob(node, ECX, EDX, kDeoptSmiBinaryOp); |
| 903 __ movl(ECX, EAX); // Save if overflow (needs original value). | 906 __ movl(ECX, EAX); // Save if overflow (needs original value). |
| 904 | 907 |
| 905 if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { | 908 if (left_info.IsClass(smi_class_) || right_info.IsClass(smi_class_)) { |
| 906 if (!left_info.IsClass(smi_class_) || !right_info.IsClass(smi_class_)) { | 909 if (!left_info.IsClass(smi_class_)) { |
| 907 // One of the type is not known (statically) to be Smi. Check it. | 910 __ testl(EAX, Immediate(kSmiTagMask)); |
| 908 Register test_reg = left_info.IsClass(smi_class_) ? EDX : EAX; | |
| 909 __ testl(test_reg, Immediate(kSmiTagMask)); | |
| 910 __ j(NOT_ZERO, deopt_blob->label()); | 911 __ j(NOT_ZERO, deopt_blob->label()); |
| 912 PropagateBackLocalClass(node->left(), smi_class_); |
| 913 } |
| 914 if (!right_info.IsClass(smi_class_)) { |
| 915 __ testl(EDX, Immediate(kSmiTagMask)); |
| 916 __ j(NOT_ZERO, deopt_blob->label()); |
| 917 PropagateBackLocalClass(node->right(), smi_class_); |
| 911 } | 918 } |
| 912 } else { | 919 } else { |
| 913 // Type feedback says both types are Smi, but static type analysis | 920 // Type feedback says both types are Smi, but static type analysis |
| 914 // does not know if any of them is Smi, therefore check. | 921 // does not know if any of them is Smi, therefore check. |
| 915 __ orl(EAX, EDX); | 922 __ orl(EAX, EDX); |
| 916 __ testl(EAX, Immediate(kSmiTagMask)); | 923 __ testl(EAX, Immediate(kSmiTagMask)); |
| 917 __ j(NOT_ZERO, deopt_blob->label()); | 924 __ j(NOT_ZERO, deopt_blob->label()); |
| 918 __ movl(EAX, ECX); | 925 __ movl(EAX, ECX); |
| 926 PropagateBackLocalClass(node->left(), smi_class_); |
| 927 PropagateBackLocalClass(node->right(), smi_class_); |
| 919 } | 928 } |
| 920 if (node->info() != NULL) { | 929 if (node->info() != NULL) { |
| 921 node->info()->set_is_class(&smi_class_); | 930 node->info()->set_is_class(&smi_class_); |
| 922 } | 931 } |
| 923 switch (kind) { | 932 switch (kind) { |
| 924 case Token::kADD: { | 933 case Token::kADD: { |
| 925 __ addl(EAX, EDX); | 934 __ addl(EAX, EDX); |
| 926 __ j(OVERFLOW, deopt_blob->label()); | 935 __ j(OVERFLOW, deopt_blob->label()); |
| 927 break; | 936 break; |
| 928 } | 937 } |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1055 // Conservative approach: | 1064 // Conservative approach: |
| 1056 // - true if both nodes are LoadLocalNodes with the same index. | 1065 // - true if both nodes are LoadLocalNodes with the same index. |
| 1057 static bool AreNodesOfSameType(AstNode* a, AstNode* b) { | 1066 static bool AreNodesOfSameType(AstNode* a, AstNode* b) { |
| 1058 ASSERT((a != NULL) && (b != NULL)); | 1067 ASSERT((a != NULL) && (b != NULL)); |
| 1059 if (a->IsLoadLocalNode() && b->IsLoadLocalNode()) { | 1068 if (a->IsLoadLocalNode() && b->IsLoadLocalNode()) { |
| 1060 return a->AsLoadLocalNode()->local().Equals(b->AsLoadLocalNode()->local()); | 1069 return a->AsLoadLocalNode()->local().Equals(b->AsLoadLocalNode()->local()); |
| 1061 } | 1070 } |
| 1062 return false; | 1071 return false; |
| 1063 } | 1072 } |
| 1064 | 1073 |
| 1074 |
| 1075 // If possible propagate node type back to the local. |
| 1076 void OptimizingCodeGenerator::PropagateBackLocalClass(AstNode* node, |
| 1077 const Class& cls) { |
| 1078 if (node->IsLoadLocalNode()) { |
| 1079 LoadLocalNode* local_node = node->AsLoadLocalNode(); |
| 1080 classes_for_locals_->SetLocalType(local_node->local(), cls); |
| 1081 } |
| 1082 } |
| 1083 |
| 1084 |
| 1065 // 'reg' is not modified, 'temp' is trashed. | 1085 // 'reg' is not modified, 'temp' is trashed. |
| 1066 // Fall through if double, jump to 'is_smi' if Smi and | 1086 // Fall through if double, jump to 'is_smi' if Smi and |
| 1067 // jump to 'not_double_or_smi' if neither double nor Smi. | 1087 // jump to 'not_double_or_smi' if neither double nor Smi. |
| 1068 void OptimizingCodeGenerator::CheckIfDoubleOrSmi(Register reg, | 1088 void OptimizingCodeGenerator::CheckIfDoubleOrSmi(Register reg, |
| 1069 Register temp, | 1089 Register temp, |
| 1070 Label* is_smi, | 1090 Label* is_smi, |
| 1071 Label* not_double_or_smi) { | 1091 Label* not_double_or_smi) { |
| 1072 __ testl(reg, Immediate(kSmiTagMask)); | 1092 __ testl(reg, Immediate(kSmiTagMask)); |
| 1073 __ j(ZERO, is_smi); | 1093 __ j(ZERO, is_smi); |
| 1074 __ movl(temp, FieldAddress(reg, Object::class_offset())); | 1094 __ movl(temp, FieldAddress(reg, Object::class_offset())); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1092 if ((kind == Token::kADD) || | 1112 if ((kind == Token::kADD) || |
| 1093 (kind == Token::kSUB) || | 1113 (kind == Token::kSUB) || |
| 1094 (kind == Token::kMUL) || | 1114 (kind == Token::kMUL) || |
| 1095 (kind == Token::kDIV)) { | 1115 (kind == Token::kDIV)) { |
| 1096 TraceOpt(node, kOptMessage); | 1116 TraceOpt(node, kOptMessage); |
| 1097 // All four register below must be different. | 1117 // All four register below must be different. |
| 1098 const Register kLeftRegister = EAX; | 1118 const Register kLeftRegister = EAX; |
| 1099 const Register kRightRegister = EDX; | 1119 const Register kRightRegister = EDX; |
| 1100 const Register kAllocatedRegister = ECX; | 1120 const Register kAllocatedRegister = ECX; |
| 1101 const Register kTempRegister = EBX; | 1121 const Register kTempRegister = EBX; |
| 1102 CodeGenInfo left_info(node->left()); | 1122 CodeGenInfo left_info(node->left()); // Receiver. |
| 1103 CodeGenInfo right_info(node->right()); | 1123 CodeGenInfo right_info(node->right()); |
| 1104 VisitLoadTwo(node->left(), node->right(), kLeftRegister, kRightRegister); | 1124 VisitLoadTwo(node->left(), node->right(), kLeftRegister, kRightRegister); |
| 1105 // First allocate result object or specify an existing object as result. | 1125 // First allocate result object or specify an existing object as result. |
| 1106 Register result_register = kNoRegister; | 1126 Register result_register = kNoRegister; |
| 1107 if (node->info() == NULL) { | 1127 if (node->info() == NULL) { |
| 1108 // Parent node cannot handle a temporary double object, allocate one | 1128 // Parent node cannot handle a temporary double object, allocate one |
| 1109 // each time. | 1129 // each time. |
| 1110 result_register = kAllocatedRegister; | 1130 result_register = kAllocatedRegister; |
| 1111 const Code& stub = | 1131 const Code& stub = |
| 1112 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 1132 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1142 } | 1162 } |
| 1143 | 1163 |
| 1144 if (receiver_can_be_smi) { | 1164 if (receiver_can_be_smi) { |
| 1145 // Only deoptimize if both argument are Smi. | 1165 // Only deoptimize if both argument are Smi. |
| 1146 __ movl(kTempRegister, kLeftRegister); | 1166 __ movl(kTempRegister, kLeftRegister); |
| 1147 __ orl(kTempRegister, kRightRegister); | 1167 __ orl(kTempRegister, kRightRegister); |
| 1148 __ testl(kTempRegister, Immediate(kSmiTagMask)); | 1168 __ testl(kTempRegister, Immediate(kSmiTagMask)); |
| 1149 __ j(ZERO, deopt_lbl); | 1169 __ j(ZERO, deopt_lbl); |
| 1150 } | 1170 } |
| 1151 | 1171 |
| 1152 bool nodes_of_same_type = AreNodesOfSameType(node->left(), node->right()); | 1172 bool args_of_same_type = AreNodesOfSameType(node->left(), node->right()); |
| 1153 if (!left_info.IsClass(double_class_)) { | 1173 if (left_info.IsClass(double_class_)) { |
| 1154 Label is_smi, done; | |
| 1155 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, &is_smi, deopt_lbl); | |
| 1156 // Fall through for double. Jump to 'is_smi' if double, jump to | |
| 1157 // 'deopt' if neither smi nor double. | |
| 1158 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset())); | 1174 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset())); |
| 1159 __ jmp(&done); | |
| 1160 __ Bind(&is_smi); | |
| 1161 __ SmiUntag(kLeftRegister); | |
| 1162 __ cvtsi2sd(XMM0, kLeftRegister); | |
| 1163 __ Bind(&done); | |
| 1164 } else { | 1175 } else { |
| 1165 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset())); | 1176 if (receiver_can_be_smi) { |
| 1177 Label is_smi, done; |
| 1178 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, &is_smi, deopt_lbl); |
| 1179 // Fall through for double. Jump to 'is_smi' if double, jump to |
| 1180 // 'deopt' if neither smi nor double. |
| 1181 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset())); |
| 1182 __ jmp(&done); |
| 1183 __ Bind(&is_smi); |
| 1184 __ SmiUntag(kLeftRegister); |
| 1185 __ cvtsi2sd(XMM0, kLeftRegister); |
| 1186 __ Bind(&done); |
| 1187 } else { |
| 1188 CheckIfDoubleOrSmi(kLeftRegister, kTempRegister, deopt_lbl, deopt_lbl); |
| 1189 __ movsd(XMM0, FieldAddress(kLeftRegister, Double::value_offset())); |
| 1190 PropagateBackLocalClass(node->left(), double_class_); |
| 1191 } |
| 1166 } | 1192 } |
| 1167 if (!right_info.IsClass(double_class_) && !nodes_of_same_type) { | 1193 |
| 1168 Label is_smi, done; | 1194 const bool right_must_be_double = |
| 1169 CheckIfDoubleOrSmi(kRightRegister, kTempRegister, &is_smi, deopt_lbl); | 1195 AtIdNodeHasClassAt(node, node->id(), double_class_, 1); |
| 1170 // Fall through for double. Jump to 'is_smi' if double, jump to | 1196 |
| 1171 // 'deopt' if neither smi nor double. | 1197 // If arguments are of same type (e.g., same local), then the test of left |
| 1198 // argument was sufficient. |
| 1199 if (right_info.IsClass(double_class_) || args_of_same_type) { |
| 1172 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); | 1200 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); |
| 1173 __ jmp(&done); | 1201 if (!right_info.IsClass(double_class_)) { |
| 1174 __ Bind(&is_smi); | 1202 PropagateBackLocalClass(node->right(), double_class_); |
| 1175 __ SmiUntag(kRightRegister); | 1203 } |
| 1176 __ cvtsi2sd(XMM1, kRightRegister); | |
| 1177 __ Bind(&done); | |
| 1178 } else { | 1204 } else { |
| 1179 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); | 1205 if (right_must_be_double) { |
| 1206 CheckIfDoubleOrSmi(kRightRegister, kTempRegister, deopt_lbl, deopt_lbl); |
| 1207 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); |
| 1208 PropagateBackLocalClass(node->right(), double_class_); |
| 1209 } else { |
| 1210 Label is_smi, done; |
| 1211 CheckIfDoubleOrSmi(kRightRegister, kTempRegister, &is_smi, deopt_lbl); |
| 1212 // Fall through for double. Jump to 'is_smi' if double, jump to |
| 1213 // 'deopt' if neither smi nor double. |
| 1214 __ movsd(XMM1, FieldAddress(kRightRegister, Double::value_offset())); |
| 1215 __ jmp(&done); |
| 1216 __ Bind(&is_smi); |
| 1217 __ SmiUntag(kRightRegister); |
| 1218 __ cvtsi2sd(XMM1, kRightRegister); |
| 1219 __ Bind(&done); |
| 1220 } |
| 1180 } | 1221 } |
| 1181 | 1222 |
| 1182 switch (kind) { | 1223 switch (kind) { |
| 1183 case Token::kADD: __ addsd(XMM0, XMM1); break; | 1224 case Token::kADD: __ addsd(XMM0, XMM1); break; |
| 1184 case Token::kSUB: __ subsd(XMM0, XMM1); break; | 1225 case Token::kSUB: __ subsd(XMM0, XMM1); break; |
| 1185 case Token::kMUL: __ mulsd(XMM0, XMM1); break; | 1226 case Token::kMUL: __ mulsd(XMM0, XMM1); break; |
| 1186 case Token::kDIV: __ divsd(XMM0, XMM1); break; | 1227 case Token::kDIV: __ divsd(XMM0, XMM1); break; |
| 1187 default: UNREACHABLE(); | 1228 default: UNREACHABLE(); |
| 1188 } | 1229 } |
| 1189 __ movsd(FieldAddress(result_register, Double::value_offset()), XMM0); | 1230 __ movsd(FieldAddress(result_register, Double::value_offset()), XMM0); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1294 | 1335 |
| 1295 const ICData& ic_data = node->ICDataAtId(node->id()); | 1336 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1296 if (ic_data.NumberOfChecks() == 0) { | 1337 if (ic_data.NumberOfChecks() == 0) { |
| 1297 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 1338 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 1298 DeoptimizationBlob* deopt_blob = | 1339 DeoptimizationBlob* deopt_blob = |
| 1299 AddDeoptimizationBlob(node, EAX, EDX, kDeoptNoTypeFeedback); | 1340 AddDeoptimizationBlob(node, EAX, EDX, kDeoptNoTypeFeedback); |
| 1300 __ jmp(deopt_blob->label()); | 1341 __ jmp(deopt_blob->label()); |
| 1301 return; | 1342 return; |
| 1302 } | 1343 } |
| 1303 | 1344 |
| 1345 ASSERT(ic_data.NumberOfArgumentsChecked() == 2); |
| 1346 |
| 1304 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, smi_class_)) { | 1347 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, smi_class_)) { |
| 1305 GenerateSmiBinaryOp(node); | 1348 GenerateSmiBinaryOp(node); |
| 1306 return; | 1349 return; |
| 1307 } | 1350 } |
| 1308 | 1351 |
| 1309 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { | 1352 if (AtIdNodeHasClassAt(node, node->id(), double_class_, 0)) { |
| 1310 const bool receiver_can_be_smi = false; | 1353 const bool receiver_can_be_smi = false; |
| 1311 GenerateDoubleBinaryOp(node, receiver_can_be_smi); | 1354 GenerateDoubleBinaryOp(node, receiver_can_be_smi); |
| 1312 return; | 1355 return; |
| 1313 } | 1356 } |
| 1314 | 1357 |
| 1315 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, double_class_)) { | 1358 if (AtIdNodeHasTwoClasses(node, node->id(), smi_class_, double_class_)) { |
| 1316 const bool receiver_can_be_smi = true; | 1359 const bool receiver_can_be_smi = true; |
| 1317 GenerateDoubleBinaryOp(node, receiver_can_be_smi); | 1360 GenerateDoubleBinaryOp(node, receiver_can_be_smi); |
| 1318 return; | 1361 return; |
| 1319 } | 1362 } |
| 1320 | 1363 |
| 1321 const Class& mint_class = | 1364 const Class& mint_class = |
| 1322 Class::Handle(Isolate::Current()->object_store()->mint_class()); | 1365 Class::Handle(Isolate::Current()->object_store()->mint_class()); |
| 1323 if (AtIdNodeHasReceiverClass(node, node->id(), mint_class)) { | 1366 if (AtIdNodeHasClassAt(node, node->id(), mint_class, 0)) { |
| 1324 GenerateMintBinaryOp(node, false); | 1367 GenerateMintBinaryOp(node, false); |
| 1325 return; | 1368 return; |
| 1326 } | 1369 } |
| 1327 | 1370 |
| 1328 if (NodeHasBothReceiverClasses(node, smi_class_, mint_class)) { | 1371 if (NodeHasBothReceiverClasses(node, smi_class_, mint_class)) { |
| 1329 GenerateMintBinaryOp(node, true); | 1372 GenerateMintBinaryOp(node, true); |
| 1330 return; | 1373 return; |
| 1331 } | 1374 } |
| 1332 | 1375 |
| 1333 // TODO(srdjan): Implement "+" for Strings. | 1376 // TODO(srdjan): Implement "+" for Strings. |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1357 } | 1400 } |
| 1358 const ICData& ic_data = node->ICDataAtId(node->id()); | 1401 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 1359 if (ic_data.NumberOfChecks() == 0) { | 1402 if (ic_data.NumberOfChecks() == 0) { |
| 1360 DeoptimizationBlob* deopt_blob = | 1403 DeoptimizationBlob* deopt_blob = |
| 1361 AddDeoptimizationBlob(node, kDeoptNoTypeFeedback); | 1404 AddDeoptimizationBlob(node, kDeoptNoTypeFeedback); |
| 1362 __ jmp(deopt_blob->label()); | 1405 __ jmp(deopt_blob->label()); |
| 1363 return; | 1406 return; |
| 1364 } | 1407 } |
| 1365 const char* kOptMessage = "Inlines IncrOpLocal"; | 1408 const char* kOptMessage = "Inlines IncrOpLocal"; |
| 1366 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); | 1409 ASSERT((node->kind() == Token::kINCR) || (node->kind() == Token::kDECR)); |
| 1367 if (!AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { | 1410 if (!AtIdNodeHasClassAt(node, node->id(), smi_class_, 0)) { |
| 1368 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); | 1411 classes_for_locals_->SetLocalType(node->local(), Class::ZoneHandle()); |
| 1369 TraceNotOpt(node, kOptMessage); | 1412 TraceNotOpt(node, kOptMessage); |
| 1370 CodeGenerator::VisitIncrOpLocalNode(node); | 1413 CodeGenerator::VisitIncrOpLocalNode(node); |
| 1371 return; | 1414 return; |
| 1372 } | 1415 } |
| 1373 TraceOpt(node, kOptMessage); | 1416 TraceOpt(node, kOptMessage); |
| 1374 | 1417 |
| 1375 GenerateLoadVariable(EAX, node->local()); | 1418 GenerateLoadVariable(EAX, node->local()); |
| 1376 if (!node->prefix() && IsResultNeeded(node)) { | 1419 if (!node->prefix() && IsResultNeeded(node)) { |
| 1377 // Preserve as result. | 1420 // Preserve as result. |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1453 node->getter_id(), | 1496 node->getter_id(), |
| 1454 node->receiver(), | 1497 node->receiver(), |
| 1455 node->field_name(), | 1498 node->field_name(), |
| 1456 EBX); | 1499 EBX); |
| 1457 // result is in EAX. | 1500 // result is in EAX. |
| 1458 __ popl(EDX); // Get receiver. | 1501 __ popl(EDX); // Get receiver. |
| 1459 const bool return_original_value = !node->prefix() && IsResultNeeded(node); | 1502 const bool return_original_value = !node->prefix() && IsResultNeeded(node); |
| 1460 const Immediate one_value = Immediate(Smi::RawValue(1)); | 1503 const Immediate one_value = Immediate(Smi::RawValue(1)); |
| 1461 // EAX: Value. | 1504 // EAX: Value. |
| 1462 // EDX: Receiver. | 1505 // EDX: Receiver. |
| 1463 if (AtIdNodeHasReceiverClass(node, node->operator_id(), smi_class_)) { | 1506 if (AtIdNodeHasClassAt(node, node->operator_id(), smi_class_, 0)) { |
| 1464 // Deoptimization point for this node is after receiver has been | 1507 // Deoptimization point for this node is after receiver has been |
| 1465 // pushed twice on stack and before the getter (above) was executed. | 1508 // pushed twice on stack and before the getter (above) was executed. |
| 1466 DeoptimizationBlob* deopt_blob = | 1509 DeoptimizationBlob* deopt_blob = |
| 1467 AddDeoptimizationBlob(node, EDX, EDX, kDeoptIncrInstanceOneClass); | 1510 AddDeoptimizationBlob(node, EDX, EDX, kDeoptIncrInstanceOneClass); |
| 1468 if (return_original_value) { | 1511 if (return_original_value) { |
| 1469 // Preserve pre increment result. | 1512 // Preserve pre increment result. |
| 1470 __ movl(ECX, EAX); | 1513 __ movl(ECX, EAX); |
| 1471 } | 1514 } |
| 1472 __ testl(EAX, Immediate(kSmiTagMask)); | 1515 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1473 __ j(NOT_ZERO, deopt_blob->label()); | 1516 __ j(NOT_ZERO, deopt_blob->label()); |
| (...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2211 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 2254 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 2212 CodeGenInfo left_info(node->left()); | 2255 CodeGenInfo left_info(node->left()); |
| 2213 CodeGenInfo right_info(node->right()); | 2256 CodeGenInfo right_info(node->right()); |
| 2214 VisitLoadTwo(node->left(), node->right(), EAX, EDX); | 2257 VisitLoadTwo(node->left(), node->right(), EAX, EDX); |
| 2215 DeoptimizationBlob* deopt_blob = NULL; | 2258 DeoptimizationBlob* deopt_blob = NULL; |
| 2216 if (!left_info.IsClass(double_class_) || !right_info.IsClass(double_class_)) { | 2259 if (!left_info.IsClass(double_class_) || !right_info.IsClass(double_class_)) { |
| 2217 deopt_blob = AddDeoptimizationBlob(node, EAX, EDX, kDeoptDoubleComparison); | 2260 deopt_blob = AddDeoptimizationBlob(node, EAX, EDX, kDeoptDoubleComparison); |
| 2218 } | 2261 } |
| 2219 if (!left_info.IsClass(double_class_)) { | 2262 if (!left_info.IsClass(double_class_)) { |
| 2220 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); | 2263 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); |
| 2264 PropagateBackLocalClass(node->left(), double_class_); |
| 2221 } | 2265 } |
| 2222 if (!right_info.IsClass(double_class_)) { | 2266 if (!right_info.IsClass(double_class_)) { |
| 2223 CheckIfDoubleOrSmi(EDX, EBX, deopt_blob->label(), deopt_blob->label()); | 2267 CheckIfDoubleOrSmi(EDX, EBX, deopt_blob->label(), deopt_blob->label()); |
| 2268 PropagateBackLocalClass(node->right(), double_class_); |
| 2224 } | 2269 } |
| 2225 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); | 2270 __ movsd(XMM0, FieldAddress(EAX, Double::value_offset())); |
| 2226 __ movsd(XMM1, FieldAddress(EDX, Double::value_offset())); | 2271 __ movsd(XMM1, FieldAddress(EDX, Double::value_offset())); |
| 2227 __ comisd(XMM0, XMM1); | 2272 __ comisd(XMM0, XMM1); |
| 2228 if (NodeInfoHasLabels(node)) { | 2273 if (NodeInfoHasLabels(node)) { |
| 2229 __ j(PARITY_EVEN, node->info()->false_label()); // NaN -> false; | 2274 __ j(PARITY_EVEN, node->info()->false_label()); // NaN -> false; |
| 2230 GenerateConditionalJumps(*(node->info()), true_condition); | 2275 GenerateConditionalJumps(*(node->info()), true_condition); |
| 2231 node->info()->set_labels_used(true); | 2276 node->info()->set_labels_used(true); |
| 2232 } else { | 2277 } else { |
| 2233 Label is_false, is_true, done; | 2278 Label is_false, is_true, done; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2288 GenerateInstanceOf(node->id(), | 2333 GenerateInstanceOf(node->id(), |
| 2289 node->token_index(), | 2334 node->token_index(), |
| 2290 node->right()->AsTypeNode()->type(), | 2335 node->right()->AsTypeNode()->type(), |
| 2291 (node->kind() == Token::kISNOT)); | 2336 (node->kind() == Token::kISNOT)); |
| 2292 if (!IsResultNeeded(node)) { | 2337 if (!IsResultNeeded(node)) { |
| 2293 __ popl(EAX); // Pop the result of the instanceof operation. | 2338 __ popl(EAX); // Pop the result of the instanceof operation. |
| 2294 } | 2339 } |
| 2295 return; | 2340 return; |
| 2296 } | 2341 } |
| 2297 | 2342 |
| 2298 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { | 2343 if (AtIdNodeHasClassAt(node, node->id(), smi_class_, 0)) { |
| 2299 if (GenerateSmiComparison(node)) { | 2344 if (GenerateSmiComparison(node)) { |
| 2300 // The comparison was handled, code was emitted. | 2345 // The comparison was handled, code was emitted. |
| 2301 return; | 2346 return; |
| 2302 } | 2347 } |
| 2303 // Fall through if condition is not supported. | 2348 // Fall through if condition is not supported. |
| 2304 } else if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { | 2349 } else if (AtIdNodeHasClassAt(node, node->id(), double_class_, 0)) { |
| 2305 // Double comparison | 2350 // Double comparison |
| 2306 if (GenerateDoubleComparison(node)) { | 2351 if (GenerateDoubleComparison(node)) { |
| 2307 return; | 2352 return; |
| 2308 } | 2353 } |
| 2309 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { | 2354 } else if ((node->kind() == Token::kEQ) || (node->kind() == Token::kNE)) { |
| 2310 // Equality, not-equality comparison of any other type. | 2355 // Equality, not-equality comparison of any other type. |
| 2311 if (GenerateEqualityComparison(node)) { | 2356 if (GenerateEqualityComparison(node)) { |
| 2312 return; | 2357 return; |
| 2313 } | 2358 } |
| 2314 } | 2359 } |
| 2315 | 2360 |
| 2316 // Fall through here if a comparison was not implemented. | 2361 // Fall through here if a comparison was not implemented. |
| 2317 // TODO(srdjan): Implement for Strings. | 2362 // TODO(srdjan): Implement for Strings. |
| 2318 CodeGenerator::VisitComparisonNode(node); | 2363 CodeGenerator::VisitComparisonNode(node); |
| 2319 } | 2364 } |
| 2320 | 2365 |
| 2321 | 2366 |
| 2322 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { | 2367 void OptimizingCodeGenerator::VisitLoadIndexedNode(LoadIndexedNode* node) { |
| 2323 const char* kMessage = "Inline indexed access"; | 2368 const char* kMessage = "Inline indexed access"; |
| 2324 ObjectStore* object_store = Isolate::Current()->object_store(); | 2369 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 2325 const Class& object_array_class = | 2370 const Class& object_array_class = |
| 2326 Class::ZoneHandle(object_store->array_class()); | 2371 Class::ZoneHandle(object_store->array_class()); |
| 2327 const Class& immutable_object_array_class = | 2372 const Class& immutable_object_array_class = |
| 2328 Class::ZoneHandle(object_store->immutable_array_class()); | 2373 Class::ZoneHandle(object_store->immutable_array_class()); |
| 2329 if (AtIdNodeHasReceiverClass(node, node->id(), object_array_class) || | 2374 if (AtIdNodeHasClassAt(node, node->id(), object_array_class, 0) || |
| 2330 AtIdNodeHasReceiverClass(node, node->id(), | 2375 AtIdNodeHasClassAt(node, node->id(), |
| 2331 immutable_object_array_class)) { | 2376 immutable_object_array_class, 0)) { |
| 2332 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); | 2377 VisitLoadTwo(node->array(), node->index_expr(), EBX, EDX); |
| 2333 DeoptimizationBlob* deopt_blob = | 2378 DeoptimizationBlob* deopt_blob = |
| 2334 AddDeoptimizationBlob(node, EBX, EDX, kDeoptLoadIndexedFixedArray); | 2379 AddDeoptimizationBlob(node, EBX, EDX, kDeoptLoadIndexedFixedArray); |
| 2335 const Class& test_class = | 2380 const Class& test_class = |
| 2336 AtIdNodeHasReceiverClass(node, node->id(), object_array_class) ? | 2381 AtIdNodeHasClassAt(node, node->id(), object_array_class, 0) ? |
| 2337 object_array_class : immutable_object_array_class; | 2382 object_array_class : immutable_object_array_class; |
| 2338 // Type checks of array. | 2383 // Type checks of array. |
| 2339 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. | 2384 __ testl(EBX, Immediate(kSmiTagMask)); // Deoptimize if Smi. |
| 2340 __ j(ZERO, deopt_blob->label()); | 2385 __ j(ZERO, deopt_blob->label()); |
| 2341 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); | 2386 __ movl(EAX, FieldAddress(EBX, Object::class_offset())); |
| 2342 __ CompareObject(EAX, test_class); | 2387 __ CompareObject(EAX, test_class); |
| 2343 __ j(NOT_EQUAL, deopt_blob->label()); | 2388 __ j(NOT_EQUAL, deopt_blob->label()); |
| 2344 | 2389 |
| 2345 // Type check of index. | 2390 // Type check of index. |
| 2346 __ testl(EDX, Immediate(kSmiTagMask)); | 2391 __ testl(EDX, Immediate(kSmiTagMask)); |
| 2347 __ j(NOT_ZERO, deopt_blob->label()); | 2392 __ j(NOT_ZERO, deopt_blob->label()); |
| 2348 // Range check. | 2393 // Range check. |
| 2349 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); | 2394 __ cmpl(EDX, FieldAddress(EBX, Array::length_offset())); |
| 2350 __ j(ABOVE_EQUAL, deopt_blob->label()); | 2395 __ j(ABOVE_EQUAL, deopt_blob->label()); |
| 2351 // Note that EDX is Smi, i.e, times 2. | 2396 // Note that EDX is Smi, i.e, times 2. |
| 2352 ASSERT(kSmiTagShift == 1); | 2397 ASSERT(kSmiTagShift == 1); |
| 2353 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); | 2398 __ movl(EAX, FieldAddress(EBX, EDX, TIMES_2, sizeof(RawArray))); |
| 2354 HandleResult(node, EAX); | 2399 HandleResult(node, EAX); |
| 2355 TraceOpt(node, kMessage); | 2400 TraceOpt(node, kMessage); |
| 2356 return; | 2401 return; |
| 2357 } | 2402 } |
| 2358 | 2403 |
| 2359 const String& growable_object_array_class_name = String::Handle( | 2404 const String& growable_object_array_class_name = String::Handle( |
| 2360 String::NewSymbol(kGrowableArrayClassName)); | 2405 String::NewSymbol(kGrowableArrayClassName)); |
| 2361 const Class& growable_array_class = Class::ZoneHandle( | 2406 const Class& growable_array_class = Class::ZoneHandle( |
| 2362 Library::Handle(Library::CoreImplLibrary()). | 2407 Library::Handle(Library::CoreImplLibrary()). |
| 2363 LookupClass(growable_object_array_class_name)); | 2408 LookupClass(growable_object_array_class_name)); |
| 2364 ASSERT(!growable_array_class.IsNull()); | 2409 ASSERT(!growable_array_class.IsNull()); |
| 2365 if (AtIdNodeHasReceiverClass(node, node->id(), growable_array_class)) { | 2410 if (AtIdNodeHasClassAt(node, node->id(), growable_array_class, 0)) { |
| 2366 const String& growable_array_length_field_name = | 2411 const String& growable_array_length_field_name = |
| 2367 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); | 2412 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); |
| 2368 const String& growable_array_array_field_name = | 2413 const String& growable_array_array_field_name = |
| 2369 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); | 2414 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); |
| 2370 intptr_t length_offset = GetFieldOffset(growable_array_class, | 2415 intptr_t length_offset = GetFieldOffset(growable_array_class, |
| 2371 growable_array_length_field_name); | 2416 growable_array_length_field_name); |
| 2372 intptr_t array_offset = GetFieldOffset(growable_array_class, | 2417 intptr_t array_offset = GetFieldOffset(growable_array_class, |
| 2373 growable_array_array_field_name); | 2418 growable_array_array_field_name); |
| 2374 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); | 2419 VisitLoadTwo(node->array(), node->index_expr(), EDX, EAX); |
| 2375 DeoptimizationBlob* deopt_blob = | 2420 DeoptimizationBlob* deopt_blob = |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2412 Class::ZoneHandle(object_store->array_class()); | 2457 Class::ZoneHandle(object_store->array_class()); |
| 2413 const ICData& ic_data = node->ICDataAtId(node->id()); | 2458 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 2414 if (ic_data.NumberOfChecks() == 0) { | 2459 if (ic_data.NumberOfChecks() == 0) { |
| 2415 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); | 2460 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); |
| 2416 DeoptimizationBlob* deopt_blob = | 2461 DeoptimizationBlob* deopt_blob = |
| 2417 AddDeoptimizationBlob(node, EBX, ECX, kDeoptNoTypeFeedback); | 2462 AddDeoptimizationBlob(node, EBX, ECX, kDeoptNoTypeFeedback); |
| 2418 __ jmp(deopt_blob->label()); | 2463 __ jmp(deopt_blob->label()); |
| 2419 return; | 2464 return; |
| 2420 } | 2465 } |
| 2421 | 2466 |
| 2422 if (AtIdNodeHasReceiverClass(node, node->id(), object_array_class)) { | 2467 if (AtIdNodeHasClassAt(node, node->id(), object_array_class, 0)) { |
| 2423 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); | 2468 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); |
| 2424 DeoptimizationBlob* deopt_blob = | 2469 DeoptimizationBlob* deopt_blob = |
| 2425 AddDeoptimizationBlob(node, EAX, EBX, ECX, kDeoptStoreIndexed); | 2470 AddDeoptimizationBlob(node, EAX, EBX, ECX, kDeoptStoreIndexed); |
| 2426 __ popl(EAX); // array. | 2471 __ popl(EAX); // array. |
| 2427 // ECX: value, EBX:index, EAX: array. | 2472 // ECX: value, EBX:index, EAX: array. |
| 2428 // Check class of array. | 2473 // Check class of array. |
| 2429 __ testl(EAX, Immediate(kSmiTagMask)); | 2474 __ testl(EAX, Immediate(kSmiTagMask)); |
| 2430 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. | 2475 __ j(ZERO, deopt_blob->label()); // Array is smi -> deopt. |
| 2431 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); | 2476 __ movl(EDX, FieldAddress(EAX, Object::class_offset())); |
| 2432 __ CompareObject(EDX, object_array_class); | 2477 __ CompareObject(EDX, object_array_class); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2444 HandleResult(node, ECX); | 2489 HandleResult(node, ECX); |
| 2445 return; | 2490 return; |
| 2446 } | 2491 } |
| 2447 | 2492 |
| 2448 const String& growable_object_array_class_name = String::Handle( | 2493 const String& growable_object_array_class_name = String::Handle( |
| 2449 String::NewSymbol(kGrowableArrayClassName)); | 2494 String::NewSymbol(kGrowableArrayClassName)); |
| 2450 const Class& growable_array_class = Class::ZoneHandle( | 2495 const Class& growable_array_class = Class::ZoneHandle( |
| 2451 Library::Handle(Library::CoreImplLibrary()). | 2496 Library::Handle(Library::CoreImplLibrary()). |
| 2452 LookupClass(growable_object_array_class_name)); | 2497 LookupClass(growable_object_array_class_name)); |
| 2453 ASSERT(!growable_array_class.IsNull()); | 2498 ASSERT(!growable_array_class.IsNull()); |
| 2454 if (AtIdNodeHasReceiverClass(node, node->id(), growable_array_class)) { | 2499 if (AtIdNodeHasClassAt(node, node->id(), growable_array_class, 0)) { |
| 2455 const String& growable_array_length_field_name = | 2500 const String& growable_array_length_field_name = |
| 2456 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); | 2501 String::Handle(String::NewSymbol(kGrowableArrayLengthFieldName)); |
| 2457 const String& growable_array_array_field_name = | 2502 const String& growable_array_array_field_name = |
| 2458 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); | 2503 String::Handle(String::NewSymbol(kGrowableArrayArrayFieldName)); |
| 2459 intptr_t length_offset = GetFieldOffset(growable_array_class, | 2504 intptr_t length_offset = GetFieldOffset(growable_array_class, |
| 2460 growable_array_length_field_name); | 2505 growable_array_length_field_name); |
| 2461 intptr_t array_offset = GetFieldOffset(growable_array_class, | 2506 intptr_t array_offset = GetFieldOffset(growable_array_class, |
| 2462 growable_array_array_field_name); | 2507 growable_array_array_field_name); |
| 2463 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); | 2508 VisitLoadTwo(node->index_expr(), node->value(), EBX, ECX); |
| 2464 DeoptimizationBlob* deopt_blob = | 2509 DeoptimizationBlob* deopt_blob = |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2843 node->function_name(), | 2888 node->function_name(), |
| 2844 num_arguments, | 2889 num_arguments, |
| 2845 num_named_arguments)); | 2890 num_named_arguments)); |
| 2846 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); | 2891 Recognizer::Kind recognized = Recognizer::RecognizeKind(target); |
| 2847 if (FLAG_trace_optimization) { | 2892 if (FLAG_trace_optimization) { |
| 2848 OS::Print("Monomorphic inline candidate: %s -> %s\n", | 2893 OS::Print("Monomorphic inline candidate: %s -> %s\n", |
| 2849 target.ToFullyQualifiedCString(), | 2894 target.ToFullyQualifiedCString(), |
| 2850 Recognizer::KindToCString(recognized)); | 2895 Recognizer::KindToCString(recognized)); |
| 2851 } | 2896 } |
| 2852 if ((recognized == Recognizer::kIntegerToDouble) && | 2897 if ((recognized == Recognizer::kIntegerToDouble) && |
| 2853 AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { | 2898 AtIdNodeHasClassAt(node, node->id(), smi_class_, 0)) { |
| 2854 // TODO(srdjan): Check if we could use temporary double instead of | 2899 // TODO(srdjan): Check if we could use temporary double instead of |
| 2855 // allocating a new object every time. | 2900 // allocating a new object every time. |
| 2856 const Code& stub = | 2901 const Code& stub = |
| 2857 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); | 2902 Code::Handle(StubCode::GetAllocationStubForClass(double_class_)); |
| 2858 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); | 2903 const ExternalLabel label(double_class_.ToCString(), stub.EntryPoint()); |
| 2859 GenerateCall(node->token_index(), &label); | 2904 GenerateCall(node->token_index(), &label); |
| 2860 // EAX is double object. | 2905 // EAX is double object. |
| 2861 DeoptimizationBlob* deopt_blob = | 2906 DeoptimizationBlob* deopt_blob = |
| 2862 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble); | 2907 AddDeoptimizationBlob(node, EBX, kDeoptIntegerToDouble); |
| 2863 __ popl(EBX); // Receiver | 2908 __ popl(EBX); // Receiver |
| 2864 __ testl(EBX, Immediate(kSmiTagMask)); | 2909 __ testl(EBX, Immediate(kSmiTagMask)); |
| 2865 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. | 2910 __ j(NOT_ZERO, deopt_blob->label()); // Deoptimize if not Smi. |
| 2866 __ SmiUntag(EBX); | 2911 __ SmiUntag(EBX); |
| 2867 __ cvtsi2sd(XMM0, EBX); | 2912 __ cvtsi2sd(XMM0, EBX); |
| 2868 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); | 2913 __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0); |
| 2869 return true; | 2914 return true; |
| 2870 } | 2915 } |
| 2871 | 2916 |
| 2872 if ((recognized == Recognizer::kDoubleToDouble) && | 2917 if ((recognized == Recognizer::kDoubleToDouble) && |
| 2873 AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { | 2918 AtIdNodeHasClassAt(node, node->id(), double_class_, 0)) { |
| 2874 DeoptimizationBlob* deopt_blob = | 2919 DeoptimizationBlob* deopt_blob = |
| 2875 AddDeoptimizationBlob(node, EAX, kDeoptDoubleToDouble); | 2920 AddDeoptimizationBlob(node, EAX, kDeoptDoubleToDouble); |
| 2876 __ popl(EAX); | 2921 __ popl(EAX); |
| 2877 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); | 2922 CheckIfDoubleOrSmi(EAX, EBX, deopt_blob->label(), deopt_blob->label()); |
| 2878 return true; | 2923 return true; |
| 2879 } | 2924 } |
| 2880 } | 2925 } |
| 2881 return false; | 2926 return false; |
| 2882 } | 2927 } |
| 2883 | 2928 |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3007 __ LoadObject(EAX, Bool::ZoneHandle(Bool::True())); | 3052 __ LoadObject(EAX, Bool::ZoneHandle(Bool::True())); |
| 3008 __ cmpl(EDX, EAX); | 3053 __ cmpl(EDX, EAX); |
| 3009 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 3054 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 3010 __ LoadObject(EAX, Bool::ZoneHandle(Bool::False())); | 3055 __ LoadObject(EAX, Bool::ZoneHandle(Bool::False())); |
| 3011 __ Bind(&done); | 3056 __ Bind(&done); |
| 3012 HandleResult(node, EAX); | 3057 HandleResult(node, EAX); |
| 3013 return; | 3058 return; |
| 3014 } | 3059 } |
| 3015 | 3060 |
| 3016 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) { | 3061 if ((node->kind() == Token::kSUB) || (node->kind() == Token::kBIT_NOT)) { |
| 3017 if (AtIdNodeHasReceiverClass(node, node->id(), smi_class_)) { | 3062 if (AtIdNodeHasClassAt(node, node->id(), smi_class_, 0)) { |
| 3018 const ICData& ic_data = node->ICDataAtId(node->id()); | 3063 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 3019 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); | 3064 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 3020 GenerateSmiUnaryOp(node); | 3065 GenerateSmiUnaryOp(node); |
| 3021 return; | 3066 return; |
| 3022 } | 3067 } |
| 3023 } | 3068 } |
| 3024 if (node->kind() == Token::kSUB) { | 3069 if (node->kind() == Token::kSUB) { |
| 3025 if (AtIdNodeHasReceiverClass(node, node->id(), double_class_)) { | 3070 if (AtIdNodeHasClassAt(node, node->id(), double_class_, 0)) { |
| 3026 const ICData& ic_data = node->ICDataAtId(node->id()); | 3071 const ICData& ic_data = node->ICDataAtId(node->id()); |
| 3027 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); | 3072 ASSERT(ic_data.NumberOfArgumentsChecked() == 1); |
| 3028 GenerateDoubleUnaryOp(node); | 3073 GenerateDoubleUnaryOp(node); |
| 3029 return; | 3074 return; |
| 3030 } | 3075 } |
| 3031 } | 3076 } |
| 3032 // TODO(srdjan): Implement unary kSUB (negate) Mint. | 3077 // TODO(srdjan): Implement unary kSUB (negate) Mint. |
| 3033 CodeGenerator::VisitUnaryOpNode(node); | 3078 CodeGenerator::VisitUnaryOpNode(node); |
| 3034 } | 3079 } |
| 3035 | 3080 |
| 3036 | 3081 |
| 3037 } // namespace dart | 3082 } // namespace dart |
| 3038 | 3083 |
| 3039 #endif // defined TARGET_ARCH_IA32 | 3084 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |