| 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 |