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

Side by Side Diff: src/ia32/code-stubs-ia32.cc

Issue 10837165: Lattice-based representation inference, powered by left/right specific type feedback for BinaryOps … (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: review feedback; fixed tests Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/code-stubs-ia32.h ('k') | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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, &not_smis); 1298 __ JumpIfNotSmi(combined, &not_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
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(&not_smis); 1489 __ jmp(&not_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(&not_smis); 1589 __ bind(&not_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
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, &not_int32);
1729 }
1730 if (right_type_ == BinaryOpIC::SMI) {
1731 __ JumpIfNotSmi(eax, &not_int32);
1732 }
1779 FloatingPointHelper::LoadSSE2Operands(masm, &not_floats); 1733 FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1780 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_int32, ecx); 1734 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, &not_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, &not_int32); 1753 __ j(zero, &not_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, &not_floats, ebx); 1760 FloatingPointHelper::CheckFloatOperands(masm, &not_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, &not_int32); 1765 FloatingPointHelper::CheckFloatOperandsAreInt32(masm, &not_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(&not_floats); 1791 __ bind(&not_floats);
1837 __ bind(&not_int32); 1792 __ bind(&not_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 &not_floats); 1813 &not_floats);
1855 FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_, 1814 FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3,
1856 &not_int32); 1815 &not_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
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
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, &not_floats);
1962 }
1963 if (right_type_ == BinaryOpIC::SMI) {
1964 __ JumpIfNotSmi(eax, &not_floats);
1965 }
2014 FloatingPointHelper::LoadSSE2Operands(masm, &not_floats); 1966 FloatingPointHelper::LoadSSE2Operands(masm, &not_floats);
1967 if (left_type_ == BinaryOpIC::INT32) {
1968 FloatingPointHelper::CheckSSE2OperandIsInt32(
1969 masm, &not_floats, xmm0, ecx, xmm2);
1970 }
1971 if (right_type_ == BinaryOpIC::INT32) {
1972 FloatingPointHelper::CheckSSE2OperandIsInt32(
1973 masm, &not_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, &not_floats, ebx); 1987 FloatingPointHelper::CheckFloatOperands(masm, &not_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(&not_floats); 2009 __ bind(&not_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 &not_floats); 2033 &not_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
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, &not_floats); 2161 FloatingPointHelper::LoadSSE2Operands(masm, &not_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, &not_floats, ebx); 2174 FloatingPointHelper::CheckFloatOperands(masm, &not_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(&not_floats); 2195 __ bind(&not_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
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
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
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
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, &not_identical); 4314 __ j(not_equal, &not_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, &not_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, &not_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(&not_identical); 4373 __ bind(&not_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
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
4630 __ bind(&not_both_objects); 4579 __ bind(&not_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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ia32/code-stubs-ia32.h ('k') | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698