OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 717 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
728 | 728 |
729 // Similar to LoadSSE2Operands but assumes that both operands are smis. | 729 // Similar to LoadSSE2Operands but assumes that both operands are smis. |
730 // Expects operands in edx, eax. | 730 // Expects operands in edx, eax. |
731 static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); | 731 static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); |
732 | 732 |
733 // Checks that the two floating point numbers loaded into xmm0 and xmm1 | 733 // Checks that the two floating point numbers loaded into xmm0 and xmm1 |
734 // have int32 values. | 734 // have int32 values. |
735 static void CheckSSE2OperandsAreInt32(MacroAssembler* masm, | 735 static void CheckSSE2OperandsAreInt32(MacroAssembler* masm, |
736 Label* non_int32, | 736 Label* non_int32, |
737 Register scratch); | 737 Register scratch); |
| 738 |
| 739 static void CheckSSE2OperandIsInt32(MacroAssembler* masm, |
| 740 Label* non_int32, |
| 741 XMMRegister operand, |
| 742 Register scratch, |
| 743 XMMRegister xmm_scratch); |
738 }; | 744 }; |
739 | 745 |
740 | 746 |
741 // Get the integer part of a heap number. Surprisingly, all this bit twiddling | 747 // Get the integer part of a heap number. Surprisingly, all this bit twiddling |
742 // is faster than using the built-in instructions on floating point registers. | 748 // is faster than using the built-in instructions on floating point registers. |
743 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the | 749 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the |
744 // trashed registers. | 750 // trashed registers. |
745 static void IntegerConvert(MacroAssembler* masm, | 751 static void IntegerConvert(MacroAssembler* masm, |
746 Register source, | 752 Register source, |
747 bool use_sse3, | 753 bool use_sse3, |
748 Label* conversion_failure) { | 754 Label* conversion_failure) { |
749 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); | 755 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); |
750 Label done, right_exponent, normal_exponent; | 756 Label done, right_exponent, normal_exponent; |
751 Register scratch = ebx; | 757 Register scratch = ebx; |
752 Register scratch2 = edi; | 758 Register scratch2 = edi; |
753 // Get exponent word. | 759 // Get exponent word. |
754 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); | 760 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); |
755 // Get exponent alone in scratch2. | 761 // Get exponent alone in scratch2. |
756 __ mov(scratch2, scratch); | 762 __ mov(scratch2, scratch); |
757 __ and_(scratch2, HeapNumber::kExponentMask); | 763 __ and_(scratch2, HeapNumber::kExponentMask); |
| 764 __ shr(scratch2, HeapNumber::kExponentShift); |
| 765 __ sub(scratch2, Immediate(HeapNumber::kExponentBias)); |
| 766 // Load ecx with zero. We use this either for the final shift or |
| 767 // for the answer. |
| 768 __ xor_(ecx, ecx); |
| 769 // If the exponent is above 83, the number contains no significant |
| 770 // bits in the range 0..2^31, so the result is zero. |
| 771 static const uint32_t kResultIsZeroExponent = 83; |
| 772 __ cmp(scratch2, Immediate(kResultIsZeroExponent)); |
| 773 __ j(above, &done); |
758 if (use_sse3) { | 774 if (use_sse3) { |
759 CpuFeatures::Scope scope(SSE3); | 775 CpuFeatures::Scope scope(SSE3); |
760 // Check whether the exponent is too big for a 64 bit signed integer. | 776 // Check whether the exponent is too big for a 64 bit signed integer. |
761 static const uint32_t kTooBigExponent = | 777 static const uint32_t kTooBigExponent = 63; |
762 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; | |
763 __ cmp(scratch2, Immediate(kTooBigExponent)); | 778 __ cmp(scratch2, Immediate(kTooBigExponent)); |
764 __ j(greater_equal, conversion_failure); | 779 __ j(greater_equal, conversion_failure); |
765 // Load x87 register with heap number. | 780 // Load x87 register with heap number. |
766 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); | 781 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); |
767 // Reserve space for 64 bit answer. | 782 // Reserve space for 64 bit answer. |
768 __ sub(esp, Immediate(sizeof(uint64_t))); // Nolint. | 783 __ sub(esp, Immediate(sizeof(uint64_t))); // Nolint. |
769 // Do conversion, which cannot fail because we checked the exponent. | 784 // Do conversion, which cannot fail because we checked the exponent. |
770 __ fisttp_d(Operand(esp, 0)); | 785 __ fisttp_d(Operand(esp, 0)); |
771 __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. | 786 __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. |
772 __ add(esp, Immediate(sizeof(uint64_t))); // Nolint. | 787 __ add(esp, Immediate(sizeof(uint64_t))); // Nolint. |
773 } else { | 788 } else { |
774 // Load ecx with zero. We use this either for the final shift or | |
775 // for the answer. | |
776 __ xor_(ecx, ecx); | |
777 // Check whether the exponent matches a 32 bit signed int that cannot be | 789 // Check whether the exponent matches a 32 bit signed int that cannot be |
778 // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the | 790 // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the |
779 // exponent is 30 (biased). This is the exponent that we are fastest at and | 791 // exponent is 30 (biased). This is the exponent that we are fastest at and |
780 // also the highest exponent we can handle here. | 792 // also the highest exponent we can handle here. |
781 const uint32_t non_smi_exponent = | 793 const uint32_t non_smi_exponent = 30; |
782 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; | |
783 __ cmp(scratch2, Immediate(non_smi_exponent)); | 794 __ cmp(scratch2, Immediate(non_smi_exponent)); |
784 // If we have a match of the int32-but-not-Smi exponent then skip some | 795 // If we have a match of the int32-but-not-Smi exponent then skip some |
785 // logic. | 796 // logic. |
786 __ j(equal, &right_exponent, Label::kNear); | 797 __ j(equal, &right_exponent, Label::kNear); |
787 // If the exponent is higher than that then go to slow case. This catches | 798 // If the exponent is higher than that then go to slow case. This catches |
788 // numbers that don't fit in a signed int32, infinities and NaNs. | 799 // numbers that don't fit in a signed int32, infinities and NaNs. |
789 __ j(less, &normal_exponent, Label::kNear); | 800 __ j(less, &normal_exponent, Label::kNear); |
790 | 801 |
791 { | 802 { |
792 // Handle a big exponent. The only reason we have this code is that the | 803 // Handle a big exponent. The only reason we have this code is that the |
793 // >>> operator has a tendency to generate numbers with an exponent of 31. | 804 // >>> operator has a tendency to generate numbers with an exponent of 31. |
794 const uint32_t big_non_smi_exponent = | 805 const uint32_t big_non_smi_exponent = 31; |
795 (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; | |
796 __ cmp(scratch2, Immediate(big_non_smi_exponent)); | 806 __ cmp(scratch2, Immediate(big_non_smi_exponent)); |
797 __ j(not_equal, conversion_failure); | 807 __ j(not_equal, conversion_failure); |
798 // We have the big exponent, typically from >>>. This means the number is | 808 // We have the big exponent, typically from >>>. This means the number is |
799 // in the range 2^31 to 2^32 - 1. Get the top bits of the mantissa. | 809 // in the range 2^31 to 2^32 - 1. Get the top bits of the mantissa. |
800 __ mov(scratch2, scratch); | 810 __ mov(scratch2, scratch); |
801 __ and_(scratch2, HeapNumber::kMantissaMask); | 811 __ and_(scratch2, HeapNumber::kMantissaMask); |
802 // Put back the implicit 1. | 812 // Put back the implicit 1. |
803 __ or_(scratch2, 1 << HeapNumber::kExponentShift); | 813 __ or_(scratch2, 1 << HeapNumber::kExponentShift); |
804 // Shift up the mantissa bits to take up the space the exponent used to | 814 // Shift up the mantissa bits to take up the space the exponent used to |
805 // take. We just orred in the implicit bit so that took care of one and | 815 // take. We just orred in the implicit bit so that took care of one and |
806 // we want to use the full unsigned range so we subtract 1 bit from the | 816 // we want to use the full unsigned range so we subtract 1 bit from the |
807 // shift distance. | 817 // shift distance. |
808 const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; | 818 const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; |
809 __ shl(scratch2, big_shift_distance); | 819 __ shl(scratch2, big_shift_distance); |
810 // Get the second half of the double. | 820 // Get the second half of the double. |
811 __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset)); | 821 __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset)); |
812 // Shift down 21 bits to get the most significant 11 bits or the low | 822 // Shift down 21 bits to get the most significant 11 bits or the low |
813 // mantissa word. | 823 // mantissa word. |
814 __ shr(ecx, 32 - big_shift_distance); | 824 __ shr(ecx, 32 - big_shift_distance); |
815 __ or_(ecx, scratch2); | 825 __ or_(ecx, scratch2); |
816 // We have the answer in ecx, but we may need to negate it. | 826 // We have the answer in ecx, but we may need to negate it. |
817 __ test(scratch, scratch); | 827 __ test(scratch, scratch); |
818 __ j(positive, &done, Label::kNear); | 828 __ j(positive, &done, Label::kNear); |
819 __ neg(ecx); | 829 __ neg(ecx); |
820 __ jmp(&done, Label::kNear); | 830 __ jmp(&done, Label::kNear); |
821 } | 831 } |
822 | 832 |
823 __ bind(&normal_exponent); | 833 __ bind(&normal_exponent); |
824 // Exponent word in scratch, exponent part of exponent word in scratch2. | 834 // Exponent word in scratch, exponent in scratch2. Zero in ecx. |
825 // Zero in ecx. | 835 // We know that 0 <= exponent < 30. |
826 // We know the exponent is smaller than 30 (biased). If it is less than | |
827 // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e. | |
828 // it rounds to zero. | |
829 const uint32_t zero_exponent = | |
830 (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; | |
831 __ sub(scratch2, Immediate(zero_exponent)); | |
832 // ecx already has a Smi zero. | |
833 __ j(less, &done, Label::kNear); | |
834 | |
835 // We have a shifted exponent between 0 and 30 in scratch2. | |
836 __ shr(scratch2, HeapNumber::kExponentShift); | |
837 __ mov(ecx, Immediate(30)); | 836 __ mov(ecx, Immediate(30)); |
838 __ sub(ecx, scratch2); | 837 __ sub(ecx, scratch2); |
839 | 838 |
840 __ bind(&right_exponent); | 839 __ bind(&right_exponent); |
841 // Here ecx is the shift, scratch is the exponent word. | 840 // Here ecx is the shift, scratch is the exponent word. |
842 // Get the top bits of the mantissa. | 841 // Get the top bits of the mantissa. |
843 __ and_(scratch, HeapNumber::kMantissaMask); | 842 __ and_(scratch, HeapNumber::kMantissaMask); |
844 // Put back the implicit 1. | 843 // Put back the implicit 1. |
845 __ or_(scratch, 1 << HeapNumber::kExponentShift); | 844 __ or_(scratch, 1 << HeapNumber::kExponentShift); |
846 // Shift up the mantissa bits to take up the space the exponent used to | 845 // Shift up the mantissa bits to take up the space the exponent used to |
(...skipping 14 matching lines...) Expand all Loading... |
861 // Now the unsigned answer is in scratch2. We need to move it to ecx and | 860 // Now the unsigned answer is in scratch2. We need to move it to ecx and |
862 // we may need to fix the sign. | 861 // we may need to fix the sign. |
863 Label negative; | 862 Label negative; |
864 __ xor_(ecx, ecx); | 863 __ xor_(ecx, ecx); |
865 __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset)); | 864 __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset)); |
866 __ j(greater, &negative, Label::kNear); | 865 __ j(greater, &negative, Label::kNear); |
867 __ mov(ecx, scratch2); | 866 __ mov(ecx, scratch2); |
868 __ jmp(&done, Label::kNear); | 867 __ jmp(&done, Label::kNear); |
869 __ bind(&negative); | 868 __ bind(&negative); |
870 __ sub(ecx, scratch2); | 869 __ sub(ecx, scratch2); |
871 __ bind(&done); | |
872 } | 870 } |
| 871 __ bind(&done); |
873 } | 872 } |
874 | 873 |
875 | 874 |
876 void UnaryOpStub::PrintName(StringStream* stream) { | 875 void UnaryOpStub::PrintName(StringStream* stream) { |
877 const char* op_name = Token::Name(op_); | 876 const char* op_name = Token::Name(op_); |
878 const char* overwrite_name = NULL; // Make g++ happy. | 877 const char* overwrite_name = NULL; // Make g++ happy. |
879 switch (mode_) { | 878 switch (mode_) { |
880 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | 879 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; |
881 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; | 880 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; |
882 } | 881 } |
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1185 break; | 1184 break; |
1186 case Token::BIT_NOT: | 1185 case Token::BIT_NOT: |
1187 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); | 1186 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); |
1188 break; | 1187 break; |
1189 default: | 1188 default: |
1190 UNREACHABLE(); | 1189 UNREACHABLE(); |
1191 } | 1190 } |
1192 } | 1191 } |
1193 | 1192 |
1194 | 1193 |
| 1194 void BinaryOpStub::Initialize() { |
| 1195 platform_specific_bit_ = CpuFeatures::IsSupported(SSE3); |
| 1196 } |
| 1197 |
| 1198 |
1195 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 1199 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
1196 __ pop(ecx); // Save return address. | 1200 __ pop(ecx); // Save return address. |
1197 __ push(edx); | 1201 __ push(edx); |
1198 __ push(eax); | 1202 __ push(eax); |
1199 // Left and right arguments are now on top. | 1203 // Left and right arguments are now on top. |
1200 // Push this stub's key. Although the operation and the type info are | |
1201 // encoded into the key, the encoding is opaque, so push them too. | |
1202 __ push(Immediate(Smi::FromInt(MinorKey()))); | 1204 __ push(Immediate(Smi::FromInt(MinorKey()))); |
1203 __ push(Immediate(Smi::FromInt(op_))); | |
1204 __ push(Immediate(Smi::FromInt(operands_type_))); | |
1205 | 1205 |
1206 __ push(ecx); // Push return address. | 1206 __ push(ecx); // Push return address. |
1207 | 1207 |
1208 // Patch the caller to an appropriate specialized stub and return the | 1208 // Patch the caller to an appropriate specialized stub and return the |
1209 // operation result to the caller of the stub. | 1209 // operation result to the caller of the stub. |
1210 __ TailCallExternalReference( | 1210 __ TailCallExternalReference( |
1211 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), | 1211 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), |
1212 masm->isolate()), | 1212 masm->isolate()), |
1213 5, | 1213 3, |
1214 1); | 1214 1); |
1215 } | 1215 } |
1216 | 1216 |
1217 | 1217 |
1218 // Prepare for a type transition runtime call when the args are already on | 1218 // Prepare for a type transition runtime call when the args are already on |
1219 // the stack, under the return address. | 1219 // the stack, under the return address. |
1220 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) { | 1220 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) { |
1221 __ pop(ecx); // Save return address. | 1221 __ pop(ecx); // Save return address. |
1222 // Left and right arguments are already on top of the stack. | 1222 // Left and right arguments are already on top of the stack. |
1223 // Push this stub's key. Although the operation and the type info are | |
1224 // encoded into the key, the encoding is opaque, so push them too. | |
1225 __ push(Immediate(Smi::FromInt(MinorKey()))); | 1223 __ push(Immediate(Smi::FromInt(MinorKey()))); |
1226 __ push(Immediate(Smi::FromInt(op_))); | |
1227 __ push(Immediate(Smi::FromInt(operands_type_))); | |
1228 | 1224 |
1229 __ push(ecx); // Push return address. | 1225 __ push(ecx); // Push return address. |
1230 | 1226 |
1231 // Patch the caller to an appropriate specialized stub and return the | 1227 // Patch the caller to an appropriate specialized stub and return the |
1232 // operation result to the caller of the stub. | 1228 // operation result to the caller of the stub. |
1233 __ TailCallExternalReference( | 1229 __ TailCallExternalReference( |
1234 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), | 1230 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), |
1235 masm->isolate()), | 1231 masm->isolate()), |
1236 5, | 1232 3, |
1237 1); | 1233 1); |
1238 } | 1234 } |
1239 | 1235 |
1240 | 1236 |
1241 void BinaryOpStub::Generate(MacroAssembler* masm) { | 1237 static void BinaryOpStub_GenerateSmiCode( |
1242 // Explicitly allow generation of nested stubs. It is safe here because | |
1243 // generation code does not use any raw pointers. | |
1244 AllowStubCallsScope allow_stub_calls(masm, true); | |
1245 | |
1246 switch (operands_type_) { | |
1247 case BinaryOpIC::UNINITIALIZED: | |
1248 GenerateTypeTransition(masm); | |
1249 break; | |
1250 case BinaryOpIC::SMI: | |
1251 GenerateSmiStub(masm); | |
1252 break; | |
1253 case BinaryOpIC::INT32: | |
1254 GenerateInt32Stub(masm); | |
1255 break; | |
1256 case BinaryOpIC::HEAP_NUMBER: | |
1257 GenerateHeapNumberStub(masm); | |
1258 break; | |
1259 case BinaryOpIC::ODDBALL: | |
1260 GenerateOddballStub(masm); | |
1261 break; | |
1262 case BinaryOpIC::BOTH_STRING: | |
1263 GenerateBothStringStub(masm); | |
1264 break; | |
1265 case BinaryOpIC::STRING: | |
1266 GenerateStringStub(masm); | |
1267 break; | |
1268 case BinaryOpIC::GENERIC: | |
1269 GenerateGeneric(masm); | |
1270 break; | |
1271 default: | |
1272 UNREACHABLE(); | |
1273 } | |
1274 } | |
1275 | |
1276 | |
1277 void BinaryOpStub::PrintName(StringStream* stream) { | |
1278 const char* op_name = Token::Name(op_); | |
1279 const char* overwrite_name; | |
1280 switch (mode_) { | |
1281 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | |
1282 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | |
1283 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | |
1284 default: overwrite_name = "UnknownOverwrite"; break; | |
1285 } | |
1286 stream->Add("BinaryOpStub_%s_%s_%s", | |
1287 op_name, | |
1288 overwrite_name, | |
1289 BinaryOpIC::GetName(operands_type_)); | |
1290 } | |
1291 | |
1292 | |
1293 void BinaryOpStub::GenerateSmiCode( | |
1294 MacroAssembler* masm, | 1238 MacroAssembler* masm, |
1295 Label* slow, | 1239 Label* slow, |
1296 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { | 1240 BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results, |
| 1241 Token::Value op) { |
1297 // 1. Move arguments into edx, eax except for DIV and MOD, which need the | 1242 // 1. Move arguments into edx, eax except for DIV and MOD, which need the |
1298 // dividend in eax and edx free for the division. Use eax, ebx for those. | 1243 // dividend in eax and edx free for the division. Use eax, ebx for those. |
1299 Comment load_comment(masm, "-- Load arguments"); | 1244 Comment load_comment(masm, "-- Load arguments"); |
1300 Register left = edx; | 1245 Register left = edx; |
1301 Register right = eax; | 1246 Register right = eax; |
1302 if (op_ == Token::DIV || op_ == Token::MOD) { | 1247 if (op == Token::DIV || op == Token::MOD) { |
1303 left = eax; | 1248 left = eax; |
1304 right = ebx; | 1249 right = ebx; |
1305 __ mov(ebx, eax); | 1250 __ mov(ebx, eax); |
1306 __ mov(eax, edx); | 1251 __ mov(eax, edx); |
1307 } | 1252 } |
1308 | 1253 |
1309 | 1254 |
1310 // 2. Prepare the smi check of both operands by oring them together. | 1255 // 2. Prepare the smi check of both operands by oring them together. |
1311 Comment smi_check_comment(masm, "-- Smi check arguments"); | 1256 Comment smi_check_comment(masm, "-- Smi check arguments"); |
1312 Label not_smis; | 1257 Label not_smis; |
1313 Register combined = ecx; | 1258 Register combined = ecx; |
1314 ASSERT(!left.is(combined) && !right.is(combined)); | 1259 ASSERT(!left.is(combined) && !right.is(combined)); |
1315 switch (op_) { | 1260 switch (op) { |
1316 case Token::BIT_OR: | 1261 case Token::BIT_OR: |
1317 // Perform the operation into eax and smi check the result. Preserve | 1262 // Perform the operation into eax and smi check the result. Preserve |
1318 // eax in case the result is not a smi. | 1263 // eax in case the result is not a smi. |
1319 ASSERT(!left.is(ecx) && !right.is(ecx)); | 1264 ASSERT(!left.is(ecx) && !right.is(ecx)); |
1320 __ mov(ecx, right); | 1265 __ mov(ecx, right); |
1321 __ or_(right, left); // Bitwise or is commutative. | 1266 __ or_(right, left); // Bitwise or is commutative. |
1322 combined = right; | 1267 combined = right; |
1323 break; | 1268 break; |
1324 | 1269 |
1325 case Token::BIT_XOR: | 1270 case Token::BIT_XOR: |
(...skipping 23 matching lines...) Expand all Loading... |
1349 } | 1294 } |
1350 | 1295 |
1351 // 3. Perform the smi check of the operands. | 1296 // 3. Perform the smi check of the operands. |
1352 STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. | 1297 STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. |
1353 __ JumpIfNotSmi(combined, ¬_smis); | 1298 __ JumpIfNotSmi(combined, ¬_smis); |
1354 | 1299 |
1355 // 4. Operands are both smis, perform the operation leaving the result in | 1300 // 4. Operands are both smis, perform the operation leaving the result in |
1356 // eax and check the result if necessary. | 1301 // eax and check the result if necessary. |
1357 Comment perform_smi(masm, "-- Perform smi operation"); | 1302 Comment perform_smi(masm, "-- Perform smi operation"); |
1358 Label use_fp_on_smis; | 1303 Label use_fp_on_smis; |
1359 switch (op_) { | 1304 switch (op) { |
1360 case Token::BIT_OR: | 1305 case Token::BIT_OR: |
1361 // Nothing to do. | 1306 // Nothing to do. |
1362 break; | 1307 break; |
1363 | 1308 |
1364 case Token::BIT_XOR: | 1309 case Token::BIT_XOR: |
1365 ASSERT(right.is(eax)); | 1310 ASSERT(right.is(eax)); |
1366 __ xor_(right, left); // Bitwise xor is commutative. | 1311 __ xor_(right, left); // Bitwise xor is commutative. |
1367 break; | 1312 break; |
1368 | 1313 |
1369 case Token::BIT_AND: | 1314 case Token::BIT_AND: |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1483 __ NegativeZeroTest(edx, combined, slow); | 1428 __ NegativeZeroTest(edx, combined, slow); |
1484 // Move remainder to register eax. | 1429 // Move remainder to register eax. |
1485 __ mov(eax, edx); | 1430 __ mov(eax, edx); |
1486 break; | 1431 break; |
1487 | 1432 |
1488 default: | 1433 default: |
1489 UNREACHABLE(); | 1434 UNREACHABLE(); |
1490 } | 1435 } |
1491 | 1436 |
1492 // 5. Emit return of result in eax. Some operations have registers pushed. | 1437 // 5. Emit return of result in eax. Some operations have registers pushed. |
1493 switch (op_) { | 1438 switch (op) { |
1494 case Token::ADD: | 1439 case Token::ADD: |
1495 case Token::SUB: | 1440 case Token::SUB: |
1496 case Token::MUL: | 1441 case Token::MUL: |
1497 case Token::DIV: | 1442 case Token::DIV: |
1498 __ ret(0); | 1443 __ ret(0); |
1499 break; | 1444 break; |
1500 case Token::MOD: | 1445 case Token::MOD: |
1501 case Token::BIT_OR: | 1446 case Token::BIT_OR: |
1502 case Token::BIT_AND: | 1447 case Token::BIT_AND: |
1503 case Token::BIT_XOR: | 1448 case Token::BIT_XOR: |
1504 case Token::SAR: | 1449 case Token::SAR: |
1505 case Token::SHL: | 1450 case Token::SHL: |
1506 case Token::SHR: | 1451 case Token::SHR: |
1507 __ ret(2 * kPointerSize); | 1452 __ ret(2 * kPointerSize); |
1508 break; | 1453 break; |
1509 default: | 1454 default: |
1510 UNREACHABLE(); | 1455 UNREACHABLE(); |
1511 } | 1456 } |
1512 | 1457 |
1513 // 6. For some operations emit inline code to perform floating point | 1458 // 6. For some operations emit inline code to perform floating point |
1514 // operations on known smis (e.g., if the result of the operation | 1459 // operations on known smis (e.g., if the result of the operation |
1515 // overflowed the smi range). | 1460 // overflowed the smi range). |
1516 if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) { | 1461 if (allow_heapnumber_results == BinaryOpStub::NO_HEAPNUMBER_RESULTS) { |
1517 __ bind(&use_fp_on_smis); | 1462 __ bind(&use_fp_on_smis); |
1518 switch (op_) { | 1463 switch (op) { |
1519 // Undo the effects of some operations, and some register moves. | 1464 // Undo the effects of some operations, and some register moves. |
1520 case Token::SHL: | 1465 case Token::SHL: |
1521 // The arguments are saved on the stack, and only used from there. | 1466 // The arguments are saved on the stack, and only used from there. |
1522 break; | 1467 break; |
1523 case Token::ADD: | 1468 case Token::ADD: |
1524 // Revert right = right + left. | 1469 // Revert right = right + left. |
1525 __ sub(right, left); | 1470 __ sub(right, left); |
1526 break; | 1471 break; |
1527 case Token::SUB: | 1472 case Token::SUB: |
1528 // Revert left = left - right. | 1473 // Revert left = left - right. |
1529 __ add(left, right); | 1474 __ add(left, right); |
1530 break; | 1475 break; |
1531 case Token::MUL: | 1476 case Token::MUL: |
1532 // Right was clobbered but a copy is in ebx. | 1477 // Right was clobbered but a copy is in ebx. |
1533 __ mov(right, ebx); | 1478 __ mov(right, ebx); |
1534 break; | 1479 break; |
1535 case Token::DIV: | 1480 case Token::DIV: |
1536 // Left was clobbered but a copy is in edi. Right is in ebx for | 1481 // Left was clobbered but a copy is in edi. Right is in ebx for |
1537 // division. They should be in eax, ebx for jump to not_smi. | 1482 // division. They should be in eax, ebx for jump to not_smi. |
1538 __ mov(eax, edi); | 1483 __ mov(eax, edi); |
1539 break; | 1484 break; |
1540 default: | 1485 default: |
1541 // No other operators jump to use_fp_on_smis. | 1486 // No other operators jump to use_fp_on_smis. |
1542 break; | 1487 break; |
1543 } | 1488 } |
1544 __ jmp(¬_smis); | 1489 __ jmp(¬_smis); |
1545 } else { | 1490 } else { |
1546 ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS); | 1491 ASSERT(allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS); |
1547 switch (op_) { | 1492 switch (op) { |
1548 case Token::SHL: | 1493 case Token::SHL: |
1549 case Token::SHR: { | 1494 case Token::SHR: { |
1550 Comment perform_float(masm, "-- Perform float operation on smis"); | 1495 Comment perform_float(masm, "-- Perform float operation on smis"); |
1551 __ bind(&use_fp_on_smis); | 1496 __ bind(&use_fp_on_smis); |
1552 // Result we want is in left == edx, so we can put the allocated heap | 1497 // Result we want is in left == edx, so we can put the allocated heap |
1553 // number in eax. | 1498 // number in eax. |
1554 __ AllocateHeapNumber(eax, ecx, ebx, slow); | 1499 __ AllocateHeapNumber(eax, ecx, ebx, slow); |
1555 // Store the result in the HeapNumber and return. | 1500 // Store the result in the HeapNumber and return. |
1556 // It's OK to overwrite the arguments on the stack because we | 1501 // It's OK to overwrite the arguments on the stack because we |
1557 // are about to return. | 1502 // are about to return. |
1558 if (op_ == Token::SHR) { | 1503 if (op == Token::SHR) { |
1559 __ mov(Operand(esp, 1 * kPointerSize), left); | 1504 __ mov(Operand(esp, 1 * kPointerSize), left); |
1560 __ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); | 1505 __ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); |
1561 __ fild_d(Operand(esp, 1 * kPointerSize)); | 1506 __ fild_d(Operand(esp, 1 * kPointerSize)); |
1562 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 1507 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
1563 } else { | 1508 } else { |
1564 ASSERT_EQ(Token::SHL, op_); | 1509 ASSERT_EQ(Token::SHL, op); |
1565 if (CpuFeatures::IsSupported(SSE2)) { | 1510 if (CpuFeatures::IsSupported(SSE2)) { |
1566 CpuFeatures::Scope use_sse2(SSE2); | 1511 CpuFeatures::Scope use_sse2(SSE2); |
1567 __ cvtsi2sd(xmm0, left); | 1512 __ cvtsi2sd(xmm0, left); |
1568 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 1513 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
1569 } else { | 1514 } else { |
1570 __ mov(Operand(esp, 1 * kPointerSize), left); | 1515 __ mov(Operand(esp, 1 * kPointerSize), left); |
1571 __ fild_s(Operand(esp, 1 * kPointerSize)); | 1516 __ fild_s(Operand(esp, 1 * kPointerSize)); |
1572 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 1517 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
1573 } | 1518 } |
1574 } | 1519 } |
1575 __ ret(2 * kPointerSize); | 1520 __ ret(2 * kPointerSize); |
1576 break; | 1521 break; |
1577 } | 1522 } |
1578 | 1523 |
1579 case Token::ADD: | 1524 case Token::ADD: |
1580 case Token::SUB: | 1525 case Token::SUB: |
1581 case Token::MUL: | 1526 case Token::MUL: |
1582 case Token::DIV: { | 1527 case Token::DIV: { |
1583 Comment perform_float(masm, "-- Perform float operation on smis"); | 1528 Comment perform_float(masm, "-- Perform float operation on smis"); |
1584 __ bind(&use_fp_on_smis); | 1529 __ bind(&use_fp_on_smis); |
1585 // Restore arguments to edx, eax. | 1530 // Restore arguments to edx, eax. |
1586 switch (op_) { | 1531 switch (op) { |
1587 case Token::ADD: | 1532 case Token::ADD: |
1588 // Revert right = right + left. | 1533 // Revert right = right + left. |
1589 __ sub(right, left); | 1534 __ sub(right, left); |
1590 break; | 1535 break; |
1591 case Token::SUB: | 1536 case Token::SUB: |
1592 // Revert left = left - right. | 1537 // Revert left = left - right. |
1593 __ add(left, right); | 1538 __ add(left, right); |
1594 break; | 1539 break; |
1595 case Token::MUL: | 1540 case Token::MUL: |
1596 // Right was clobbered but a copy is in ebx. | 1541 // Right was clobbered but a copy is in ebx. |
1597 __ mov(right, ebx); | 1542 __ mov(right, ebx); |
1598 break; | 1543 break; |
1599 case Token::DIV: | 1544 case Token::DIV: |
1600 // Left was clobbered but a copy is in edi. Right is in ebx for | 1545 // Left was clobbered but a copy is in edi. Right is in ebx for |
1601 // division. | 1546 // division. |
1602 __ mov(edx, edi); | 1547 __ mov(edx, edi); |
1603 __ mov(eax, right); | 1548 __ mov(eax, right); |
1604 break; | 1549 break; |
1605 default: UNREACHABLE(); | 1550 default: UNREACHABLE(); |
1606 break; | 1551 break; |
1607 } | 1552 } |
1608 __ AllocateHeapNumber(ecx, ebx, no_reg, slow); | 1553 __ AllocateHeapNumber(ecx, ebx, no_reg, slow); |
1609 if (CpuFeatures::IsSupported(SSE2)) { | 1554 if (CpuFeatures::IsSupported(SSE2)) { |
1610 CpuFeatures::Scope use_sse2(SSE2); | 1555 CpuFeatures::Scope use_sse2(SSE2); |
1611 FloatingPointHelper::LoadSSE2Smis(masm, ebx); | 1556 FloatingPointHelper::LoadSSE2Smis(masm, ebx); |
1612 switch (op_) { | 1557 switch (op) { |
1613 case Token::ADD: __ addsd(xmm0, xmm1); break; | 1558 case Token::ADD: __ addsd(xmm0, xmm1); break; |
1614 case Token::SUB: __ subsd(xmm0, xmm1); break; | 1559 case Token::SUB: __ subsd(xmm0, xmm1); break; |
1615 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 1560 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
1616 case Token::DIV: __ divsd(xmm0, xmm1); break; | 1561 case Token::DIV: __ divsd(xmm0, xmm1); break; |
1617 default: UNREACHABLE(); | 1562 default: UNREACHABLE(); |
1618 } | 1563 } |
1619 __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); | 1564 __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); |
1620 } else { // SSE2 not available, use FPU. | 1565 } else { // SSE2 not available, use FPU. |
1621 FloatingPointHelper::LoadFloatSmis(masm, ebx); | 1566 FloatingPointHelper::LoadFloatSmis(masm, ebx); |
1622 switch (op_) { | 1567 switch (op) { |
1623 case Token::ADD: __ faddp(1); break; | 1568 case Token::ADD: __ faddp(1); break; |
1624 case Token::SUB: __ fsubp(1); break; | 1569 case Token::SUB: __ fsubp(1); break; |
1625 case Token::MUL: __ fmulp(1); break; | 1570 case Token::MUL: __ fmulp(1); break; |
1626 case Token::DIV: __ fdivp(1); break; | 1571 case Token::DIV: __ fdivp(1); break; |
1627 default: UNREACHABLE(); | 1572 default: UNREACHABLE(); |
1628 } | 1573 } |
1629 __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset)); | 1574 __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset)); |
1630 } | 1575 } |
1631 __ mov(eax, ecx); | 1576 __ mov(eax, ecx); |
1632 __ ret(0); | 1577 __ ret(0); |
1633 break; | 1578 break; |
1634 } | 1579 } |
1635 | 1580 |
1636 default: | 1581 default: |
1637 break; | 1582 break; |
1638 } | 1583 } |
1639 } | 1584 } |
1640 | 1585 |
1641 // 7. Non-smi operands, fall out to the non-smi code with the operands in | 1586 // 7. Non-smi operands, fall out to the non-smi code with the operands in |
1642 // edx and eax. | 1587 // edx and eax. |
1643 Comment done_comment(masm, "-- Enter non-smi code"); | 1588 Comment done_comment(masm, "-- Enter non-smi code"); |
1644 __ bind(¬_smis); | 1589 __ bind(¬_smis); |
1645 switch (op_) { | 1590 switch (op) { |
1646 case Token::BIT_OR: | 1591 case Token::BIT_OR: |
1647 case Token::SHL: | 1592 case Token::SHL: |
1648 case Token::SAR: | 1593 case Token::SAR: |
1649 case Token::SHR: | 1594 case Token::SHR: |
1650 // Right operand is saved in ecx and eax was destroyed by the smi | 1595 // Right operand is saved in ecx and eax was destroyed by the smi |
1651 // check. | 1596 // check. |
1652 __ mov(eax, ecx); | 1597 __ mov(eax, ecx); |
1653 break; | 1598 break; |
1654 | 1599 |
1655 case Token::DIV: | 1600 case Token::DIV: |
(...skipping 26 matching lines...) Expand all Loading... |
1682 case Token::SHL: | 1627 case Token::SHL: |
1683 case Token::SHR: | 1628 case Token::SHR: |
1684 GenerateRegisterArgsPush(masm); | 1629 GenerateRegisterArgsPush(masm); |
1685 break; | 1630 break; |
1686 default: | 1631 default: |
1687 UNREACHABLE(); | 1632 UNREACHABLE(); |
1688 } | 1633 } |
1689 | 1634 |
1690 if (result_type_ == BinaryOpIC::UNINITIALIZED || | 1635 if (result_type_ == BinaryOpIC::UNINITIALIZED || |
1691 result_type_ == BinaryOpIC::SMI) { | 1636 result_type_ == BinaryOpIC::SMI) { |
1692 GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS); | 1637 BinaryOpStub_GenerateSmiCode( |
| 1638 masm, &call_runtime, NO_HEAPNUMBER_RESULTS, op_); |
1693 } else { | 1639 } else { |
1694 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); | 1640 BinaryOpStub_GenerateSmiCode( |
| 1641 masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_); |
1695 } | 1642 } |
1696 __ bind(&call_runtime); | 1643 __ bind(&call_runtime); |
1697 switch (op_) { | 1644 switch (op_) { |
1698 case Token::ADD: | 1645 case Token::ADD: |
1699 case Token::SUB: | 1646 case Token::SUB: |
1700 case Token::MUL: | 1647 case Token::MUL: |
1701 case Token::DIV: | 1648 case Token::DIV: |
1702 GenerateTypeTransition(masm); | 1649 GenerateTypeTransition(masm); |
1703 break; | 1650 break; |
1704 case Token::MOD: | 1651 case Token::MOD: |
1705 case Token::BIT_OR: | 1652 case Token::BIT_OR: |
1706 case Token::BIT_AND: | 1653 case Token::BIT_AND: |
1707 case Token::BIT_XOR: | 1654 case Token::BIT_XOR: |
1708 case Token::SAR: | 1655 case Token::SAR: |
1709 case Token::SHL: | 1656 case Token::SHL: |
1710 case Token::SHR: | 1657 case Token::SHR: |
1711 GenerateTypeTransitionWithSavedArgs(masm); | 1658 GenerateTypeTransitionWithSavedArgs(masm); |
1712 break; | 1659 break; |
1713 default: | 1660 default: |
1714 UNREACHABLE(); | 1661 UNREACHABLE(); |
1715 } | 1662 } |
1716 } | 1663 } |
1717 | 1664 |
1718 | 1665 |
1719 void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { | |
1720 ASSERT(operands_type_ == BinaryOpIC::STRING); | |
1721 ASSERT(op_ == Token::ADD); | |
1722 // Try to add arguments as strings, otherwise, transition to the generic | |
1723 // BinaryOpIC type. | |
1724 GenerateAddStrings(masm); | |
1725 GenerateTypeTransition(masm); | |
1726 } | |
1727 | |
1728 | |
1729 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { | 1666 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { |
1730 Label call_runtime; | 1667 Label call_runtime; |
1731 ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); | 1668 ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING); |
1732 ASSERT(op_ == Token::ADD); | 1669 ASSERT(op_ == Token::ADD); |
1733 // If both arguments are strings, call the string add stub. | 1670 // If both arguments are strings, call the string add stub. |
1734 // Otherwise, do a transition. | 1671 // Otherwise, do a transition. |
1735 | 1672 |
1736 // Registers containing left and right operands respectively. | 1673 // Registers containing left and right operands respectively. |
1737 Register left = edx; | 1674 Register left = edx; |
1738 Register right = eax; | 1675 Register right = eax; |
1739 | 1676 |
1740 // Test if left operand is a string. | 1677 // Test if left operand is a string. |
1741 __ JumpIfSmi(left, &call_runtime, Label::kNear); | 1678 __ JumpIfSmi(left, &call_runtime, Label::kNear); |
1742 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); | 1679 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); |
1743 __ j(above_equal, &call_runtime, Label::kNear); | 1680 __ j(above_equal, &call_runtime, Label::kNear); |
1744 | 1681 |
1745 // Test if right operand is a string. | 1682 // Test if right operand is a string. |
1746 __ JumpIfSmi(right, &call_runtime, Label::kNear); | 1683 __ JumpIfSmi(right, &call_runtime, Label::kNear); |
1747 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); | 1684 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); |
1748 __ j(above_equal, &call_runtime, Label::kNear); | 1685 __ j(above_equal, &call_runtime, Label::kNear); |
1749 | 1686 |
1750 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); | 1687 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); |
1751 GenerateRegisterArgsPush(masm); | 1688 GenerateRegisterArgsPush(masm); |
1752 __ TailCallStub(&string_add_stub); | 1689 __ TailCallStub(&string_add_stub); |
1753 | 1690 |
1754 __ bind(&call_runtime); | 1691 __ bind(&call_runtime); |
1755 GenerateTypeTransition(masm); | 1692 GenerateTypeTransition(masm); |
1756 } | 1693 } |
1757 | 1694 |
1758 | 1695 |
| 1696 static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, |
| 1697 Label* alloc_failure, |
| 1698 OverwriteMode mode); |
| 1699 |
| 1700 |
1759 // Input: | 1701 // Input: |
1760 // edx: left operand (tagged) | 1702 // edx: left operand (tagged) |
1761 // eax: right operand (tagged) | 1703 // eax: right operand (tagged) |
1762 // Output: | 1704 // Output: |
1763 // eax: result (tagged) | 1705 // eax: result (tagged) |
1764 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { | 1706 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { |
1765 Label call_runtime; | 1707 Label call_runtime; |
1766 ASSERT(operands_type_ == BinaryOpIC::INT32); | 1708 ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32); |
1767 | 1709 |
1768 // Floating point case. | 1710 // Floating point case. |
1769 switch (op_) { | 1711 switch (op_) { |
1770 case Token::ADD: | 1712 case Token::ADD: |
1771 case Token::SUB: | 1713 case Token::SUB: |
1772 case Token::MUL: | 1714 case Token::MUL: |
1773 case Token::DIV: | 1715 case Token::DIV: |
1774 case Token::MOD: { | 1716 case Token::MOD: { |
1775 Label not_floats; | 1717 Label not_floats; |
1776 Label not_int32; | 1718 Label not_int32; |
1777 if (CpuFeatures::IsSupported(SSE2)) { | 1719 if (CpuFeatures::IsSupported(SSE2)) { |
1778 CpuFeatures::Scope use_sse2(SSE2); | 1720 CpuFeatures::Scope use_sse2(SSE2); |
| 1721 // It could be that only SMIs have been seen at either the left |
| 1722 // or the right operand. For precise type feedback, patch the IC |
| 1723 // again if this changes. |
| 1724 // In theory, we would need the same check in the non-SSE2 case, |
| 1725 // but since we don't support Crankshaft on such hardware we can |
| 1726 // afford not to care about precise type feedback. |
| 1727 if (left_type_ == BinaryOpIC::SMI) { |
| 1728 __ JumpIfNotSmi(edx, ¬_int32); |
| 1729 } |
| 1730 if (right_type_ == BinaryOpIC::SMI) { |
| 1731 __ JumpIfNotSmi(eax, ¬_int32); |
| 1732 } |
1779 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); | 1733 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
1780 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); | 1734 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); |
1781 if (op_ == Token::MOD) { | 1735 if (op_ == Token::MOD) { |
1782 GenerateRegisterArgsPush(masm); | 1736 GenerateRegisterArgsPush(masm); |
1783 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); | 1737 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); |
1784 } else { | 1738 } else { |
1785 switch (op_) { | 1739 switch (op_) { |
1786 case Token::ADD: __ addsd(xmm0, xmm1); break; | 1740 case Token::ADD: __ addsd(xmm0, xmm1); break; |
1787 case Token::SUB: __ subsd(xmm0, xmm1); break; | 1741 case Token::SUB: __ subsd(xmm0, xmm1); break; |
1788 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 1742 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
1789 case Token::DIV: __ divsd(xmm0, xmm1); break; | 1743 case Token::DIV: __ divsd(xmm0, xmm1); break; |
1790 default: UNREACHABLE(); | 1744 default: UNREACHABLE(); |
1791 } | 1745 } |
1792 // Check result type if it is currently Int32. | 1746 // Check result type if it is currently Int32. |
1793 if (result_type_ <= BinaryOpIC::INT32) { | 1747 if (result_type_ <= BinaryOpIC::INT32) { |
1794 __ cvttsd2si(ecx, Operand(xmm0)); | 1748 __ cvttsd2si(ecx, Operand(xmm0)); |
1795 __ cvtsi2sd(xmm2, ecx); | 1749 __ cvtsi2sd(xmm2, ecx); |
1796 __ pcmpeqd(xmm2, xmm0); | 1750 __ pcmpeqd(xmm2, xmm0); |
1797 __ movmskpd(ecx, xmm2); | 1751 __ movmskpd(ecx, xmm2); |
1798 __ test(ecx, Immediate(1)); | 1752 __ test(ecx, Immediate(1)); |
1799 __ j(zero, ¬_int32); | 1753 __ j(zero, ¬_int32); |
1800 } | 1754 } |
1801 GenerateHeapResultAllocation(masm, &call_runtime); | 1755 BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_); |
1802 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 1756 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
1803 __ ret(0); | 1757 __ ret(0); |
1804 } | 1758 } |
1805 } else { // SSE2 not available, use FPU. | 1759 } else { // SSE2 not available, use FPU. |
1806 FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); | 1760 FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); |
1807 FloatingPointHelper::LoadFloatOperands( | 1761 FloatingPointHelper::LoadFloatOperands( |
1808 masm, | 1762 masm, |
1809 ecx, | 1763 ecx, |
1810 FloatingPointHelper::ARGS_IN_REGISTERS); | 1764 FloatingPointHelper::ARGS_IN_REGISTERS); |
1811 FloatingPointHelper::CheckFloatOperandsAreInt32(masm, ¬_int32); | 1765 FloatingPointHelper::CheckFloatOperandsAreInt32(masm, ¬_int32); |
1812 if (op_ == Token::MOD) { | 1766 if (op_ == Token::MOD) { |
1813 // The operands are now on the FPU stack, but we don't need them. | 1767 // The operands are now on the FPU stack, but we don't need them. |
1814 __ fstp(0); | 1768 __ fstp(0); |
1815 __ fstp(0); | 1769 __ fstp(0); |
1816 GenerateRegisterArgsPush(masm); | 1770 GenerateRegisterArgsPush(masm); |
1817 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); | 1771 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); |
1818 } else { | 1772 } else { |
1819 switch (op_) { | 1773 switch (op_) { |
1820 case Token::ADD: __ faddp(1); break; | 1774 case Token::ADD: __ faddp(1); break; |
1821 case Token::SUB: __ fsubp(1); break; | 1775 case Token::SUB: __ fsubp(1); break; |
1822 case Token::MUL: __ fmulp(1); break; | 1776 case Token::MUL: __ fmulp(1); break; |
1823 case Token::DIV: __ fdivp(1); break; | 1777 case Token::DIV: __ fdivp(1); break; |
1824 default: UNREACHABLE(); | 1778 default: UNREACHABLE(); |
1825 } | 1779 } |
1826 Label after_alloc_failure; | 1780 Label after_alloc_failure; |
1827 GenerateHeapResultAllocation(masm, &after_alloc_failure); | 1781 BinaryOpStub_GenerateHeapResultAllocation( |
| 1782 masm, &after_alloc_failure, mode_); |
1828 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 1783 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
1829 __ ret(0); | 1784 __ ret(0); |
1830 __ bind(&after_alloc_failure); | 1785 __ bind(&after_alloc_failure); |
1831 __ fstp(0); // Pop FPU stack before calling runtime. | 1786 __ fstp(0); // Pop FPU stack before calling runtime. |
1832 __ jmp(&call_runtime); | 1787 __ jmp(&call_runtime); |
1833 } | 1788 } |
1834 } | 1789 } |
1835 | 1790 |
1836 __ bind(¬_floats); | 1791 __ bind(¬_floats); |
1837 __ bind(¬_int32); | 1792 __ bind(¬_int32); |
1838 GenerateTypeTransition(masm); | 1793 GenerateTypeTransition(masm); |
1839 break; | 1794 break; |
1840 } | 1795 } |
1841 | 1796 |
1842 case Token::BIT_OR: | 1797 case Token::BIT_OR: |
1843 case Token::BIT_AND: | 1798 case Token::BIT_AND: |
1844 case Token::BIT_XOR: | 1799 case Token::BIT_XOR: |
1845 case Token::SAR: | 1800 case Token::SAR: |
1846 case Token::SHL: | 1801 case Token::SHL: |
1847 case Token::SHR: { | 1802 case Token::SHR: { |
1848 GenerateRegisterArgsPush(masm); | 1803 GenerateRegisterArgsPush(masm); |
1849 Label not_floats; | 1804 Label not_floats; |
1850 Label not_int32; | 1805 Label not_int32; |
1851 Label non_smi_result; | 1806 Label non_smi_result; |
| 1807 // We do not check the input arguments here, as any value is |
| 1808 // unconditionally truncated to an int32 anyway. To get the |
| 1809 // right optimized code, int32 type feedback is just right. |
| 1810 bool use_sse3 = platform_specific_bit_; |
1852 FloatingPointHelper::LoadUnknownsAsIntegers(masm, | 1811 FloatingPointHelper::LoadUnknownsAsIntegers(masm, |
1853 use_sse3_, | 1812 use_sse3, |
1854 ¬_floats); | 1813 ¬_floats); |
1855 FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_, | 1814 FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3, |
1856 ¬_int32); | 1815 ¬_int32); |
1857 switch (op_) { | 1816 switch (op_) { |
1858 case Token::BIT_OR: __ or_(eax, ecx); break; | 1817 case Token::BIT_OR: __ or_(eax, ecx); break; |
1859 case Token::BIT_AND: __ and_(eax, ecx); break; | 1818 case Token::BIT_AND: __ and_(eax, ecx); break; |
1860 case Token::BIT_XOR: __ xor_(eax, ecx); break; | 1819 case Token::BIT_XOR: __ xor_(eax, ecx); break; |
1861 case Token::SAR: __ sar_cl(eax); break; | 1820 case Token::SAR: __ sar_cl(eax); break; |
1862 case Token::SHL: __ shl_cl(eax); break; | 1821 case Token::SHL: __ shl_cl(eax); break; |
1863 case Token::SHR: __ shr_cl(eax); break; | 1822 case Token::SHR: __ shr_cl(eax); break; |
1864 default: UNREACHABLE(); | 1823 default: UNREACHABLE(); |
1865 } | 1824 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1918 } | 1877 } |
1919 default: UNREACHABLE(); break; | 1878 default: UNREACHABLE(); break; |
1920 } | 1879 } |
1921 | 1880 |
1922 // If an allocation fails, or SHR hits a hard case, use the runtime system to | 1881 // If an allocation fails, or SHR hits a hard case, use the runtime system to |
1923 // get the correct result. | 1882 // get the correct result. |
1924 __ bind(&call_runtime); | 1883 __ bind(&call_runtime); |
1925 | 1884 |
1926 switch (op_) { | 1885 switch (op_) { |
1927 case Token::ADD: | 1886 case Token::ADD: |
1928 GenerateRegisterArgsPush(masm); | |
1929 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); | |
1930 break; | |
1931 case Token::SUB: | 1887 case Token::SUB: |
1932 GenerateRegisterArgsPush(masm); | |
1933 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); | |
1934 break; | |
1935 case Token::MUL: | 1888 case Token::MUL: |
1936 GenerateRegisterArgsPush(masm); | |
1937 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); | |
1938 break; | |
1939 case Token::DIV: | 1889 case Token::DIV: |
1940 GenerateRegisterArgsPush(masm); | 1890 GenerateRegisterArgsPush(masm); |
1941 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); | |
1942 break; | 1891 break; |
1943 case Token::MOD: | 1892 case Token::MOD: |
1944 break; | 1893 return; // Handled above. |
1945 case Token::BIT_OR: | 1894 case Token::BIT_OR: |
1946 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); | |
1947 break; | |
1948 case Token::BIT_AND: | 1895 case Token::BIT_AND: |
1949 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); | |
1950 break; | |
1951 case Token::BIT_XOR: | 1896 case Token::BIT_XOR: |
1952 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); | |
1953 break; | |
1954 case Token::SAR: | 1897 case Token::SAR: |
1955 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); | |
1956 break; | |
1957 case Token::SHL: | 1898 case Token::SHL: |
1958 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); | |
1959 break; | |
1960 case Token::SHR: | 1899 case Token::SHR: |
1961 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | |
1962 break; | 1900 break; |
1963 default: | 1901 default: |
1964 UNREACHABLE(); | 1902 UNREACHABLE(); |
1965 } | 1903 } |
| 1904 GenerateCallRuntime(masm); |
1966 } | 1905 } |
1967 | 1906 |
1968 | 1907 |
1969 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | 1908 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { |
1970 if (op_ == Token::ADD) { | 1909 if (op_ == Token::ADD) { |
1971 // Handle string addition here, because it is the only operation | 1910 // Handle string addition here, because it is the only operation |
1972 // that does not do a ToNumber conversion on the operands. | 1911 // that does not do a ToNumber conversion on the operands. |
1973 GenerateAddStrings(masm); | 1912 GenerateAddStrings(masm); |
1974 } | 1913 } |
1975 | 1914 |
(...skipping 28 matching lines...) Expand all Loading... |
2004 | 1943 |
2005 // Floating point case. | 1944 // Floating point case. |
2006 switch (op_) { | 1945 switch (op_) { |
2007 case Token::ADD: | 1946 case Token::ADD: |
2008 case Token::SUB: | 1947 case Token::SUB: |
2009 case Token::MUL: | 1948 case Token::MUL: |
2010 case Token::DIV: { | 1949 case Token::DIV: { |
2011 Label not_floats; | 1950 Label not_floats; |
2012 if (CpuFeatures::IsSupported(SSE2)) { | 1951 if (CpuFeatures::IsSupported(SSE2)) { |
2013 CpuFeatures::Scope use_sse2(SSE2); | 1952 CpuFeatures::Scope use_sse2(SSE2); |
| 1953 |
| 1954 // It could be that only SMIs have been seen at either the left |
| 1955 // or the right operand. For precise type feedback, patch the IC |
| 1956 // again if this changes. |
| 1957 // In theory, we would need the same check in the non-SSE2 case, |
| 1958 // but since we don't support Crankshaft on such hardware we can |
| 1959 // afford not to care about precise type feedback. |
| 1960 if (left_type_ == BinaryOpIC::SMI) { |
| 1961 __ JumpIfNotSmi(edx, ¬_floats); |
| 1962 } |
| 1963 if (right_type_ == BinaryOpIC::SMI) { |
| 1964 __ JumpIfNotSmi(eax, ¬_floats); |
| 1965 } |
2014 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); | 1966 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
| 1967 if (left_type_ == BinaryOpIC::INT32) { |
| 1968 FloatingPointHelper::CheckSSE2OperandIsInt32( |
| 1969 masm, ¬_floats, xmm0, ecx, xmm2); |
| 1970 } |
| 1971 if (right_type_ == BinaryOpIC::INT32) { |
| 1972 FloatingPointHelper::CheckSSE2OperandIsInt32( |
| 1973 masm, ¬_floats, xmm1, ecx, xmm2); |
| 1974 } |
2015 | 1975 |
2016 switch (op_) { | 1976 switch (op_) { |
2017 case Token::ADD: __ addsd(xmm0, xmm1); break; | 1977 case Token::ADD: __ addsd(xmm0, xmm1); break; |
2018 case Token::SUB: __ subsd(xmm0, xmm1); break; | 1978 case Token::SUB: __ subsd(xmm0, xmm1); break; |
2019 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 1979 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
2020 case Token::DIV: __ divsd(xmm0, xmm1); break; | 1980 case Token::DIV: __ divsd(xmm0, xmm1); break; |
2021 default: UNREACHABLE(); | 1981 default: UNREACHABLE(); |
2022 } | 1982 } |
2023 GenerateHeapResultAllocation(masm, &call_runtime); | 1983 BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_); |
2024 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 1984 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
2025 __ ret(0); | 1985 __ ret(0); |
2026 } else { // SSE2 not available, use FPU. | 1986 } else { // SSE2 not available, use FPU. |
2027 FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); | 1987 FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); |
2028 FloatingPointHelper::LoadFloatOperands( | 1988 FloatingPointHelper::LoadFloatOperands( |
2029 masm, | 1989 masm, |
2030 ecx, | 1990 ecx, |
2031 FloatingPointHelper::ARGS_IN_REGISTERS); | 1991 FloatingPointHelper::ARGS_IN_REGISTERS); |
2032 switch (op_) { | 1992 switch (op_) { |
2033 case Token::ADD: __ faddp(1); break; | 1993 case Token::ADD: __ faddp(1); break; |
2034 case Token::SUB: __ fsubp(1); break; | 1994 case Token::SUB: __ fsubp(1); break; |
2035 case Token::MUL: __ fmulp(1); break; | 1995 case Token::MUL: __ fmulp(1); break; |
2036 case Token::DIV: __ fdivp(1); break; | 1996 case Token::DIV: __ fdivp(1); break; |
2037 default: UNREACHABLE(); | 1997 default: UNREACHABLE(); |
2038 } | 1998 } |
2039 Label after_alloc_failure; | 1999 Label after_alloc_failure; |
2040 GenerateHeapResultAllocation(masm, &after_alloc_failure); | 2000 BinaryOpStub_GenerateHeapResultAllocation( |
| 2001 masm, &after_alloc_failure, mode_); |
2041 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 2002 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
2042 __ ret(0); | 2003 __ ret(0); |
2043 __ bind(&after_alloc_failure); | 2004 __ bind(&after_alloc_failure); |
2044 __ fstp(0); // Pop FPU stack before calling runtime. | 2005 __ fstp(0); // Pop FPU stack before calling runtime. |
2045 __ jmp(&call_runtime); | 2006 __ jmp(&call_runtime); |
2046 } | 2007 } |
2047 | 2008 |
2048 __ bind(¬_floats); | 2009 __ bind(¬_floats); |
2049 GenerateTypeTransition(masm); | 2010 GenerateTypeTransition(masm); |
2050 break; | 2011 break; |
2051 } | 2012 } |
2052 | 2013 |
2053 case Token::MOD: { | 2014 case Token::MOD: { |
2054 // For MOD we go directly to runtime in the non-smi case. | 2015 // For MOD we go directly to runtime in the non-smi case. |
2055 break; | 2016 break; |
2056 } | 2017 } |
2057 case Token::BIT_OR: | 2018 case Token::BIT_OR: |
2058 case Token::BIT_AND: | 2019 case Token::BIT_AND: |
2059 case Token::BIT_XOR: | 2020 case Token::BIT_XOR: |
2060 case Token::SAR: | 2021 case Token::SAR: |
2061 case Token::SHL: | 2022 case Token::SHL: |
2062 case Token::SHR: { | 2023 case Token::SHR: { |
2063 GenerateRegisterArgsPush(masm); | 2024 GenerateRegisterArgsPush(masm); |
2064 Label not_floats; | 2025 Label not_floats; |
2065 Label non_smi_result; | 2026 Label non_smi_result; |
| 2027 // We do not check the input arguments here, as any value is |
| 2028 // unconditionally truncated to an int32 anyway. To get the |
| 2029 // right optimized code, int32 type feedback is just right. |
| 2030 bool use_sse3 = platform_specific_bit_; |
2066 FloatingPointHelper::LoadUnknownsAsIntegers(masm, | 2031 FloatingPointHelper::LoadUnknownsAsIntegers(masm, |
2067 use_sse3_, | 2032 use_sse3, |
2068 ¬_floats); | 2033 ¬_floats); |
2069 switch (op_) { | 2034 switch (op_) { |
2070 case Token::BIT_OR: __ or_(eax, ecx); break; | 2035 case Token::BIT_OR: __ or_(eax, ecx); break; |
2071 case Token::BIT_AND: __ and_(eax, ecx); break; | 2036 case Token::BIT_AND: __ and_(eax, ecx); break; |
2072 case Token::BIT_XOR: __ xor_(eax, ecx); break; | 2037 case Token::BIT_XOR: __ xor_(eax, ecx); break; |
2073 case Token::SAR: __ sar_cl(eax); break; | 2038 case Token::SAR: __ sar_cl(eax); break; |
2074 case Token::SHL: __ shl_cl(eax); break; | 2039 case Token::SHL: __ shl_cl(eax); break; |
2075 case Token::SHR: __ shr_cl(eax); break; | 2040 case Token::SHR: __ shr_cl(eax); break; |
2076 default: UNREACHABLE(); | 2041 default: UNREACHABLE(); |
2077 } | 2042 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2129 } | 2094 } |
2130 default: UNREACHABLE(); break; | 2095 default: UNREACHABLE(); break; |
2131 } | 2096 } |
2132 | 2097 |
2133 // If an allocation fails, or SHR or MOD hit a hard case, | 2098 // If an allocation fails, or SHR or MOD hit a hard case, |
2134 // use the runtime system to get the correct result. | 2099 // use the runtime system to get the correct result. |
2135 __ bind(&call_runtime); | 2100 __ bind(&call_runtime); |
2136 | 2101 |
2137 switch (op_) { | 2102 switch (op_) { |
2138 case Token::ADD: | 2103 case Token::ADD: |
2139 GenerateRegisterArgsPush(masm); | |
2140 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); | |
2141 break; | |
2142 case Token::SUB: | 2104 case Token::SUB: |
2143 GenerateRegisterArgsPush(masm); | |
2144 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); | |
2145 break; | |
2146 case Token::MUL: | 2105 case Token::MUL: |
2147 GenerateRegisterArgsPush(masm); | |
2148 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); | |
2149 break; | |
2150 case Token::DIV: | 2106 case Token::DIV: |
2151 GenerateRegisterArgsPush(masm); | |
2152 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); | |
2153 break; | |
2154 case Token::MOD: | 2107 case Token::MOD: |
2155 GenerateRegisterArgsPush(masm); | 2108 GenerateRegisterArgsPush(masm); |
2156 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); | |
2157 break; | 2109 break; |
2158 case Token::BIT_OR: | 2110 case Token::BIT_OR: |
2159 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); | |
2160 break; | |
2161 case Token::BIT_AND: | 2111 case Token::BIT_AND: |
2162 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); | |
2163 break; | |
2164 case Token::BIT_XOR: | 2112 case Token::BIT_XOR: |
2165 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); | |
2166 break; | |
2167 case Token::SAR: | 2113 case Token::SAR: |
2168 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); | |
2169 break; | |
2170 case Token::SHL: | 2114 case Token::SHL: |
2171 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); | |
2172 break; | |
2173 case Token::SHR: | 2115 case Token::SHR: |
2174 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | |
2175 break; | 2116 break; |
2176 default: | 2117 default: |
2177 UNREACHABLE(); | 2118 UNREACHABLE(); |
2178 } | 2119 } |
| 2120 GenerateCallRuntime(masm); |
2179 } | 2121 } |
2180 | 2122 |
2181 | 2123 |
2182 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { | 2124 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { |
2183 Label call_runtime; | 2125 Label call_runtime; |
2184 | 2126 |
2185 Counters* counters = masm->isolate()->counters(); | 2127 Counters* counters = masm->isolate()->counters(); |
2186 __ IncrementCounter(counters->generic_binary_stub_calls(), 1); | 2128 __ IncrementCounter(counters->generic_binary_stub_calls(), 1); |
2187 | 2129 |
2188 switch (op_) { | 2130 switch (op_) { |
2189 case Token::ADD: | 2131 case Token::ADD: |
2190 case Token::SUB: | 2132 case Token::SUB: |
2191 case Token::MUL: | 2133 case Token::MUL: |
2192 case Token::DIV: | 2134 case Token::DIV: |
2193 break; | 2135 break; |
2194 case Token::MOD: | 2136 case Token::MOD: |
2195 case Token::BIT_OR: | 2137 case Token::BIT_OR: |
2196 case Token::BIT_AND: | 2138 case Token::BIT_AND: |
2197 case Token::BIT_XOR: | 2139 case Token::BIT_XOR: |
2198 case Token::SAR: | 2140 case Token::SAR: |
2199 case Token::SHL: | 2141 case Token::SHL: |
2200 case Token::SHR: | 2142 case Token::SHR: |
2201 GenerateRegisterArgsPush(masm); | 2143 GenerateRegisterArgsPush(masm); |
2202 break; | 2144 break; |
2203 default: | 2145 default: |
2204 UNREACHABLE(); | 2146 UNREACHABLE(); |
2205 } | 2147 } |
2206 | 2148 |
2207 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); | 2149 BinaryOpStub_GenerateSmiCode( |
| 2150 masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_); |
2208 | 2151 |
2209 // Floating point case. | 2152 // Floating point case. |
2210 switch (op_) { | 2153 switch (op_) { |
2211 case Token::ADD: | 2154 case Token::ADD: |
2212 case Token::SUB: | 2155 case Token::SUB: |
2213 case Token::MUL: | 2156 case Token::MUL: |
2214 case Token::DIV: { | 2157 case Token::DIV: { |
2215 Label not_floats; | 2158 Label not_floats; |
2216 if (CpuFeatures::IsSupported(SSE2)) { | 2159 if (CpuFeatures::IsSupported(SSE2)) { |
2217 CpuFeatures::Scope use_sse2(SSE2); | 2160 CpuFeatures::Scope use_sse2(SSE2); |
2218 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); | 2161 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
2219 | 2162 |
2220 switch (op_) { | 2163 switch (op_) { |
2221 case Token::ADD: __ addsd(xmm0, xmm1); break; | 2164 case Token::ADD: __ addsd(xmm0, xmm1); break; |
2222 case Token::SUB: __ subsd(xmm0, xmm1); break; | 2165 case Token::SUB: __ subsd(xmm0, xmm1); break; |
2223 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 2166 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
2224 case Token::DIV: __ divsd(xmm0, xmm1); break; | 2167 case Token::DIV: __ divsd(xmm0, xmm1); break; |
2225 default: UNREACHABLE(); | 2168 default: UNREACHABLE(); |
2226 } | 2169 } |
2227 GenerateHeapResultAllocation(masm, &call_runtime); | 2170 BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_); |
2228 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 2171 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
2229 __ ret(0); | 2172 __ ret(0); |
2230 } else { // SSE2 not available, use FPU. | 2173 } else { // SSE2 not available, use FPU. |
2231 FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); | 2174 FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); |
2232 FloatingPointHelper::LoadFloatOperands( | 2175 FloatingPointHelper::LoadFloatOperands( |
2233 masm, | 2176 masm, |
2234 ecx, | 2177 ecx, |
2235 FloatingPointHelper::ARGS_IN_REGISTERS); | 2178 FloatingPointHelper::ARGS_IN_REGISTERS); |
2236 switch (op_) { | 2179 switch (op_) { |
2237 case Token::ADD: __ faddp(1); break; | 2180 case Token::ADD: __ faddp(1); break; |
2238 case Token::SUB: __ fsubp(1); break; | 2181 case Token::SUB: __ fsubp(1); break; |
2239 case Token::MUL: __ fmulp(1); break; | 2182 case Token::MUL: __ fmulp(1); break; |
2240 case Token::DIV: __ fdivp(1); break; | 2183 case Token::DIV: __ fdivp(1); break; |
2241 default: UNREACHABLE(); | 2184 default: UNREACHABLE(); |
2242 } | 2185 } |
2243 Label after_alloc_failure; | 2186 Label after_alloc_failure; |
2244 GenerateHeapResultAllocation(masm, &after_alloc_failure); | 2187 BinaryOpStub_GenerateHeapResultAllocation( |
| 2188 masm, &after_alloc_failure, mode_); |
2245 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 2189 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
2246 __ ret(0); | 2190 __ ret(0); |
2247 __ bind(&after_alloc_failure); | 2191 __ bind(&after_alloc_failure); |
2248 __ fstp(0); // Pop FPU stack before calling runtime. | 2192 __ fstp(0); // Pop FPU stack before calling runtime. |
2249 __ jmp(&call_runtime); | 2193 __ jmp(&call_runtime); |
2250 } | 2194 } |
2251 __ bind(¬_floats); | 2195 __ bind(¬_floats); |
2252 break; | 2196 break; |
2253 } | 2197 } |
2254 case Token::MOD: { | 2198 case Token::MOD: { |
2255 // For MOD we go directly to runtime in the non-smi case. | 2199 // For MOD we go directly to runtime in the non-smi case. |
2256 break; | 2200 break; |
2257 } | 2201 } |
2258 case Token::BIT_OR: | 2202 case Token::BIT_OR: |
2259 case Token::BIT_AND: | 2203 case Token::BIT_AND: |
2260 case Token::BIT_XOR: | 2204 case Token::BIT_XOR: |
2261 case Token::SAR: | 2205 case Token::SAR: |
2262 case Token::SHL: | 2206 case Token::SHL: |
2263 case Token::SHR: { | 2207 case Token::SHR: { |
2264 Label non_smi_result; | 2208 Label non_smi_result; |
| 2209 bool use_sse3 = platform_specific_bit_; |
2265 FloatingPointHelper::LoadUnknownsAsIntegers(masm, | 2210 FloatingPointHelper::LoadUnknownsAsIntegers(masm, |
2266 use_sse3_, | 2211 use_sse3, |
2267 &call_runtime); | 2212 &call_runtime); |
2268 switch (op_) { | 2213 switch (op_) { |
2269 case Token::BIT_OR: __ or_(eax, ecx); break; | 2214 case Token::BIT_OR: __ or_(eax, ecx); break; |
2270 case Token::BIT_AND: __ and_(eax, ecx); break; | 2215 case Token::BIT_AND: __ and_(eax, ecx); break; |
2271 case Token::BIT_XOR: __ xor_(eax, ecx); break; | 2216 case Token::BIT_XOR: __ xor_(eax, ecx); break; |
2272 case Token::SAR: __ sar_cl(eax); break; | 2217 case Token::SAR: __ sar_cl(eax); break; |
2273 case Token::SHL: __ shl_cl(eax); break; | 2218 case Token::SHL: __ shl_cl(eax); break; |
2274 case Token::SHR: __ shr_cl(eax); break; | 2219 case Token::SHR: __ shr_cl(eax); break; |
2275 default: UNREACHABLE(); | 2220 default: UNREACHABLE(); |
2276 } | 2221 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2323 } | 2268 } |
2324 break; | 2269 break; |
2325 } | 2270 } |
2326 default: UNREACHABLE(); break; | 2271 default: UNREACHABLE(); break; |
2327 } | 2272 } |
2328 | 2273 |
2329 // If all else fails, use the runtime system to get the correct | 2274 // If all else fails, use the runtime system to get the correct |
2330 // result. | 2275 // result. |
2331 __ bind(&call_runtime); | 2276 __ bind(&call_runtime); |
2332 switch (op_) { | 2277 switch (op_) { |
2333 case Token::ADD: { | 2278 case Token::ADD: |
2334 GenerateAddStrings(masm); | 2279 GenerateAddStrings(masm); |
2335 GenerateRegisterArgsPush(masm); | 2280 // Fall through. |
2336 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); | |
2337 break; | |
2338 } | |
2339 case Token::SUB: | 2281 case Token::SUB: |
2340 GenerateRegisterArgsPush(masm); | |
2341 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); | |
2342 break; | |
2343 case Token::MUL: | 2282 case Token::MUL: |
2344 GenerateRegisterArgsPush(masm); | |
2345 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); | |
2346 break; | |
2347 case Token::DIV: | 2283 case Token::DIV: |
2348 GenerateRegisterArgsPush(masm); | 2284 GenerateRegisterArgsPush(masm); |
2349 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); | |
2350 break; | 2285 break; |
2351 case Token::MOD: | 2286 case Token::MOD: |
2352 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); | |
2353 break; | |
2354 case Token::BIT_OR: | 2287 case Token::BIT_OR: |
2355 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); | |
2356 break; | |
2357 case Token::BIT_AND: | 2288 case Token::BIT_AND: |
2358 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); | |
2359 break; | |
2360 case Token::BIT_XOR: | 2289 case Token::BIT_XOR: |
2361 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); | |
2362 break; | |
2363 case Token::SAR: | 2290 case Token::SAR: |
2364 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); | |
2365 break; | |
2366 case Token::SHL: | 2291 case Token::SHL: |
2367 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); | |
2368 break; | |
2369 case Token::SHR: | 2292 case Token::SHR: |
2370 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | |
2371 break; | 2293 break; |
2372 default: | 2294 default: |
2373 UNREACHABLE(); | 2295 UNREACHABLE(); |
2374 } | 2296 } |
| 2297 GenerateCallRuntime(masm); |
2375 } | 2298 } |
2376 | 2299 |
2377 | 2300 |
2378 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { | 2301 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { |
2379 ASSERT(op_ == Token::ADD); | 2302 ASSERT(op_ == Token::ADD); |
2380 Label left_not_string, call_runtime; | 2303 Label left_not_string, call_runtime; |
2381 | 2304 |
2382 // Registers containing left and right operands respectively. | 2305 // Registers containing left and right operands respectively. |
2383 Register left = edx; | 2306 Register left = edx; |
2384 Register right = eax; | 2307 Register right = eax; |
(...skipping 15 matching lines...) Expand all Loading... |
2400 | 2323 |
2401 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); | 2324 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); |
2402 GenerateRegisterArgsPush(masm); | 2325 GenerateRegisterArgsPush(masm); |
2403 __ TailCallStub(&string_add_right_stub); | 2326 __ TailCallStub(&string_add_right_stub); |
2404 | 2327 |
2405 // Neither argument is a string. | 2328 // Neither argument is a string. |
2406 __ bind(&call_runtime); | 2329 __ bind(&call_runtime); |
2407 } | 2330 } |
2408 | 2331 |
2409 | 2332 |
2410 void BinaryOpStub::GenerateHeapResultAllocation( | 2333 static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, |
2411 MacroAssembler* masm, | 2334 Label* alloc_failure, |
2412 Label* alloc_failure) { | 2335 OverwriteMode mode) { |
2413 Label skip_allocation; | 2336 Label skip_allocation; |
2414 OverwriteMode mode = mode_; | |
2415 switch (mode) { | 2337 switch (mode) { |
2416 case OVERWRITE_LEFT: { | 2338 case OVERWRITE_LEFT: { |
2417 // If the argument in edx is already an object, we skip the | 2339 // If the argument in edx is already an object, we skip the |
2418 // allocation of a heap number. | 2340 // allocation of a heap number. |
2419 __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); | 2341 __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); |
2420 // Allocate a heap number for the result. Keep eax and edx intact | 2342 // Allocate a heap number for the result. Keep eax and edx intact |
2421 // for the possible runtime call. | 2343 // for the possible runtime call. |
2422 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); | 2344 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); |
2423 // Now edx can be overwritten losing one of the arguments as we are | 2345 // Now edx can be overwritten losing one of the arguments as we are |
2424 // now done and will not need it any more. | 2346 // now done and will not need it any more. |
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2916 | 2838 |
2917 __ mov(scratch, right); | 2839 __ mov(scratch, right); |
2918 __ SmiUntag(scratch); | 2840 __ SmiUntag(scratch); |
2919 __ cvtsi2sd(xmm1, scratch); | 2841 __ cvtsi2sd(xmm1, scratch); |
2920 } | 2842 } |
2921 | 2843 |
2922 | 2844 |
2923 void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, | 2845 void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, |
2924 Label* non_int32, | 2846 Label* non_int32, |
2925 Register scratch) { | 2847 Register scratch) { |
2926 __ cvttsd2si(scratch, Operand(xmm0)); | 2848 CheckSSE2OperandIsInt32(masm, non_int32, xmm0, scratch, xmm2); |
2927 __ cvtsi2sd(xmm2, scratch); | 2849 CheckSSE2OperandIsInt32(masm, non_int32, xmm1, scratch, xmm2); |
2928 __ ucomisd(xmm0, xmm2); | |
2929 __ j(not_zero, non_int32); | |
2930 __ j(carry, non_int32); | |
2931 __ cvttsd2si(scratch, Operand(xmm1)); | |
2932 __ cvtsi2sd(xmm2, scratch); | |
2933 __ ucomisd(xmm1, xmm2); | |
2934 __ j(not_zero, non_int32); | |
2935 __ j(carry, non_int32); | |
2936 } | 2850 } |
2937 | 2851 |
2938 | 2852 |
| 2853 void FloatingPointHelper::CheckSSE2OperandIsInt32(MacroAssembler* masm, |
| 2854 Label* non_int32, |
| 2855 XMMRegister operand, |
| 2856 Register scratch, |
| 2857 XMMRegister xmm_scratch) { |
| 2858 __ cvttsd2si(scratch, Operand(operand)); |
| 2859 __ cvtsi2sd(xmm_scratch, scratch); |
| 2860 __ pcmpeqd(xmm_scratch, operand); |
| 2861 __ movmskpd(scratch, xmm_scratch); |
| 2862 __ test(scratch, Immediate(1)); |
| 2863 __ j(zero, non_int32); |
| 2864 } |
| 2865 |
| 2866 |
2939 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, | 2867 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
2940 Register scratch, | 2868 Register scratch, |
2941 ArgLocation arg_location) { | 2869 ArgLocation arg_location) { |
2942 Label load_smi_1, load_smi_2, done_load_1, done; | 2870 Label load_smi_1, load_smi_2, done_load_1, done; |
2943 if (arg_location == ARGS_IN_REGISTERS) { | 2871 if (arg_location == ARGS_IN_REGISTERS) { |
2944 __ mov(scratch, edx); | 2872 __ mov(scratch, edx); |
2945 } else { | 2873 } else { |
2946 __ mov(scratch, Operand(esp, 2 * kPointerSize)); | 2874 __ mov(scratch, Operand(esp, 2 * kPointerSize)); |
2947 } | 2875 } |
2948 __ JumpIfSmi(scratch, &load_smi_1, Label::kNear); | 2876 __ JumpIfSmi(scratch, &load_smi_1, Label::kNear); |
(...skipping 1365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4314 } | 4242 } |
4315 | 4243 |
4316 | 4244 |
4317 static int NegativeComparisonResult(Condition cc) { | 4245 static int NegativeComparisonResult(Condition cc) { |
4318 ASSERT(cc != equal); | 4246 ASSERT(cc != equal); |
4319 ASSERT((cc == less) || (cc == less_equal) | 4247 ASSERT((cc == less) || (cc == less_equal) |
4320 || (cc == greater) || (cc == greater_equal)); | 4248 || (cc == greater) || (cc == greater_equal)); |
4321 return (cc == greater || cc == greater_equal) ? LESS : GREATER; | 4249 return (cc == greater || cc == greater_equal) ? LESS : GREATER; |
4322 } | 4250 } |
4323 | 4251 |
4324 void CompareStub::Generate(MacroAssembler* masm) { | |
4325 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | |
4326 | 4252 |
| 4253 static void CheckInputType(MacroAssembler* masm, |
| 4254 Register input, |
| 4255 CompareIC::State expected, |
| 4256 Label* fail) { |
| 4257 Label ok; |
| 4258 if (expected == CompareIC::SMI) { |
| 4259 __ JumpIfNotSmi(input, fail); |
| 4260 } else if (expected == CompareIC::HEAP_NUMBER) { |
| 4261 __ JumpIfSmi(input, &ok); |
| 4262 __ cmp(FieldOperand(input, HeapObject::kMapOffset), |
| 4263 Immediate(masm->isolate()->factory()->heap_number_map())); |
| 4264 __ j(not_equal, fail); |
| 4265 } |
| 4266 // We could be strict about symbol/string here, but as long as |
| 4267 // hydrogen doesn't care, the stub doesn't have to care either. |
| 4268 __ bind(&ok); |
| 4269 } |
| 4270 |
| 4271 |
| 4272 static void BranchIfNonSymbol(MacroAssembler* masm, |
| 4273 Label* label, |
| 4274 Register object, |
| 4275 Register scratch) { |
| 4276 __ JumpIfSmi(object, label); |
| 4277 __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); |
| 4278 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 4279 __ and_(scratch, kIsSymbolMask | kIsNotStringMask); |
| 4280 __ cmp(scratch, kSymbolTag | kStringTag); |
| 4281 __ j(not_equal, label); |
| 4282 } |
| 4283 |
| 4284 |
| 4285 void ICCompareStub::GenerateGeneric(MacroAssembler* masm) { |
4327 Label check_unequal_objects; | 4286 Label check_unequal_objects; |
| 4287 Condition cc = GetCondition(); |
4328 | 4288 |
4329 // Compare two smis if required. | 4289 Label miss; |
4330 if (include_smi_compare_) { | 4290 CheckInputType(masm, edx, left_, &miss); |
4331 Label non_smi, smi_done; | 4291 CheckInputType(masm, eax, right_, &miss); |
4332 __ mov(ecx, edx); | 4292 |
4333 __ or_(ecx, eax); | 4293 // Compare two smis. |
4334 __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); | 4294 Label non_smi, smi_done; |
4335 __ sub(edx, eax); // Return on the result of the subtraction. | 4295 __ mov(ecx, edx); |
4336 __ j(no_overflow, &smi_done, Label::kNear); | 4296 __ or_(ecx, eax); |
4337 __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. | 4297 __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); |
4338 __ bind(&smi_done); | 4298 __ sub(edx, eax); // Return on the result of the subtraction. |
4339 __ mov(eax, edx); | 4299 __ j(no_overflow, &smi_done, Label::kNear); |
4340 __ ret(0); | 4300 __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. |
4341 __ bind(&non_smi); | 4301 __ bind(&smi_done); |
4342 } else if (FLAG_debug_code) { | 4302 __ mov(eax, edx); |
4343 __ mov(ecx, edx); | 4303 __ ret(0); |
4344 __ or_(ecx, eax); | 4304 __ bind(&non_smi); |
4345 __ test(ecx, Immediate(kSmiTagMask)); | |
4346 __ Assert(not_zero, "Unexpected smi operands."); | |
4347 } | |
4348 | 4305 |
4349 // NOTICE! This code is only reached after a smi-fast-case check, so | 4306 // NOTICE! This code is only reached after a smi-fast-case check, so |
4350 // it is certain that at least one operand isn't a smi. | 4307 // it is certain that at least one operand isn't a smi. |
4351 | 4308 |
4352 // Identical objects can be compared fast, but there are some tricky cases | 4309 // Identical objects can be compared fast, but there are some tricky cases |
4353 // for NaN and undefined. | 4310 // for NaN and undefined. |
4354 { | 4311 { |
4355 Label not_identical; | 4312 Label not_identical; |
4356 __ cmp(eax, edx); | 4313 __ cmp(eax, edx); |
4357 __ j(not_equal, ¬_identical); | 4314 __ j(not_equal, ¬_identical); |
4358 | 4315 |
4359 if (cc_ != equal) { | 4316 if (cc != equal) { |
4360 // Check for undefined. undefined OP undefined is false even though | 4317 // Check for undefined. undefined OP undefined is false even though |
4361 // undefined == undefined. | 4318 // undefined == undefined. |
4362 Label check_for_nan; | 4319 Label check_for_nan; |
4363 __ cmp(edx, masm->isolate()->factory()->undefined_value()); | 4320 __ cmp(edx, masm->isolate()->factory()->undefined_value()); |
4364 __ j(not_equal, &check_for_nan, Label::kNear); | 4321 __ j(not_equal, &check_for_nan, Label::kNear); |
4365 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); | 4322 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); |
4366 __ ret(0); | 4323 __ ret(0); |
4367 __ bind(&check_for_nan); | 4324 __ bind(&check_for_nan); |
4368 } | 4325 } |
4369 | 4326 |
4370 // Test for NaN. Sadly, we can't just compare to factory->nan_value(), | 4327 // Test for NaN. Sadly, we can't just compare to factory->nan_value(), |
4371 // so we do the second best thing - test it ourselves. | 4328 // so we do the second best thing - test it ourselves. |
4372 // Note: if cc_ != equal, never_nan_nan_ is not used. | 4329 Label heap_number; |
4373 if (never_nan_nan_ && (cc_ == equal)) { | 4330 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 4331 Immediate(masm->isolate()->factory()->heap_number_map())); |
| 4332 __ j(equal, &heap_number, Label::kNear); |
| 4333 if (cc != equal) { |
| 4334 // Call runtime on identical JSObjects. Otherwise return equal. |
| 4335 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); |
| 4336 __ j(above_equal, ¬_identical); |
| 4337 } |
| 4338 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 4339 __ ret(0); |
| 4340 |
| 4341 __ bind(&heap_number); |
| 4342 // It is a heap number, so return non-equal if it's NaN and equal if |
| 4343 // it's not NaN. |
| 4344 // The representation of NaN values has all exponent bits (52..62) set, |
| 4345 // and not all mantissa bits (0..51) clear. |
| 4346 // We only accept QNaNs, which have bit 51 set. |
| 4347 // Read top bits of double representation (second word of value). |
| 4348 |
| 4349 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., |
| 4350 // all bits in the mask are set. We only need to check the word |
| 4351 // that contains the exponent and high bit of the mantissa. |
| 4352 STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); |
| 4353 __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); |
| 4354 __ Set(eax, Immediate(0)); |
| 4355 // Shift value and mask so kQuietNaNHighBitsMask applies to topmost |
| 4356 // bits. |
| 4357 __ add(edx, edx); |
| 4358 __ cmp(edx, kQuietNaNHighBitsMask << 1); |
| 4359 if (cc == equal) { |
| 4360 STATIC_ASSERT(EQUAL != 1); |
| 4361 __ setcc(above_equal, eax); |
| 4362 __ ret(0); |
| 4363 } else { |
| 4364 Label nan; |
| 4365 __ j(above_equal, &nan, Label::kNear); |
4374 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 4366 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
4375 __ ret(0); | 4367 __ ret(0); |
4376 } else { | 4368 __ bind(&nan); |
4377 Label heap_number; | 4369 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); |
4378 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | |
4379 Immediate(masm->isolate()->factory()->heap_number_map())); | |
4380 __ j(equal, &heap_number, Label::kNear); | |
4381 if (cc_ != equal) { | |
4382 // Call runtime on identical JSObjects. Otherwise return equal. | |
4383 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); | |
4384 __ j(above_equal, ¬_identical); | |
4385 } | |
4386 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | |
4387 __ ret(0); | 4370 __ ret(0); |
4388 | |
4389 __ bind(&heap_number); | |
4390 // It is a heap number, so return non-equal if it's NaN and equal if | |
4391 // it's not NaN. | |
4392 // The representation of NaN values has all exponent bits (52..62) set, | |
4393 // and not all mantissa bits (0..51) clear. | |
4394 // We only accept QNaNs, which have bit 51 set. | |
4395 // Read top bits of double representation (second word of value). | |
4396 | |
4397 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., | |
4398 // all bits in the mask are set. We only need to check the word | |
4399 // that contains the exponent and high bit of the mantissa. | |
4400 STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); | |
4401 __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); | |
4402 __ Set(eax, Immediate(0)); | |
4403 // Shift value and mask so kQuietNaNHighBitsMask applies to topmost | |
4404 // bits. | |
4405 __ add(edx, edx); | |
4406 __ cmp(edx, kQuietNaNHighBitsMask << 1); | |
4407 if (cc_ == equal) { | |
4408 STATIC_ASSERT(EQUAL != 1); | |
4409 __ setcc(above_equal, eax); | |
4410 __ ret(0); | |
4411 } else { | |
4412 Label nan; | |
4413 __ j(above_equal, &nan, Label::kNear); | |
4414 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | |
4415 __ ret(0); | |
4416 __ bind(&nan); | |
4417 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); | |
4418 __ ret(0); | |
4419 } | |
4420 } | 4371 } |
4421 | 4372 |
4422 __ bind(¬_identical); | 4373 __ bind(¬_identical); |
4423 } | 4374 } |
4424 | 4375 |
4425 // Strict equality can quickly decide whether objects are equal. | 4376 // Strict equality can quickly decide whether objects are equal. |
4426 // Non-strict object equality is slower, so it is handled later in the stub. | 4377 // Non-strict object equality is slower, so it is handled later in the stub. |
4427 if (cc_ == equal && strict_) { | 4378 if (cc == equal && strict()) { |
4428 Label slow; // Fallthrough label. | 4379 Label slow; // Fallthrough label. |
4429 Label not_smis; | 4380 Label not_smis; |
4430 // If we're doing a strict equality comparison, we don't have to do | 4381 // If we're doing a strict equality comparison, we don't have to do |
4431 // type conversion, so we generate code to do fast comparison for objects | 4382 // type conversion, so we generate code to do fast comparison for objects |
4432 // and oddballs. Non-smi numbers and strings still go through the usual | 4383 // and oddballs. Non-smi numbers and strings still go through the usual |
4433 // slow-case code. | 4384 // slow-case code. |
4434 // If either is a Smi (we know that not both are), then they can only | 4385 // If either is a Smi (we know that not both are), then they can only |
4435 // be equal if the other is a HeapNumber. If so, use the slow case. | 4386 // be equal if the other is a HeapNumber. If so, use the slow case. |
4436 STATIC_ASSERT(kSmiTag == 0); | 4387 STATIC_ASSERT(kSmiTag == 0); |
4437 ASSERT_EQ(0, Smi::FromInt(0)); | 4388 ASSERT_EQ(0, Smi::FromInt(0)); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4488 | 4439 |
4489 // Check for oddballs: true, false, null, undefined. | 4440 // Check for oddballs: true, false, null, undefined. |
4490 __ CmpInstanceType(ecx, ODDBALL_TYPE); | 4441 __ CmpInstanceType(ecx, ODDBALL_TYPE); |
4491 __ j(equal, &return_not_equal); | 4442 __ j(equal, &return_not_equal); |
4492 | 4443 |
4493 // Fall through to the general case. | 4444 // Fall through to the general case. |
4494 __ bind(&slow); | 4445 __ bind(&slow); |
4495 } | 4446 } |
4496 | 4447 |
4497 // Generate the number comparison code. | 4448 // Generate the number comparison code. |
4498 if (include_number_compare_) { | 4449 Label non_number_comparison; |
4499 Label non_number_comparison; | 4450 Label unordered; |
4500 Label unordered; | 4451 if (CpuFeatures::IsSupported(SSE2)) { |
4501 if (CpuFeatures::IsSupported(SSE2)) { | 4452 CpuFeatures::Scope use_sse2(SSE2); |
4502 CpuFeatures::Scope use_sse2(SSE2); | 4453 CpuFeatures::Scope use_cmov(CMOV); |
4503 CpuFeatures::Scope use_cmov(CMOV); | |
4504 | 4454 |
4505 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); | 4455 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); |
4506 __ ucomisd(xmm0, xmm1); | 4456 __ ucomisd(xmm0, xmm1); |
4507 | 4457 |
4508 // Don't base result on EFLAGS when a NaN is involved. | 4458 // Don't base result on EFLAGS when a NaN is involved. |
4509 __ j(parity_even, &unordered, Label::kNear); | 4459 __ j(parity_even, &unordered, Label::kNear); |
4510 // Return a result of -1, 0, or 1, based on EFLAGS. | 4460 // Return a result of -1, 0, or 1, based on EFLAGS. |
4511 __ mov(eax, 0); // equal | 4461 __ mov(eax, 0); // equal |
4512 __ mov(ecx, Immediate(Smi::FromInt(1))); | 4462 __ mov(ecx, Immediate(Smi::FromInt(1))); |
4513 __ cmov(above, eax, ecx); | 4463 __ cmov(above, eax, ecx); |
4514 __ mov(ecx, Immediate(Smi::FromInt(-1))); | 4464 __ mov(ecx, Immediate(Smi::FromInt(-1))); |
4515 __ cmov(below, eax, ecx); | 4465 __ cmov(below, eax, ecx); |
4516 __ ret(0); | 4466 __ ret(0); |
4517 } else { | 4467 } else { |
4518 FloatingPointHelper::CheckFloatOperands( | 4468 FloatingPointHelper::CheckFloatOperands( |
4519 masm, &non_number_comparison, ebx); | 4469 masm, &non_number_comparison, ebx); |
4520 FloatingPointHelper::LoadFloatOperand(masm, eax); | 4470 FloatingPointHelper::LoadFloatOperand(masm, eax); |
4521 FloatingPointHelper::LoadFloatOperand(masm, edx); | 4471 FloatingPointHelper::LoadFloatOperand(masm, edx); |
4522 __ FCmp(); | 4472 __ FCmp(); |
4523 | 4473 |
4524 // Don't base result on EFLAGS when a NaN is involved. | 4474 // Don't base result on EFLAGS when a NaN is involved. |
4525 __ j(parity_even, &unordered, Label::kNear); | 4475 __ j(parity_even, &unordered, Label::kNear); |
4526 | 4476 |
4527 Label below_label, above_label; | 4477 Label below_label, above_label; |
4528 // Return a result of -1, 0, or 1, based on EFLAGS. | 4478 // Return a result of -1, 0, or 1, based on EFLAGS. |
4529 __ j(below, &below_label, Label::kNear); | 4479 __ j(below, &below_label, Label::kNear); |
4530 __ j(above, &above_label, Label::kNear); | 4480 __ j(above, &above_label, Label::kNear); |
4531 | 4481 |
4532 __ Set(eax, Immediate(0)); | 4482 __ Set(eax, Immediate(0)); |
4533 __ ret(0); | |
4534 | |
4535 __ bind(&below_label); | |
4536 __ mov(eax, Immediate(Smi::FromInt(-1))); | |
4537 __ ret(0); | |
4538 | |
4539 __ bind(&above_label); | |
4540 __ mov(eax, Immediate(Smi::FromInt(1))); | |
4541 __ ret(0); | |
4542 } | |
4543 | |
4544 // If one of the numbers was NaN, then the result is always false. | |
4545 // The cc is never not-equal. | |
4546 __ bind(&unordered); | |
4547 ASSERT(cc_ != not_equal); | |
4548 if (cc_ == less || cc_ == less_equal) { | |
4549 __ mov(eax, Immediate(Smi::FromInt(1))); | |
4550 } else { | |
4551 __ mov(eax, Immediate(Smi::FromInt(-1))); | |
4552 } | |
4553 __ ret(0); | 4483 __ ret(0); |
4554 | 4484 |
4555 // The number comparison code did not provide a valid result. | 4485 __ bind(&below_label); |
4556 __ bind(&non_number_comparison); | 4486 __ mov(eax, Immediate(Smi::FromInt(-1))); |
| 4487 __ ret(0); |
| 4488 |
| 4489 __ bind(&above_label); |
| 4490 __ mov(eax, Immediate(Smi::FromInt(1))); |
| 4491 __ ret(0); |
4557 } | 4492 } |
4558 | 4493 |
| 4494 // If one of the numbers was NaN, then the result is always false. |
| 4495 // The cc is never not-equal. |
| 4496 __ bind(&unordered); |
| 4497 ASSERT(cc != not_equal); |
| 4498 if (cc == less || cc == less_equal) { |
| 4499 __ mov(eax, Immediate(Smi::FromInt(1))); |
| 4500 } else { |
| 4501 __ mov(eax, Immediate(Smi::FromInt(-1))); |
| 4502 } |
| 4503 __ ret(0); |
| 4504 |
| 4505 // The number comparison code did not provide a valid result. |
| 4506 __ bind(&non_number_comparison); |
| 4507 |
4559 // Fast negative check for symbol-to-symbol equality. | 4508 // Fast negative check for symbol-to-symbol equality. |
4560 Label check_for_strings; | 4509 Label check_for_strings; |
4561 if (cc_ == equal) { | 4510 if (cc == equal) { |
4562 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); | 4511 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); |
4563 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); | 4512 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); |
4564 | 4513 |
4565 // We've already checked for object identity, so if both operands | 4514 // We've already checked for object identity, so if both operands |
4566 // are symbols they aren't equal. Register eax already holds a | 4515 // are symbols they aren't equal. Register eax already holds a |
4567 // non-zero value, which indicates not equal, so just return. | 4516 // non-zero value, which indicates not equal, so just return. |
4568 __ ret(0); | 4517 __ ret(0); |
4569 } | 4518 } |
4570 | 4519 |
4571 __ bind(&check_for_strings); | 4520 __ bind(&check_for_strings); |
4572 | 4521 |
4573 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, | 4522 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, |
4574 &check_unequal_objects); | 4523 &check_unequal_objects); |
4575 | 4524 |
4576 // Inline comparison of ASCII strings. | 4525 // Inline comparison of ASCII strings. |
4577 if (cc_ == equal) { | 4526 if (cc == equal) { |
4578 StringCompareStub::GenerateFlatAsciiStringEquals(masm, | 4527 StringCompareStub::GenerateFlatAsciiStringEquals(masm, |
4579 edx, | 4528 edx, |
4580 eax, | 4529 eax, |
4581 ecx, | 4530 ecx, |
4582 ebx); | 4531 ebx); |
4583 } else { | 4532 } else { |
4584 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, | 4533 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, |
4585 edx, | 4534 edx, |
4586 eax, | 4535 eax, |
4587 ecx, | 4536 ecx, |
4588 ebx, | 4537 ebx, |
4589 edi); | 4538 edi); |
4590 } | 4539 } |
4591 #ifdef DEBUG | 4540 #ifdef DEBUG |
4592 __ Abort("Unexpected fall-through from string comparison"); | 4541 __ Abort("Unexpected fall-through from string comparison"); |
4593 #endif | 4542 #endif |
4594 | 4543 |
4595 __ bind(&check_unequal_objects); | 4544 __ bind(&check_unequal_objects); |
4596 if (cc_ == equal && !strict_) { | 4545 if (cc == equal && !strict()) { |
4597 // Non-strict equality. Objects are unequal if | 4546 // Non-strict equality. Objects are unequal if |
4598 // they are both JSObjects and not undetectable, | 4547 // they are both JSObjects and not undetectable, |
4599 // and their pointers are different. | 4548 // and their pointers are different. |
4600 Label not_both_objects; | 4549 Label not_both_objects; |
4601 Label return_unequal; | 4550 Label return_unequal; |
4602 // At most one is a smi, so we can test for smi by adding the two. | 4551 // At most one is a smi, so we can test for smi by adding the two. |
4603 // A smi plus a heap object has the low bit set, a heap object plus | 4552 // A smi plus a heap object has the low bit set, a heap object plus |
4604 // a heap object has the low bit clear. | 4553 // a heap object has the low bit clear. |
4605 STATIC_ASSERT(kSmiTag == 0); | 4554 STATIC_ASSERT(kSmiTag == 0); |
4606 STATIC_ASSERT(kSmiTagMask == 1); | 4555 STATIC_ASSERT(kSmiTagMask == 1); |
(...skipping 23 matching lines...) Expand all Loading... |
4630 __ bind(¬_both_objects); | 4579 __ bind(¬_both_objects); |
4631 } | 4580 } |
4632 | 4581 |
4633 // Push arguments below the return address. | 4582 // Push arguments below the return address. |
4634 __ pop(ecx); | 4583 __ pop(ecx); |
4635 __ push(edx); | 4584 __ push(edx); |
4636 __ push(eax); | 4585 __ push(eax); |
4637 | 4586 |
4638 // Figure out which native to call and setup the arguments. | 4587 // Figure out which native to call and setup the arguments. |
4639 Builtins::JavaScript builtin; | 4588 Builtins::JavaScript builtin; |
4640 if (cc_ == equal) { | 4589 if (cc == equal) { |
4641 builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; | 4590 builtin = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS; |
4642 } else { | 4591 } else { |
4643 builtin = Builtins::COMPARE; | 4592 builtin = Builtins::COMPARE; |
4644 __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); | 4593 __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc)))); |
4645 } | 4594 } |
4646 | 4595 |
4647 // Restore return address on the stack. | 4596 // Restore return address on the stack. |
4648 __ push(ecx); | 4597 __ push(ecx); |
4649 | 4598 |
4650 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 4599 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
4651 // tagged as a small integer. | 4600 // tagged as a small integer. |
4652 __ InvokeBuiltin(builtin, JUMP_FUNCTION); | 4601 __ InvokeBuiltin(builtin, JUMP_FUNCTION); |
| 4602 |
| 4603 __ bind(&miss); |
| 4604 GenerateMiss(masm); |
4653 } | 4605 } |
4654 | 4606 |
4655 | 4607 |
4656 void CompareStub::BranchIfNonSymbol(MacroAssembler* masm, | |
4657 Label* label, | |
4658 Register object, | |
4659 Register scratch) { | |
4660 __ JumpIfSmi(object, label); | |
4661 __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); | |
4662 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | |
4663 __ and_(scratch, kIsSymbolMask | kIsNotStringMask); | |
4664 __ cmp(scratch, kSymbolTag | kStringTag); | |
4665 __ j(not_equal, label); | |
4666 } | |
4667 | |
4668 | |
4669 void StackCheckStub::Generate(MacroAssembler* masm) { | 4608 void StackCheckStub::Generate(MacroAssembler* masm) { |
4670 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); | 4609 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); |
4671 } | 4610 } |
4672 | 4611 |
4673 | 4612 |
4674 void InterruptStub::Generate(MacroAssembler* masm) { | 4613 void InterruptStub::Generate(MacroAssembler* masm) { |
4675 __ TailCallRuntime(Runtime::kInterrupt, 0, 1); | 4614 __ TailCallRuntime(Runtime::kInterrupt, 0, 1); |
4676 } | 4615 } |
4677 | 4616 |
4678 | 4617 |
(...skipping 721 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5400 } | 5339 } |
5401 } | 5340 } |
5402 | 5341 |
5403 | 5342 |
5404 Register InstanceofStub::left() { return eax; } | 5343 Register InstanceofStub::left() { return eax; } |
5405 | 5344 |
5406 | 5345 |
5407 Register InstanceofStub::right() { return edx; } | 5346 Register InstanceofStub::right() { return edx; } |
5408 | 5347 |
5409 | 5348 |
5410 int CompareStub::MinorKey() { | |
5411 // Encode the three parameters in a unique 16 bit value. To avoid duplicate | |
5412 // stubs the never NaN NaN condition is only taken into account if the | |
5413 // condition is equals. | |
5414 ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); | |
5415 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | |
5416 return ConditionField::encode(static_cast<unsigned>(cc_)) | |
5417 | RegisterField::encode(false) // lhs_ and rhs_ are not used | |
5418 | StrictField::encode(strict_) | |
5419 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) | |
5420 | IncludeNumberCompareField::encode(include_number_compare_) | |
5421 | IncludeSmiCompareField::encode(include_smi_compare_); | |
5422 } | |
5423 | |
5424 | |
5425 // Unfortunately you have to run without snapshots to see most of these | |
5426 // names in the profile since most compare stubs end up in the snapshot. | |
5427 void CompareStub::PrintName(StringStream* stream) { | |
5428 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | |
5429 const char* cc_name; | |
5430 switch (cc_) { | |
5431 case less: cc_name = "LT"; break; | |
5432 case greater: cc_name = "GT"; break; | |
5433 case less_equal: cc_name = "LE"; break; | |
5434 case greater_equal: cc_name = "GE"; break; | |
5435 case equal: cc_name = "EQ"; break; | |
5436 case not_equal: cc_name = "NE"; break; | |
5437 default: cc_name = "UnknownCondition"; break; | |
5438 } | |
5439 bool is_equality = cc_ == equal || cc_ == not_equal; | |
5440 stream->Add("CompareStub_%s", cc_name); | |
5441 if (strict_ && is_equality) stream->Add("_STRICT"); | |
5442 if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); | |
5443 if (!include_number_compare_) stream->Add("_NO_NUMBER"); | |
5444 if (!include_smi_compare_) stream->Add("_NO_SMI"); | |
5445 } | |
5446 | |
5447 | |
5448 // ------------------------------------------------------------------------- | 5349 // ------------------------------------------------------------------------- |
5449 // StringCharCodeAtGenerator | 5350 // StringCharCodeAtGenerator |
5450 | 5351 |
5451 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 5352 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
5452 // If the receiver is a smi trigger the non-string case. | 5353 // If the receiver is a smi trigger the non-string case. |
5453 STATIC_ASSERT(kSmiTag == 0); | 5354 STATIC_ASSERT(kSmiTag == 0); |
5454 __ JumpIfSmi(object_, receiver_not_string_); | 5355 __ JumpIfSmi(object_, receiver_not_string_); |
5455 | 5356 |
5456 // Fetch the instance type of the receiver into result register. | 5357 // Fetch the instance type of the receiver into result register. |
5457 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 5358 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
(...skipping 1141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6599 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); | 6500 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); |
6600 | 6501 |
6601 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 6502 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
6602 // tagged as a small integer. | 6503 // tagged as a small integer. |
6603 __ bind(&runtime); | 6504 __ bind(&runtime); |
6604 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 6505 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
6605 } | 6506 } |
6606 | 6507 |
6607 | 6508 |
6608 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 6509 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |
6609 ASSERT(state_ == CompareIC::SMIS); | 6510 ASSERT(state_ == CompareIC::SMI); |
6610 Label miss; | 6511 Label miss; |
6611 __ mov(ecx, edx); | 6512 __ mov(ecx, edx); |
6612 __ or_(ecx, eax); | 6513 __ or_(ecx, eax); |
6613 __ JumpIfNotSmi(ecx, &miss, Label::kNear); | 6514 __ JumpIfNotSmi(ecx, &miss, Label::kNear); |
6614 | 6515 |
6615 if (GetCondition() == equal) { | 6516 if (GetCondition() == equal) { |
6616 // For equality we do not care about the sign of the result. | 6517 // For equality we do not care about the sign of the result. |
6617 __ sub(eax, edx); | 6518 __ sub(eax, edx); |
6618 } else { | 6519 } else { |
6619 Label done; | 6520 Label done; |
6620 __ sub(edx, eax); | 6521 __ sub(edx, eax); |
6621 __ j(no_overflow, &done, Label::kNear); | 6522 __ j(no_overflow, &done, Label::kNear); |
6622 // Correct sign of result in case of overflow. | 6523 // Correct sign of result in case of overflow. |
6623 __ not_(edx); | 6524 __ not_(edx); |
6624 __ bind(&done); | 6525 __ bind(&done); |
6625 __ mov(eax, edx); | 6526 __ mov(eax, edx); |
6626 } | 6527 } |
6627 __ ret(0); | 6528 __ ret(0); |
6628 | 6529 |
6629 __ bind(&miss); | 6530 __ bind(&miss); |
6630 GenerateMiss(masm); | 6531 GenerateMiss(masm); |
6631 } | 6532 } |
6632 | 6533 |
6633 | 6534 |
6634 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { | 6535 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { |
6635 ASSERT(state_ == CompareIC::HEAP_NUMBERS); | 6536 ASSERT(state_ == CompareIC::HEAP_NUMBER); |
6636 | 6537 |
6637 Label generic_stub; | 6538 Label generic_stub; |
6638 Label unordered, maybe_undefined1, maybe_undefined2; | 6539 Label unordered, maybe_undefined1, maybe_undefined2; |
6639 Label miss; | 6540 Label miss; |
6640 __ mov(ecx, edx); | |
6641 __ and_(ecx, eax); | |
6642 __ JumpIfSmi(ecx, &generic_stub, Label::kNear); | |
6643 | 6541 |
6644 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); | 6542 if (left_ == CompareIC::SMI) { |
6645 __ j(not_equal, &maybe_undefined1, Label::kNear); | 6543 __ JumpIfNotSmi(edx, &miss); |
6646 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); | 6544 } |
6647 __ j(not_equal, &maybe_undefined2, Label::kNear); | 6545 if (right_ == CompareIC::SMI) { |
| 6546 __ JumpIfNotSmi(eax, &miss); |
| 6547 } |
6648 | 6548 |
6649 // Inlining the double comparison and falling back to the general compare | 6549 // Inlining the double comparison and falling back to the general compare |
6650 // stub if NaN is involved or SS2 or CMOV is unsupported. | 6550 // stub if NaN is involved or SSE2 or CMOV is unsupported. |
6651 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { | 6551 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { |
6652 CpuFeatures::Scope scope1(SSE2); | 6552 CpuFeatures::Scope scope1(SSE2); |
6653 CpuFeatures::Scope scope2(CMOV); | 6553 CpuFeatures::Scope scope2(CMOV); |
6654 | 6554 |
6655 // Load left and right operand | 6555 // Load left and right operand. |
| 6556 Label done, left, left_smi, right_smi; |
| 6557 __ JumpIfSmi(eax, &right_smi, Label::kNear); |
| 6558 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 6559 masm->isolate()->factory()->heap_number_map()); |
| 6560 __ j(not_equal, &maybe_undefined1, Label::kNear); |
| 6561 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 6562 __ jmp(&left, Label::kNear); |
| 6563 __ bind(&right_smi); |
| 6564 __ mov(ecx, eax); // Can't clobber eax because we can still jump away. |
| 6565 __ SmiUntag(ecx); |
| 6566 __ cvtsi2sd(xmm1, ecx); |
| 6567 |
| 6568 __ bind(&left); |
| 6569 __ JumpIfSmi(edx, &left_smi, Label::kNear); |
| 6570 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 6571 masm->isolate()->factory()->heap_number_map()); |
| 6572 __ j(not_equal, &maybe_undefined2, Label::kNear); |
6656 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 6573 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |
6657 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 6574 __ jmp(&done); |
| 6575 __ bind(&left_smi); |
| 6576 __ mov(ecx, edx); // Can't clobber edx because we can still jump away. |
| 6577 __ SmiUntag(ecx); |
| 6578 __ cvtsi2sd(xmm0, ecx); |
6658 | 6579 |
6659 // Compare operands | 6580 __ bind(&done); |
| 6581 // Compare operands. |
6660 __ ucomisd(xmm0, xmm1); | 6582 __ ucomisd(xmm0, xmm1); |
6661 | 6583 |
6662 // Don't base result on EFLAGS when a NaN is involved. | 6584 // Don't base result on EFLAGS when a NaN is involved. |
6663 __ j(parity_even, &unordered, Label::kNear); | 6585 __ j(parity_even, &unordered, Label::kNear); |
6664 | 6586 |
6665 // Return a result of -1, 0, or 1, based on EFLAGS. | 6587 // Return a result of -1, 0, or 1, based on EFLAGS. |
6666 // Performing mov, because xor would destroy the flag register. | 6588 // Performing mov, because xor would destroy the flag register. |
6667 __ mov(eax, 0); // equal | 6589 __ mov(eax, 0); // equal |
6668 __ mov(ecx, Immediate(Smi::FromInt(1))); | 6590 __ mov(ecx, Immediate(Smi::FromInt(1))); |
6669 __ cmov(above, eax, ecx); | 6591 __ cmov(above, eax, ecx); |
6670 __ mov(ecx, Immediate(Smi::FromInt(-1))); | 6592 __ mov(ecx, Immediate(Smi::FromInt(-1))); |
6671 __ cmov(below, eax, ecx); | 6593 __ cmov(below, eax, ecx); |
6672 __ ret(0); | 6594 __ ret(0); |
| 6595 } else { |
| 6596 __ mov(ecx, edx); |
| 6597 __ and_(ecx, eax); |
| 6598 __ JumpIfSmi(ecx, &generic_stub, Label::kNear); |
| 6599 |
| 6600 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 6601 masm->isolate()->factory()->heap_number_map()); |
| 6602 __ j(not_equal, &maybe_undefined1, Label::kNear); |
| 6603 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 6604 masm->isolate()->factory()->heap_number_map()); |
| 6605 __ j(not_equal, &maybe_undefined2, Label::kNear); |
6673 } | 6606 } |
6674 | 6607 |
6675 __ bind(&unordered); | 6608 __ bind(&unordered); |
6676 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); | |
6677 __ bind(&generic_stub); | 6609 __ bind(&generic_stub); |
| 6610 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC, |
| 6611 CompareIC::GENERIC); |
6678 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); | 6612 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); |
6679 | 6613 |
6680 __ bind(&maybe_undefined1); | 6614 __ bind(&maybe_undefined1); |
6681 if (Token::IsOrderedRelationalCompareOp(op_)) { | 6615 if (Token::IsOrderedRelationalCompareOp(op_)) { |
6682 __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value())); | 6616 __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value())); |
6683 __ j(not_equal, &miss); | 6617 __ j(not_equal, &miss); |
| 6618 __ JumpIfSmi(edx, &unordered); |
6684 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); | 6619 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); |
6685 __ j(not_equal, &maybe_undefined2, Label::kNear); | 6620 __ j(not_equal, &maybe_undefined2, Label::kNear); |
6686 __ jmp(&unordered); | 6621 __ jmp(&unordered); |
6687 } | 6622 } |
6688 | 6623 |
6689 __ bind(&maybe_undefined2); | 6624 __ bind(&maybe_undefined2); |
6690 if (Token::IsOrderedRelationalCompareOp(op_)) { | 6625 if (Token::IsOrderedRelationalCompareOp(op_)) { |
6691 __ cmp(edx, Immediate(masm->isolate()->factory()->undefined_value())); | 6626 __ cmp(edx, Immediate(masm->isolate()->factory()->undefined_value())); |
6692 __ j(equal, &unordered); | 6627 __ j(equal, &unordered); |
6693 } | 6628 } |
6694 | 6629 |
6695 __ bind(&miss); | 6630 __ bind(&miss); |
6696 GenerateMiss(masm); | 6631 GenerateMiss(masm); |
6697 } | 6632 } |
6698 | 6633 |
6699 | 6634 |
6700 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { | 6635 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { |
6701 ASSERT(state_ == CompareIC::SYMBOLS); | 6636 ASSERT(state_ == CompareIC::SYMBOL); |
6702 ASSERT(GetCondition() == equal); | 6637 ASSERT(GetCondition() == equal); |
6703 | 6638 |
6704 // Registers containing left and right operands respectively. | 6639 // Registers containing left and right operands respectively. |
6705 Register left = edx; | 6640 Register left = edx; |
6706 Register right = eax; | 6641 Register right = eax; |
6707 Register tmp1 = ecx; | 6642 Register tmp1 = ecx; |
6708 Register tmp2 = ebx; | 6643 Register tmp2 = ebx; |
6709 | 6644 |
6710 // Check that both operands are heap objects. | 6645 // Check that both operands are heap objects. |
6711 Label miss; | 6646 Label miss; |
(...skipping 24 matching lines...) Expand all Loading... |
6736 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 6671 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
6737 __ bind(&done); | 6672 __ bind(&done); |
6738 __ ret(0); | 6673 __ ret(0); |
6739 | 6674 |
6740 __ bind(&miss); | 6675 __ bind(&miss); |
6741 GenerateMiss(masm); | 6676 GenerateMiss(masm); |
6742 } | 6677 } |
6743 | 6678 |
6744 | 6679 |
6745 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { | 6680 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { |
6746 ASSERT(state_ == CompareIC::STRINGS); | 6681 ASSERT(state_ == CompareIC::STRING); |
6747 Label miss; | 6682 Label miss; |
6748 | 6683 |
6749 bool equality = Token::IsEqualityOp(op_); | 6684 bool equality = Token::IsEqualityOp(op_); |
6750 | 6685 |
6751 // Registers containing left and right operands respectively. | 6686 // Registers containing left and right operands respectively. |
6752 Register left = edx; | 6687 Register left = edx; |
6753 Register right = eax; | 6688 Register right = eax; |
6754 Register tmp1 = ecx; | 6689 Register tmp1 = ecx; |
6755 Register tmp2 = ebx; | 6690 Register tmp2 = ebx; |
6756 Register tmp3 = edi; | 6691 Register tmp3 = edi; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6825 } else { | 6760 } else { |
6826 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 6761 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
6827 } | 6762 } |
6828 | 6763 |
6829 __ bind(&miss); | 6764 __ bind(&miss); |
6830 GenerateMiss(masm); | 6765 GenerateMiss(masm); |
6831 } | 6766 } |
6832 | 6767 |
6833 | 6768 |
6834 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { | 6769 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { |
6835 ASSERT(state_ == CompareIC::OBJECTS); | 6770 ASSERT(state_ == CompareIC::OBJECT); |
6836 Label miss; | 6771 Label miss; |
6837 __ mov(ecx, edx); | 6772 __ mov(ecx, edx); |
6838 __ and_(ecx, eax); | 6773 __ and_(ecx, eax); |
6839 __ JumpIfSmi(ecx, &miss, Label::kNear); | 6774 __ JumpIfSmi(ecx, &miss, Label::kNear); |
6840 | 6775 |
6841 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); | 6776 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); |
6842 __ j(not_equal, &miss, Label::kNear); | 6777 __ j(not_equal, &miss, Label::kNear); |
6843 __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); | 6778 __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); |
6844 __ j(not_equal, &miss, Label::kNear); | 6779 __ j(not_equal, &miss, Label::kNear); |
6845 | 6780 |
(...skipping 681 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7527 // Restore ecx. | 7462 // Restore ecx. |
7528 __ pop(ecx); | 7463 __ pop(ecx); |
7529 __ ret(0); | 7464 __ ret(0); |
7530 } | 7465 } |
7531 | 7466 |
7532 #undef __ | 7467 #undef __ |
7533 | 7468 |
7534 } } // namespace v8::internal | 7469 } } // namespace v8::internal |
7535 | 7470 |
7536 #endif // V8_TARGET_ARCH_IA32 | 7471 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |