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

Side by Side Diff: src/arm/code-stubs-arm.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/arm/code-stubs-arm.h ('k') | src/arm/full-codegen-arm.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 23 matching lines...) Expand all
34 #include "regexp-macro-assembler.h" 34 #include "regexp-macro-assembler.h"
35 35
36 namespace v8 { 36 namespace v8 {
37 namespace internal { 37 namespace internal {
38 38
39 39
40 #define __ ACCESS_MASM(masm) 40 #define __ ACCESS_MASM(masm)
41 41
42 static void EmitIdenticalObjectComparison(MacroAssembler* masm, 42 static void EmitIdenticalObjectComparison(MacroAssembler* masm,
43 Label* slow, 43 Label* slow,
44 Condition cond, 44 Condition cond);
45 bool never_nan_nan);
46 static void EmitSmiNonsmiComparison(MacroAssembler* masm, 45 static void EmitSmiNonsmiComparison(MacroAssembler* masm,
47 Register lhs, 46 Register lhs,
48 Register rhs, 47 Register rhs,
49 Label* lhs_not_nan, 48 Label* lhs_not_nan,
50 Label* slow, 49 Label* slow,
51 bool strict); 50 bool strict);
52 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cond); 51 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cond);
53 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, 52 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
54 Register lhs, 53 Register lhs,
55 Register rhs); 54 Register rhs);
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 __ Call(stub1.GetCode()); 619 __ Call(stub1.GetCode());
621 // Write Smi from r1 to r1 and r0 in double format. 620 // Write Smi from r1 to r1 and r0 in double format.
622 __ mov(scratch1, Operand(r1)); 621 __ mov(scratch1, Operand(r1));
623 ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2); 622 ConvertToDoubleStub stub2(r1, r0, scratch1, scratch2);
624 __ Call(stub2.GetCode()); 623 __ Call(stub2.GetCode());
625 __ pop(lr); 624 __ pop(lr);
626 } 625 }
627 } 626 }
628 627
629 628
630 void FloatingPointHelper::LoadOperands(
631 MacroAssembler* masm,
632 FloatingPointHelper::Destination destination,
633 Register heap_number_map,
634 Register scratch1,
635 Register scratch2,
636 Label* slow) {
637
638 // Load right operand (r0) to d6 or r2/r3.
639 LoadNumber(masm, destination,
640 r0, d7, r2, r3, heap_number_map, scratch1, scratch2, slow);
641
642 // Load left operand (r1) to d7 or r0/r1.
643 LoadNumber(masm, destination,
644 r1, d6, r0, r1, heap_number_map, scratch1, scratch2, slow);
645 }
646
647
648 void FloatingPointHelper::LoadNumber(MacroAssembler* masm, 629 void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
649 Destination destination, 630 Destination destination,
650 Register object, 631 Register object,
651 DwVfpRegister dst, 632 DwVfpRegister dst,
652 Register dst1, 633 Register dst1,
653 Register dst2, 634 Register dst2,
654 Register heap_number_map, 635 Register heap_number_map,
655 Register scratch1, 636 Register scratch1,
656 Register scratch2, 637 Register scratch2,
657 Label* not_number) { 638 Label* not_number) {
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
903 Register scratch3, 884 Register scratch3,
904 DwVfpRegister double_scratch0, 885 DwVfpRegister double_scratch0,
905 DwVfpRegister double_scratch1, 886 DwVfpRegister double_scratch1,
906 Label* not_int32) { 887 Label* not_int32) {
907 ASSERT(!dst.is(object)); 888 ASSERT(!dst.is(object));
908 ASSERT(!scratch1.is(object) && !scratch2.is(object) && !scratch3.is(object)); 889 ASSERT(!scratch1.is(object) && !scratch2.is(object) && !scratch3.is(object));
909 ASSERT(!scratch1.is(scratch2) && 890 ASSERT(!scratch1.is(scratch2) &&
910 !scratch1.is(scratch3) && 891 !scratch1.is(scratch3) &&
911 !scratch2.is(scratch3)); 892 !scratch2.is(scratch3));
912 893
913 Label done; 894 Label done, maybe_undefined;
914 895
915 __ UntagAndJumpIfSmi(dst, object, &done); 896 __ UntagAndJumpIfSmi(dst, object, &done);
916 897
917 __ AssertRootValue(heap_number_map, 898 __ AssertRootValue(heap_number_map,
918 Heap::kHeapNumberMapRootIndex, 899 Heap::kHeapNumberMapRootIndex,
919 "HeapNumberMap register clobbered."); 900 "HeapNumberMap register clobbered.");
920 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_int32); 901
902 __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, &maybe_undefined);
921 903
922 // Object is a heap number. 904 // Object is a heap number.
923 // Convert the floating point value to a 32-bit integer. 905 // Convert the floating point value to a 32-bit integer.
924 if (CpuFeatures::IsSupported(VFP2)) { 906 if (CpuFeatures::IsSupported(VFP2)) {
925 CpuFeatures::Scope scope(VFP2); 907 CpuFeatures::Scope scope(VFP2);
926 908
927 // Load the double value. 909 // Load the double value.
928 __ sub(scratch1, object, Operand(kHeapObjectTag)); 910 __ sub(scratch1, object, Operand(kHeapObjectTag));
929 __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset); 911 __ vldr(double_scratch0, scratch1, HeapNumber::kValueOffset);
930 912
(...skipping 26 matching lines...) Expand all
957 // Shift back the higher bits of the mantissa. 939 // Shift back the higher bits of the mantissa.
958 __ mov(dst, Operand(dst, LSR, scratch3)); 940 __ mov(dst, Operand(dst, LSR, scratch3));
959 // Set the implicit first bit. 941 // Set the implicit first bit.
960 __ rsb(scratch3, scratch3, Operand(32)); 942 __ rsb(scratch3, scratch3, Operand(32));
961 __ orr(dst, dst, Operand(scratch2, LSL, scratch3)); 943 __ orr(dst, dst, Operand(scratch2, LSL, scratch3));
962 // Set the sign. 944 // Set the sign.
963 __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset)); 945 __ ldr(scratch1, FieldMemOperand(object, HeapNumber::kExponentOffset));
964 __ tst(scratch1, Operand(HeapNumber::kSignMask)); 946 __ tst(scratch1, Operand(HeapNumber::kSignMask));
965 __ rsb(dst, dst, Operand::Zero(), LeaveCC, mi); 947 __ rsb(dst, dst, Operand::Zero(), LeaveCC, mi);
966 } 948 }
949 __ b(&done);
950
951 __ bind(&maybe_undefined);
952 __ CompareRoot(object, Heap::kUndefinedValueRootIndex);
953 __ b(ne, not_int32);
954 // |undefined| is truncated to 0.
955 __ mov(dst, Operand(Smi::FromInt(0)));
956 // Fall through.
967 957
968 __ bind(&done); 958 __ bind(&done);
969 } 959 }
970 960
971 961
972 void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm, 962 void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm,
973 Register src1, 963 Register src1,
974 Register src2, 964 Register src2,
975 Register dst, 965 Register dst,
976 Register scratch, 966 Register scratch,
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
1141 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset)); 1131 __ str(ip, FieldMemOperand(the_heap_number_, HeapNumber::kMantissaOffset));
1142 __ Ret(); 1132 __ Ret();
1143 } 1133 }
1144 1134
1145 1135
1146 // Handle the case where the lhs and rhs are the same object. 1136 // Handle the case where the lhs and rhs are the same object.
1147 // Equality is almost reflexive (everything but NaN), so this is a test 1137 // Equality is almost reflexive (everything but NaN), so this is a test
1148 // for "identity and not NaN". 1138 // for "identity and not NaN".
1149 static void EmitIdenticalObjectComparison(MacroAssembler* masm, 1139 static void EmitIdenticalObjectComparison(MacroAssembler* masm,
1150 Label* slow, 1140 Label* slow,
1151 Condition cond, 1141 Condition cond) {
1152 bool never_nan_nan) {
1153 Label not_identical; 1142 Label not_identical;
1154 Label heap_number, return_equal; 1143 Label heap_number, return_equal;
1155 __ cmp(r0, r1); 1144 __ cmp(r0, r1);
1156 __ b(ne, &not_identical); 1145 __ b(ne, &not_identical);
1157 1146
1158 // The two objects are identical. If we know that one of them isn't NaN then 1147 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(),
1159 // we now know they test equal. 1148 // so we do the second best thing - test it ourselves.
1160 if (cond != eq || !never_nan_nan) { 1149 // They are both equal and they are not both Smis so both of them are not
1161 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), 1150 // Smis. If it's not a heap number, then return equal.
1162 // so we do the second best thing - test it ourselves. 1151 if (cond == lt || cond == gt) {
1163 // They are both equal and they are not both Smis so both of them are not 1152 __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE);
1164 // Smis. If it's not a heap number, then return equal. 1153 __ b(ge, slow);
1165 if (cond == lt || cond == gt) { 1154 } else {
1166 __ CompareObjectType(r0, r4, r4, FIRST_SPEC_OBJECT_TYPE); 1155 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE);
1156 __ b(eq, &heap_number);
1157 // Comparing JS objects with <=, >= is complicated.
1158 if (cond != eq) {
1159 __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE));
1167 __ b(ge, slow); 1160 __ b(ge, slow);
1168 } else { 1161 // Normally here we fall through to return_equal, but undefined is
1169 __ CompareObjectType(r0, r4, r4, HEAP_NUMBER_TYPE); 1162 // special: (undefined == undefined) == true, but
1170 __ b(eq, &heap_number); 1163 // (undefined <= undefined) == false! See ECMAScript 11.8.5.
1171 // Comparing JS objects with <=, >= is complicated. 1164 if (cond == le || cond == ge) {
1172 if (cond != eq) { 1165 __ cmp(r4, Operand(ODDBALL_TYPE));
1173 __ cmp(r4, Operand(FIRST_SPEC_OBJECT_TYPE)); 1166 __ b(ne, &return_equal);
1174 __ b(ge, slow); 1167 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
1175 // Normally here we fall through to return_equal, but undefined is 1168 __ cmp(r0, r2);
1176 // special: (undefined == undefined) == true, but 1169 __ b(ne, &return_equal);
1177 // (undefined <= undefined) == false! See ECMAScript 11.8.5. 1170 if (cond == le) {
1178 if (cond == le || cond == ge) { 1171 // undefined <= undefined should fail.
1179 __ cmp(r4, Operand(ODDBALL_TYPE)); 1172 __ mov(r0, Operand(GREATER));
1180 __ b(ne, &return_equal); 1173 } else {
1181 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); 1174 // undefined >= undefined should fail.
1182 __ cmp(r0, r2); 1175 __ mov(r0, Operand(LESS));
1183 __ b(ne, &return_equal);
1184 if (cond == le) {
1185 // undefined <= undefined should fail.
1186 __ mov(r0, Operand(GREATER));
1187 } else {
1188 // undefined >= undefined should fail.
1189 __ mov(r0, Operand(LESS));
1190 }
1191 __ Ret();
1192 } 1176 }
1177 __ Ret();
1193 } 1178 }
1194 } 1179 }
1195 } 1180 }
1196 1181
1197 __ bind(&return_equal); 1182 __ bind(&return_equal);
1198 if (cond == lt) { 1183 if (cond == lt) {
1199 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves. 1184 __ mov(r0, Operand(GREATER)); // Things aren't less than themselves.
1200 } else if (cond == gt) { 1185 } else if (cond == gt) {
1201 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves. 1186 __ mov(r0, Operand(LESS)); // Things aren't greater than themselves.
1202 } else { 1187 } else {
1203 __ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves. 1188 __ mov(r0, Operand(EQUAL)); // Things are <=, >=, ==, === themselves.
1204 } 1189 }
1205 __ Ret(); 1190 __ Ret();
1206 1191
1207 if (cond != eq || !never_nan_nan) { 1192 // For less and greater we don't have to check for NaN since the result of
1208 // For less and greater we don't have to check for NaN since the result of 1193 // x < x is false regardless. For the others here is some code to check
1209 // x < x is false regardless. For the others here is some code to check 1194 // for NaN.
1210 // for NaN. 1195 if (cond != lt && cond != gt) {
1211 if (cond != lt && cond != gt) { 1196 __ bind(&heap_number);
1212 __ bind(&heap_number); 1197 // It is a heap number, so return non-equal if it's NaN and equal if it's
1213 // It is a heap number, so return non-equal if it's NaN and equal if it's 1198 // not NaN.
1214 // not NaN.
1215 1199
1216 // The representation of NaN values has all exponent bits (52..62) set, 1200 // The representation of NaN values has all exponent bits (52..62) set,
1217 // and not all mantissa bits (0..51) clear. 1201 // and not all mantissa bits (0..51) clear.
1218 // Read top bits of double representation (second word of value). 1202 // Read top bits of double representation (second word of value).
1219 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); 1203 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
1220 // Test that exponent bits are all set. 1204 // Test that exponent bits are all set.
1221 __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits); 1205 __ Sbfx(r3, r2, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
1222 // NaNs have all-one exponents so they sign extend to -1. 1206 // NaNs have all-one exponents so they sign extend to -1.
1223 __ cmp(r3, Operand(-1)); 1207 __ cmp(r3, Operand(-1));
1224 __ b(ne, &return_equal); 1208 __ b(ne, &return_equal);
1225 1209
1226 // Shift out flag and all exponent bits, retaining only mantissa. 1210 // Shift out flag and all exponent bits, retaining only mantissa.
1227 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord)); 1211 __ mov(r2, Operand(r2, LSL, HeapNumber::kNonMantissaBitsInTopWord));
1228 // Or with all low-bits of mantissa. 1212 // Or with all low-bits of mantissa.
1229 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); 1213 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
1230 __ orr(r0, r3, Operand(r2), SetCC); 1214 __ orr(r0, r3, Operand(r2), SetCC);
1231 // For equal we already have the right value in r0: Return zero (equal) 1215 // For equal we already have the right value in r0: Return zero (equal)
1232 // if all bits in mantissa are zero (it's an Infinity) and non-zero if 1216 // if all bits in mantissa are zero (it's an Infinity) and non-zero if
1233 // not (it's a NaN). For <= and >= we need to load r0 with the failing 1217 // not (it's a NaN). For <= and >= we need to load r0 with the failing
1234 // value if it's a NaN. 1218 // value if it's a NaN.
1235 if (cond != eq) { 1219 if (cond != eq) {
1236 // All-zero means Infinity means equal. 1220 // All-zero means Infinity means equal.
1237 __ Ret(eq); 1221 __ Ret(eq);
1238 if (cond == le) { 1222 if (cond == le) {
1239 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail. 1223 __ mov(r0, Operand(GREATER)); // NaN <= NaN should fail.
1240 } else { 1224 } else {
1241 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail. 1225 __ mov(r0, Operand(LESS)); // NaN >= NaN should fail.
1242 }
1243 } 1226 }
1244 __ Ret();
1245 } 1227 }
1246 // No fall through here. 1228 __ Ret();
1247 } 1229 }
1230 // No fall through here.
1248 1231
1249 __ bind(&not_identical); 1232 __ bind(&not_identical);
1250 } 1233 }
1251 1234
1252 1235
1253 // See comment at call site. 1236 // See comment at call site.
1254 static void EmitSmiNonsmiComparison(MacroAssembler* masm, 1237 static void EmitSmiNonsmiComparison(MacroAssembler* masm,
1255 Register lhs, 1238 Register lhs,
1256 Register rhs, 1239 Register rhs,
1257 Label* lhs_not_nan, 1240 Label* lhs_not_nan,
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after
1671 GenerateLookupNumberStringCache(masm, r1, r0, r2, r3, r4, false, &runtime); 1654 GenerateLookupNumberStringCache(masm, r1, r0, r2, r3, r4, false, &runtime);
1672 __ add(sp, sp, Operand(1 * kPointerSize)); 1655 __ add(sp, sp, Operand(1 * kPointerSize));
1673 __ Ret(); 1656 __ Ret();
1674 1657
1675 __ bind(&runtime); 1658 __ bind(&runtime);
1676 // Handle number to string in the runtime system if not found in the cache. 1659 // Handle number to string in the runtime system if not found in the cache.
1677 __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1); 1660 __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1);
1678 } 1661 }
1679 1662
1680 1663
1681 // On entry lhs_ and rhs_ are the values to be compared. 1664 static void ICCompareStub_CheckInputType(MacroAssembler* masm,
1665 Register input,
1666 Register scratch,
1667 CompareIC::State expected,
1668 Label* fail) {
1669 Label ok;
1670 if (expected == CompareIC::SMI) {
1671 __ JumpIfNotSmi(input, fail);
1672 } else if (expected == CompareIC::HEAP_NUMBER) {
1673 __ JumpIfSmi(input, &ok);
1674 __ CheckMap(input, scratch, Heap::kHeapNumberMapRootIndex, fail,
1675 DONT_DO_SMI_CHECK);
1676 }
1677 // We could be strict about symbol/string here, but as long as
1678 // hydrogen doesn't care, the stub doesn't have to care either.
1679 __ bind(&ok);
1680 }
1681
1682
1683 // On entry r1 and r2 are the values to be compared.
1682 // On exit r0 is 0, positive or negative to indicate the result of 1684 // On exit r0 is 0, positive or negative to indicate the result of
1683 // the comparison. 1685 // the comparison.
1684 void CompareStub::Generate(MacroAssembler* masm) { 1686 void ICCompareStub::GenerateGeneric(MacroAssembler* masm) {
1685 ASSERT((lhs_.is(r0) && rhs_.is(r1)) || 1687 Register lhs = r1;
1686 (lhs_.is(r1) && rhs_.is(r0))); 1688 Register rhs = r0;
1689 Condition cc = GetCondition();
1690
1691 Label miss;
1692 ICCompareStub_CheckInputType(masm, lhs, r2, left_, &miss);
1693 ICCompareStub_CheckInputType(masm, rhs, r3, right_, &miss);
1687 1694
1688 Label slow; // Call builtin. 1695 Label slow; // Call builtin.
1689 Label not_smis, both_loaded_as_doubles, lhs_not_nan; 1696 Label not_smis, both_loaded_as_doubles, lhs_not_nan;
1690 1697
1691 if (include_smi_compare_) { 1698 Label not_two_smis, smi_done;
1692 Label not_two_smis, smi_done; 1699 __ orr(r2, r1, r0);
1693 __ orr(r2, r1, r0); 1700 __ JumpIfNotSmi(r2, &not_two_smis);
1694 __ JumpIfNotSmi(r2, &not_two_smis); 1701 __ mov(r1, Operand(r1, ASR, 1));
1695 __ mov(r1, Operand(r1, ASR, 1)); 1702 __ sub(r0, r1, Operand(r0, ASR, 1));
1696 __ sub(r0, r1, Operand(r0, ASR, 1)); 1703 __ Ret();
1697 __ Ret(); 1704 __ bind(&not_two_smis);
1698 __ bind(&not_two_smis);
1699 } else if (FLAG_debug_code) {
1700 __ orr(r2, r1, r0);
1701 __ tst(r2, Operand(kSmiTagMask));
1702 __ Assert(ne, "CompareStub: unexpected smi operands.");
1703 }
1704 1705
1705 // NOTICE! This code is only reached after a smi-fast-case check, so 1706 // NOTICE! This code is only reached after a smi-fast-case check, so
1706 // it is certain that at least one operand isn't a smi. 1707 // it is certain that at least one operand isn't a smi.
1707 1708
1708 // Handle the case where the objects are identical. Either returns the answer 1709 // Handle the case where the objects are identical. Either returns the answer
1709 // or goes to slow. Only falls through if the objects were not identical. 1710 // or goes to slow. Only falls through if the objects were not identical.
1710 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); 1711 EmitIdenticalObjectComparison(masm, &slow, cc);
1711 1712
1712 // If either is a Smi (we know that not both are), then they can only 1713 // If either is a Smi (we know that not both are), then they can only
1713 // be strictly equal if the other is a HeapNumber. 1714 // be strictly equal if the other is a HeapNumber.
1714 STATIC_ASSERT(kSmiTag == 0); 1715 STATIC_ASSERT(kSmiTag == 0);
1715 ASSERT_EQ(0, Smi::FromInt(0)); 1716 ASSERT_EQ(0, Smi::FromInt(0));
1716 __ and_(r2, lhs_, Operand(rhs_)); 1717 __ and_(r2, lhs, Operand(rhs));
1717 __ JumpIfNotSmi(r2, &not_smis); 1718 __ JumpIfNotSmi(r2, &not_smis);
1718 // One operand is a smi. EmitSmiNonsmiComparison generates code that can: 1719 // One operand is a smi. EmitSmiNonsmiComparison generates code that can:
1719 // 1) Return the answer. 1720 // 1) Return the answer.
1720 // 2) Go to slow. 1721 // 2) Go to slow.
1721 // 3) Fall through to both_loaded_as_doubles. 1722 // 3) Fall through to both_loaded_as_doubles.
1722 // 4) Jump to lhs_not_nan. 1723 // 4) Jump to lhs_not_nan.
1723 // In cases 3 and 4 we have found out we were dealing with a number-number 1724 // In cases 3 and 4 we have found out we were dealing with a number-number
1724 // comparison. If VFP3 is supported the double values of the numbers have 1725 // comparison. If VFP3 is supported the double values of the numbers have
1725 // been loaded into d7 and d6. Otherwise, the double values have been loaded 1726 // been loaded into d7 and d6. Otherwise, the double values have been loaded
1726 // into r0, r1, r2, and r3. 1727 // into r0, r1, r2, and r3.
1727 EmitSmiNonsmiComparison(masm, lhs_, rhs_, &lhs_not_nan, &slow, strict_); 1728 EmitSmiNonsmiComparison(masm, lhs, rhs, &lhs_not_nan, &slow, strict());
1728 1729
1729 __ bind(&both_loaded_as_doubles); 1730 __ bind(&both_loaded_as_doubles);
1730 // The arguments have been converted to doubles and stored in d6 and d7, if 1731 // The arguments have been converted to doubles and stored in d6 and d7, if
1731 // VFP3 is supported, or in r0, r1, r2, and r3. 1732 // VFP3 is supported, or in r0, r1, r2, and r3.
1732 Isolate* isolate = masm->isolate(); 1733 Isolate* isolate = masm->isolate();
1733 if (CpuFeatures::IsSupported(VFP2)) { 1734 if (CpuFeatures::IsSupported(VFP2)) {
1734 __ bind(&lhs_not_nan); 1735 __ bind(&lhs_not_nan);
1735 CpuFeatures::Scope scope(VFP2); 1736 CpuFeatures::Scope scope(VFP2);
1736 Label no_nan; 1737 Label no_nan;
1737 // ARMv7 VFP3 instructions to implement double precision comparison. 1738 // ARMv7 VFP3 instructions to implement double precision comparison.
1738 __ VFPCompareAndSetFlags(d7, d6); 1739 __ VFPCompareAndSetFlags(d7, d6);
1739 Label nan; 1740 Label nan;
1740 __ b(vs, &nan); 1741 __ b(vs, &nan);
1741 __ mov(r0, Operand(EQUAL), LeaveCC, eq); 1742 __ mov(r0, Operand(EQUAL), LeaveCC, eq);
1742 __ mov(r0, Operand(LESS), LeaveCC, lt); 1743 __ mov(r0, Operand(LESS), LeaveCC, lt);
1743 __ mov(r0, Operand(GREATER), LeaveCC, gt); 1744 __ mov(r0, Operand(GREATER), LeaveCC, gt);
1744 __ Ret(); 1745 __ Ret();
1745 1746
1746 __ bind(&nan); 1747 __ bind(&nan);
1747 // If one of the sides was a NaN then the v flag is set. Load r0 with 1748 // If one of the sides was a NaN then the v flag is set. Load r0 with
1748 // whatever it takes to make the comparison fail, since comparisons with NaN 1749 // whatever it takes to make the comparison fail, since comparisons with NaN
1749 // always fail. 1750 // always fail.
1750 if (cc_ == lt || cc_ == le) { 1751 if (cc == lt || cc == le) {
1751 __ mov(r0, Operand(GREATER)); 1752 __ mov(r0, Operand(GREATER));
1752 } else { 1753 } else {
1753 __ mov(r0, Operand(LESS)); 1754 __ mov(r0, Operand(LESS));
1754 } 1755 }
1755 __ Ret(); 1756 __ Ret();
1756 } else { 1757 } else {
1757 // Checks for NaN in the doubles we have loaded. Can return the answer or 1758 // Checks for NaN in the doubles we have loaded. Can return the answer or
1758 // fall through if neither is a NaN. Also binds lhs_not_nan. 1759 // fall through if neither is a NaN. Also binds lhs_not_nan.
1759 EmitNanCheck(masm, &lhs_not_nan, cc_); 1760 EmitNanCheck(masm, &lhs_not_nan, cc);
1760 // Compares two doubles in r0, r1, r2, r3 that are not NaNs. Returns the 1761 // Compares two doubles in r0, r1, r2, r3 that are not NaNs. Returns the
1761 // answer. Never falls through. 1762 // answer. Never falls through.
1762 EmitTwoNonNanDoubleComparison(masm, cc_); 1763 EmitTwoNonNanDoubleComparison(masm, cc);
1763 } 1764 }
1764 1765
1765 __ bind(&not_smis); 1766 __ bind(&not_smis);
1766 // At this point we know we are dealing with two different objects, 1767 // At this point we know we are dealing with two different objects,
1767 // and neither of them is a Smi. The objects are in rhs_ and lhs_. 1768 // and neither of them is a Smi. The objects are in rhs_ and lhs_.
1768 if (strict_) { 1769 if (strict()) {
1769 // This returns non-equal for some object types, or falls through if it 1770 // This returns non-equal for some object types, or falls through if it
1770 // was not lucky. 1771 // was not lucky.
1771 EmitStrictTwoHeapObjectCompare(masm, lhs_, rhs_); 1772 EmitStrictTwoHeapObjectCompare(masm, lhs, rhs);
1772 } 1773 }
1773 1774
1774 Label check_for_symbols; 1775 Label check_for_symbols;
1775 Label flat_string_check; 1776 Label flat_string_check;
1776 // Check for heap-number-heap-number comparison. Can jump to slow case, 1777 // Check for heap-number-heap-number comparison. Can jump to slow case,
1777 // or load both doubles into r0, r1, r2, r3 and jump to the code that handles 1778 // or load both doubles into r0, r1, r2, r3 and jump to the code that handles
1778 // that case. If the inputs are not doubles then jumps to check_for_symbols. 1779 // that case. If the inputs are not doubles then jumps to check_for_symbols.
1779 // In this case r2 will contain the type of rhs_. Never falls through. 1780 // In this case r2 will contain the type of rhs_. Never falls through.
1780 EmitCheckForTwoHeapNumbers(masm, 1781 EmitCheckForTwoHeapNumbers(masm,
1781 lhs_, 1782 lhs,
1782 rhs_, 1783 rhs,
1783 &both_loaded_as_doubles, 1784 &both_loaded_as_doubles,
1784 &check_for_symbols, 1785 &check_for_symbols,
1785 &flat_string_check); 1786 &flat_string_check);
1786 1787
1787 __ bind(&check_for_symbols); 1788 __ bind(&check_for_symbols);
1788 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of 1789 // In the strict case the EmitStrictTwoHeapObjectCompare already took care of
1789 // symbols. 1790 // symbols.
1790 if (cc_ == eq && !strict_) { 1791 if (cc == eq && !strict()) {
1791 // Returns an answer for two symbols or two detectable objects. 1792 // Returns an answer for two symbols or two detectable objects.
1792 // Otherwise jumps to string case or not both strings case. 1793 // Otherwise jumps to string case or not both strings case.
1793 // Assumes that r2 is the type of rhs_ on entry. 1794 // Assumes that r2 is the type of rhs_ on entry.
1794 EmitCheckForSymbolsOrObjects(masm, lhs_, rhs_, &flat_string_check, &slow); 1795 EmitCheckForSymbolsOrObjects(masm, lhs, rhs, &flat_string_check, &slow);
1795 } 1796 }
1796 1797
1797 // Check for both being sequential ASCII strings, and inline if that is the 1798 // Check for both being sequential ASCII strings, and inline if that is the
1798 // case. 1799 // case.
1799 __ bind(&flat_string_check); 1800 __ bind(&flat_string_check);
1800 1801
1801 __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs_, rhs_, r2, r3, &slow); 1802 __ JumpIfNonSmisNotBothSequentialAsciiStrings(lhs, rhs, r2, r3, &slow);
1802 1803
1803 __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3); 1804 __ IncrementCounter(isolate->counters()->string_compare_native(), 1, r2, r3);
1804 if (cc_ == eq) { 1805 if (cc == eq) {
1805 StringCompareStub::GenerateFlatAsciiStringEquals(masm, 1806 StringCompareStub::GenerateFlatAsciiStringEquals(masm,
1806 lhs_, 1807 lhs,
1807 rhs_, 1808 rhs,
1808 r2, 1809 r2,
1809 r3, 1810 r3,
1810 r4); 1811 r4);
1811 } else { 1812 } else {
1812 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, 1813 StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
1813 lhs_, 1814 lhs,
1814 rhs_, 1815 rhs,
1815 r2, 1816 r2,
1816 r3, 1817 r3,
1817 r4, 1818 r4,
1818 r5); 1819 r5);
1819 } 1820 }
1820 // Never falls through to here. 1821 // Never falls through to here.
1821 1822
1822 __ bind(&slow); 1823 __ bind(&slow);
1823 1824
1824 __ Push(lhs_, rhs_); 1825 __ Push(lhs, rhs);
1825 // Figure out which native to call and setup the arguments. 1826 // Figure out which native to call and setup the arguments.
1826 Builtins::JavaScript native; 1827 Builtins::JavaScript native;
1827 if (cc_ == eq) { 1828 if (cc == eq) {
1828 native = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; 1829 native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
1829 } else { 1830 } else {
1830 native = Builtins::COMPARE; 1831 native = Builtins::COMPARE;
1831 int ncr; // NaN compare result 1832 int ncr; // NaN compare result
1832 if (cc_ == lt || cc_ == le) { 1833 if (cc == lt || cc == le) {
1833 ncr = GREATER; 1834 ncr = GREATER;
1834 } else { 1835 } else {
1835 ASSERT(cc_ == gt || cc_ == ge); // remaining cases 1836 ASSERT(cc == gt || cc == ge); // remaining cases
1836 ncr = LESS; 1837 ncr = LESS;
1837 } 1838 }
1838 __ mov(r0, Operand(Smi::FromInt(ncr))); 1839 __ mov(r0, Operand(Smi::FromInt(ncr)));
1839 __ push(r0); 1840 __ push(r0);
1840 } 1841 }
1841 1842
1842 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) 1843 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
1843 // tagged as a small integer. 1844 // tagged as a small integer.
1844 __ InvokeBuiltin(native, JUMP_FUNCTION); 1845 __ InvokeBuiltin(native, JUMP_FUNCTION);
1846
1847 __ bind(&miss);
1848 GenerateMiss(masm);
1845 } 1849 }
1846 1850
1847 1851
1848 // The stub expects its argument in the tos_ register and returns its result in 1852 // The stub expects its argument in the tos_ register and returns its result in
1849 // it, too: zero for false, and a non-zero value for true. 1853 // it, too: zero for false, and a non-zero value for true.
1850 void ToBooleanStub::Generate(MacroAssembler* masm) { 1854 void ToBooleanStub::Generate(MacroAssembler* masm) {
1851 // This stub overrides SometimesSetsUpAFrame() to return false. That means 1855 // This stub overrides SometimesSetsUpAFrame() to return false. That means
1852 // we cannot call anything that could cause a GC from this stub. 1856 // we cannot call anything that could cause a GC from this stub.
1853 Label patch; 1857 Label patch;
1854 const Register map = r9.is(tos_) ? r7 : r9; 1858 const Register map = r9.is(tos_) ? r7 : r9;
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after
2318 break; 2322 break;
2319 case Token::BIT_NOT: 2323 case Token::BIT_NOT:
2320 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); 2324 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION);
2321 break; 2325 break;
2322 default: 2326 default:
2323 UNREACHABLE(); 2327 UNREACHABLE();
2324 } 2328 }
2325 } 2329 }
2326 2330
2327 2331
2332 void BinaryOpStub::Initialize() {
2333 platform_specific_bit_ = CpuFeatures::IsSupported(VFP2);
2334 }
2335
2336
2328 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 2337 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) {
2329 Label get_result; 2338 Label get_result;
2330 2339
2331 __ Push(r1, r0); 2340 __ Push(r1, r0);
2332 2341
2333 __ mov(r2, Operand(Smi::FromInt(MinorKey()))); 2342 __ mov(r2, Operand(Smi::FromInt(MinorKey())));
2334 __ mov(r1, Operand(Smi::FromInt(op_))); 2343 __ push(r2);
2335 __ mov(r0, Operand(Smi::FromInt(operands_type_)));
2336 __ Push(r2, r1, r0);
2337 2344
2338 __ TailCallExternalReference( 2345 __ TailCallExternalReference(
2339 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 2346 ExternalReference(IC_Utility(IC::kBinaryOp_Patch),
2340 masm->isolate()), 2347 masm->isolate()),
2341 5, 2348 3,
2342 1); 2349 1);
2343 } 2350 }
2344 2351
2345 2352
2346 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs( 2353 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(
2347 MacroAssembler* masm) { 2354 MacroAssembler* masm) {
2348 UNIMPLEMENTED(); 2355 UNIMPLEMENTED();
2349 } 2356 }
2350 2357
2351 2358
2352 void BinaryOpStub::Generate(MacroAssembler* masm) { 2359 void BinaryOpStub_GenerateSmiSmiOperation(MacroAssembler* masm,
2353 // Explicitly allow generation of nested stubs. It is safe here because 2360 Token::Value op) {
2354 // generation code does not use any raw pointers.
2355 AllowStubCallsScope allow_stub_calls(masm, true);
2356
2357 switch (operands_type_) {
2358 case BinaryOpIC::UNINITIALIZED:
2359 GenerateTypeTransition(masm);
2360 break;
2361 case BinaryOpIC::SMI:
2362 GenerateSmiStub(masm);
2363 break;
2364 case BinaryOpIC::INT32:
2365 GenerateInt32Stub(masm);
2366 break;
2367 case BinaryOpIC::HEAP_NUMBER:
2368 GenerateHeapNumberStub(masm);
2369 break;
2370 case BinaryOpIC::ODDBALL:
2371 GenerateOddballStub(masm);
2372 break;
2373 case BinaryOpIC::BOTH_STRING:
2374 GenerateBothStringStub(masm);
2375 break;
2376 case BinaryOpIC::STRING:
2377 GenerateStringStub(masm);
2378 break;
2379 case BinaryOpIC::GENERIC:
2380 GenerateGeneric(masm);
2381 break;
2382 default:
2383 UNREACHABLE();
2384 }
2385 }
2386
2387
2388 void BinaryOpStub::PrintName(StringStream* stream) {
2389 const char* op_name = Token::Name(op_);
2390 const char* overwrite_name;
2391 switch (mode_) {
2392 case NO_OVERWRITE: overwrite_name = "Alloc"; break;
2393 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
2394 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
2395 default: overwrite_name = "UnknownOverwrite"; break;
2396 }
2397 stream->Add("BinaryOpStub_%s_%s_%s",
2398 op_name,
2399 overwrite_name,
2400 BinaryOpIC::GetName(operands_type_));
2401 }
2402
2403
2404 void BinaryOpStub::GenerateSmiSmiOperation(MacroAssembler* masm) {
2405 Register left = r1; 2361 Register left = r1;
2406 Register right = r0; 2362 Register right = r0;
2407 Register scratch1 = r7; 2363 Register scratch1 = r7;
2408 Register scratch2 = r9; 2364 Register scratch2 = r9;
2409 2365
2410 ASSERT(right.is(r0)); 2366 ASSERT(right.is(r0));
2411 STATIC_ASSERT(kSmiTag == 0); 2367 STATIC_ASSERT(kSmiTag == 0);
2412 2368
2413 Label not_smi_result; 2369 Label not_smi_result;
2414 switch (op_) { 2370 switch (op) {
2415 case Token::ADD: 2371 case Token::ADD:
2416 __ add(right, left, Operand(right), SetCC); // Add optimistically. 2372 __ add(right, left, Operand(right), SetCC); // Add optimistically.
2417 __ Ret(vc); 2373 __ Ret(vc);
2418 __ sub(right, right, Operand(left)); // Revert optimistic add. 2374 __ sub(right, right, Operand(left)); // Revert optimistic add.
2419 break; 2375 break;
2420 case Token::SUB: 2376 case Token::SUB:
2421 __ sub(right, left, Operand(right), SetCC); // Subtract optimistically. 2377 __ sub(right, left, Operand(right), SetCC); // Subtract optimistically.
2422 __ Ret(vc); 2378 __ Ret(vc);
2423 __ sub(right, left, Operand(right)); // Revert optimistic subtract. 2379 __ sub(right, left, Operand(right)); // Revert optimistic subtract.
2424 break; 2380 break;
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
2519 __ SmiTag(right, scratch1); 2475 __ SmiTag(right, scratch1);
2520 __ Ret(); 2476 __ Ret();
2521 break; 2477 break;
2522 default: 2478 default:
2523 UNREACHABLE(); 2479 UNREACHABLE();
2524 } 2480 }
2525 __ bind(&not_smi_result); 2481 __ bind(&not_smi_result);
2526 } 2482 }
2527 2483
2528 2484
2529 void BinaryOpStub::GenerateFPOperation(MacroAssembler* masm, 2485 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
2530 bool smi_operands, 2486 Register result,
2531 Label* not_numbers, 2487 Register heap_number_map,
2532 Label* gc_required) { 2488 Register scratch1,
2489 Register scratch2,
2490 Label* gc_required,
2491 OverwriteMode mode);
2492
2493
2494 void BinaryOpStub_GenerateFPOperation(MacroAssembler* masm,
2495 BinaryOpIC::TypeInfo left_type,
2496 BinaryOpIC::TypeInfo right_type,
2497 bool smi_operands,
2498 Label* not_numbers,
2499 Label* gc_required,
2500 Label* miss,
2501 Token::Value op,
2502 OverwriteMode mode) {
2533 Register left = r1; 2503 Register left = r1;
2534 Register right = r0; 2504 Register right = r0;
2535 Register scratch1 = r7; 2505 Register scratch1 = r7;
2536 Register scratch2 = r9; 2506 Register scratch2 = r9;
2537 Register scratch3 = r4; 2507 Register scratch3 = r4;
2538 2508
2539 ASSERT(smi_operands || (not_numbers != NULL)); 2509 ASSERT(smi_operands || (not_numbers != NULL));
2540 if (smi_operands) { 2510 if (smi_operands) {
2541 __ AssertSmi(left); 2511 __ AssertSmi(left);
2542 __ AssertSmi(right); 2512 __ AssertSmi(right);
2543 } 2513 }
2514 if (left_type == BinaryOpIC::SMI) {
2515 __ JumpIfNotSmi(left, miss);
2516 }
2517 if (right_type == BinaryOpIC::SMI) {
2518 __ JumpIfNotSmi(right, miss);
2519 }
2544 2520
2545 Register heap_number_map = r6; 2521 Register heap_number_map = r6;
2546 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 2522 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2547 2523
2548 switch (op_) { 2524 switch (op) {
2549 case Token::ADD: 2525 case Token::ADD:
2550 case Token::SUB: 2526 case Token::SUB:
2551 case Token::MUL: 2527 case Token::MUL:
2552 case Token::DIV: 2528 case Token::DIV:
2553 case Token::MOD: { 2529 case Token::MOD: {
2554 // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 2530 // Load left and right operands into d6 and d7 or r0/r1 and r2/r3
2555 // depending on whether VFP3 is available or not. 2531 // depending on whether VFP3 is available or not.
2556 FloatingPointHelper::Destination destination = 2532 FloatingPointHelper::Destination destination =
2557 CpuFeatures::IsSupported(VFP2) && 2533 CpuFeatures::IsSupported(VFP2) &&
2558 op_ != Token::MOD ? 2534 op != Token::MOD ?
2559 FloatingPointHelper::kVFPRegisters : 2535 FloatingPointHelper::kVFPRegisters :
2560 FloatingPointHelper::kCoreRegisters; 2536 FloatingPointHelper::kCoreRegisters;
2561 2537
2562 // Allocate new heap number for result. 2538 // Allocate new heap number for result.
2563 Register result = r5; 2539 Register result = r5;
2564 GenerateHeapResultAllocation( 2540 BinaryOpStub_GenerateHeapResultAllocation(
2565 masm, result, heap_number_map, scratch1, scratch2, gc_required); 2541 masm, result, heap_number_map, scratch1, scratch2, gc_required, mode);
2566 2542
2567 // Load the operands. 2543 // Load the operands.
2568 if (smi_operands) { 2544 if (smi_operands) {
2569 FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); 2545 FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2);
2570 } else { 2546 } else {
2571 FloatingPointHelper::LoadOperands(masm, 2547 // Load right operand to d7 or r2/r3.
2572 destination, 2548 if (right_type == BinaryOpIC::INT32) {
2573 heap_number_map, 2549 FloatingPointHelper::LoadNumberAsInt32Double(
2574 scratch1, 2550 masm, right, destination, d7, d8, r2, r3, heap_number_map,
2575 scratch2, 2551 scratch1, scratch2, s0, miss);
2576 not_numbers); 2552 } else {
2553 Label* fail = (right_type == BinaryOpIC::HEAP_NUMBER) ? miss
2554 : not_numbers;
2555 FloatingPointHelper::LoadNumber(
2556 masm, destination, right, d7, r2, r3, heap_number_map,
2557 scratch1, scratch2, fail);
2558 }
2559 // Load left operand to d6 or r0/r1. This keeps r0/r1 intact if it
2560 // jumps to |miss|.
2561 if (left_type == BinaryOpIC::INT32) {
2562 FloatingPointHelper::LoadNumberAsInt32Double(
2563 masm, left, destination, d6, d8, r0, r1, heap_number_map,
2564 scratch1, scratch2, s0, miss);
2565 } else {
2566 Label* fail = (left_type == BinaryOpIC::HEAP_NUMBER) ? miss
2567 : not_numbers;
2568 FloatingPointHelper::LoadNumber(
2569 masm, destination, left, d6, r0, r1, heap_number_map,
2570 scratch1, scratch2, fail);
2571 }
2577 } 2572 }
2578 2573
2579 // Calculate the result. 2574 // Calculate the result.
2580 if (destination == FloatingPointHelper::kVFPRegisters) { 2575 if (destination == FloatingPointHelper::kVFPRegisters) {
2581 // Using VFP registers: 2576 // Using VFP registers:
2582 // d6: Left value 2577 // d6: Left value
2583 // d7: Right value 2578 // d7: Right value
2584 CpuFeatures::Scope scope(VFP2); 2579 CpuFeatures::Scope scope(VFP2);
2585 switch (op_) { 2580 switch (op) {
2586 case Token::ADD: 2581 case Token::ADD:
2587 __ vadd(d5, d6, d7); 2582 __ vadd(d5, d6, d7);
2588 break; 2583 break;
2589 case Token::SUB: 2584 case Token::SUB:
2590 __ vsub(d5, d6, d7); 2585 __ vsub(d5, d6, d7);
2591 break; 2586 break;
2592 case Token::MUL: 2587 case Token::MUL:
2593 __ vmul(d5, d6, d7); 2588 __ vmul(d5, d6, d7);
2594 break; 2589 break;
2595 case Token::DIV: 2590 case Token::DIV:
2596 __ vdiv(d5, d6, d7); 2591 __ vdiv(d5, d6, d7);
2597 break; 2592 break;
2598 default: 2593 default:
2599 UNREACHABLE(); 2594 UNREACHABLE();
2600 } 2595 }
2601 2596
2602 __ sub(r0, result, Operand(kHeapObjectTag)); 2597 __ sub(r0, result, Operand(kHeapObjectTag));
2603 __ vstr(d5, r0, HeapNumber::kValueOffset); 2598 __ vstr(d5, r0, HeapNumber::kValueOffset);
2604 __ add(r0, r0, Operand(kHeapObjectTag)); 2599 __ add(r0, r0, Operand(kHeapObjectTag));
2605 __ Ret(); 2600 __ Ret();
2606 } else { 2601 } else {
2607 // Call the C function to handle the double operation. 2602 // Call the C function to handle the double operation.
2608 FloatingPointHelper::CallCCodeForDoubleOperation(masm, 2603 FloatingPointHelper::CallCCodeForDoubleOperation(masm,
2609 op_, 2604 op,
2610 result, 2605 result,
2611 scratch1); 2606 scratch1);
2612 if (FLAG_debug_code) { 2607 if (FLAG_debug_code) {
2613 __ stop("Unreachable code."); 2608 __ stop("Unreachable code.");
2614 } 2609 }
2615 } 2610 }
2616 break; 2611 break;
2617 } 2612 }
2618 case Token::BIT_OR: 2613 case Token::BIT_OR:
2619 case Token::BIT_XOR: 2614 case Token::BIT_XOR:
(...skipping 20 matching lines...) Expand all
2640 r2, 2635 r2,
2641 heap_number_map, 2636 heap_number_map,
2642 scratch1, 2637 scratch1,
2643 scratch2, 2638 scratch2,
2644 scratch3, 2639 scratch3,
2645 d0, 2640 d0,
2646 not_numbers); 2641 not_numbers);
2647 } 2642 }
2648 2643
2649 Label result_not_a_smi; 2644 Label result_not_a_smi;
2650 switch (op_) { 2645 switch (op) {
2651 case Token::BIT_OR: 2646 case Token::BIT_OR:
2652 __ orr(r2, r3, Operand(r2)); 2647 __ orr(r2, r3, Operand(r2));
2653 break; 2648 break;
2654 case Token::BIT_XOR: 2649 case Token::BIT_XOR:
2655 __ eor(r2, r3, Operand(r2)); 2650 __ eor(r2, r3, Operand(r2));
2656 break; 2651 break;
2657 case Token::BIT_AND: 2652 case Token::BIT_AND:
2658 __ and_(r2, r3, Operand(r2)); 2653 __ and_(r2, r3, Operand(r2));
2659 break; 2654 break;
2660 case Token::SAR: 2655 case Token::SAR:
(...skipping 30 matching lines...) Expand all
2691 __ SmiTag(r0, r2); 2686 __ SmiTag(r0, r2);
2692 __ Ret(); 2687 __ Ret();
2693 2688
2694 // Allocate new heap number for result. 2689 // Allocate new heap number for result.
2695 __ bind(&result_not_a_smi); 2690 __ bind(&result_not_a_smi);
2696 Register result = r5; 2691 Register result = r5;
2697 if (smi_operands) { 2692 if (smi_operands) {
2698 __ AllocateHeapNumber( 2693 __ AllocateHeapNumber(
2699 result, scratch1, scratch2, heap_number_map, gc_required); 2694 result, scratch1, scratch2, heap_number_map, gc_required);
2700 } else { 2695 } else {
2701 GenerateHeapResultAllocation( 2696 BinaryOpStub_GenerateHeapResultAllocation(
2702 masm, result, heap_number_map, scratch1, scratch2, gc_required); 2697 masm, result, heap_number_map, scratch1, scratch2, gc_required,
2698 mode);
2703 } 2699 }
2704 2700
2705 // r2: Answer as signed int32. 2701 // r2: Answer as signed int32.
2706 // r5: Heap number to write answer into. 2702 // r5: Heap number to write answer into.
2707 2703
2708 // Nothing can go wrong now, so move the heap number to r0, which is the 2704 // Nothing can go wrong now, so move the heap number to r0, which is the
2709 // result. 2705 // result.
2710 __ mov(r0, Operand(r5)); 2706 __ mov(r0, Operand(r5));
2711 2707
2712 if (CpuFeatures::IsSupported(VFP2)) { 2708 if (CpuFeatures::IsSupported(VFP2)) {
2713 // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As 2709 // Convert the int32 in r2 to the heap number in r0. r3 is corrupted. As
2714 // mentioned above SHR needs to always produce a positive result. 2710 // mentioned above SHR needs to always produce a positive result.
2715 CpuFeatures::Scope scope(VFP2); 2711 CpuFeatures::Scope scope(VFP2);
2716 __ vmov(s0, r2); 2712 __ vmov(s0, r2);
2717 if (op_ == Token::SHR) { 2713 if (op == Token::SHR) {
2718 __ vcvt_f64_u32(d0, s0); 2714 __ vcvt_f64_u32(d0, s0);
2719 } else { 2715 } else {
2720 __ vcvt_f64_s32(d0, s0); 2716 __ vcvt_f64_s32(d0, s0);
2721 } 2717 }
2722 __ sub(r3, r0, Operand(kHeapObjectTag)); 2718 __ sub(r3, r0, Operand(kHeapObjectTag));
2723 __ vstr(d0, r3, HeapNumber::kValueOffset); 2719 __ vstr(d0, r3, HeapNumber::kValueOffset);
2724 __ Ret(); 2720 __ Ret();
2725 } else { 2721 } else {
2726 // Tail call that writes the int32 in r2 to the heap number in r0, using 2722 // Tail call that writes the int32 in r2 to the heap number in r0, using
2727 // r3 as scratch. r0 is preserved and returned. 2723 // r3 as scratch. r0 is preserved and returned.
2728 WriteInt32ToHeapNumberStub stub(r2, r0, r3); 2724 WriteInt32ToHeapNumberStub stub(r2, r0, r3);
2729 __ TailCallStub(&stub); 2725 __ TailCallStub(&stub);
2730 } 2726 }
2731 break; 2727 break;
2732 } 2728 }
2733 default: 2729 default:
2734 UNREACHABLE(); 2730 UNREACHABLE();
2735 } 2731 }
2736 } 2732 }
2737 2733
2738 2734
2739 // Generate the smi code. If the operation on smis are successful this return is 2735 // Generate the smi code. If the operation on smis are successful this return is
2740 // generated. If the result is not a smi and heap number allocation is not 2736 // generated. If the result is not a smi and heap number allocation is not
2741 // requested the code falls through. If number allocation is requested but a 2737 // requested the code falls through. If number allocation is requested but a
2742 // heap number cannot be allocated the code jumps to the lable gc_required. 2738 // heap number cannot be allocated the code jumps to the label gc_required.
2743 void BinaryOpStub::GenerateSmiCode( 2739 void BinaryOpStub_GenerateSmiCode(
2744 MacroAssembler* masm, 2740 MacroAssembler* masm,
2745 Label* use_runtime, 2741 Label* use_runtime,
2746 Label* gc_required, 2742 Label* gc_required,
2747 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { 2743 Token::Value op,
2744 BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results,
2745 OverwriteMode mode) {
2748 Label not_smis; 2746 Label not_smis;
2749 2747
2750 Register left = r1; 2748 Register left = r1;
2751 Register right = r0; 2749 Register right = r0;
2752 Register scratch1 = r7; 2750 Register scratch1 = r7;
2753 2751
2754 // Perform combined smi check on both operands. 2752 // Perform combined smi check on both operands.
2755 __ orr(scratch1, left, Operand(right)); 2753 __ orr(scratch1, left, Operand(right));
2756 STATIC_ASSERT(kSmiTag == 0); 2754 STATIC_ASSERT(kSmiTag == 0);
2757 __ JumpIfNotSmi(scratch1, &not_smis); 2755 __ JumpIfNotSmi(scratch1, &not_smis);
2758 2756
2759 // If the smi-smi operation results in a smi return is generated. 2757 // If the smi-smi operation results in a smi return is generated.
2760 GenerateSmiSmiOperation(masm); 2758 BinaryOpStub_GenerateSmiSmiOperation(masm, op);
2761 2759
2762 // If heap number results are possible generate the result in an allocated 2760 // If heap number results are possible generate the result in an allocated
2763 // heap number. 2761 // heap number.
2764 if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { 2762 if (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) {
2765 GenerateFPOperation(masm, true, use_runtime, gc_required); 2763 BinaryOpStub_GenerateFPOperation(
2764 masm, BinaryOpIC::UNINITIALIZED, BinaryOpIC::UNINITIALIZED, true,
2765 use_runtime, gc_required, &not_smis, op, mode);
2766 } 2766 }
2767 __ bind(&not_smis); 2767 __ bind(&not_smis);
2768 } 2768 }
2769 2769
2770 2770
2771 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 2771 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
2772 Label not_smis, call_runtime; 2772 Label not_smis, call_runtime;
2773 2773
2774 if (result_type_ == BinaryOpIC::UNINITIALIZED || 2774 if (result_type_ == BinaryOpIC::UNINITIALIZED ||
2775 result_type_ == BinaryOpIC::SMI) { 2775 result_type_ == BinaryOpIC::SMI) {
2776 // Only allow smi results. 2776 // Only allow smi results.
2777 GenerateSmiCode(masm, &call_runtime, NULL, NO_HEAPNUMBER_RESULTS); 2777 BinaryOpStub_GenerateSmiCode(
2778 masm, &call_runtime, NULL, op_, NO_HEAPNUMBER_RESULTS, mode_);
2778 } else { 2779 } else {
2779 // Allow heap number result and don't make a transition if a heap number 2780 // Allow heap number result and don't make a transition if a heap number
2780 // cannot be allocated. 2781 // cannot be allocated.
2781 GenerateSmiCode(masm, 2782 BinaryOpStub_GenerateSmiCode(
2782 &call_runtime, 2783 masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS,
2783 &call_runtime, 2784 mode_);
2784 ALLOW_HEAPNUMBER_RESULTS);
2785 } 2785 }
2786 2786
2787 // Code falls through if the result is not returned as either a smi or heap 2787 // Code falls through if the result is not returned as either a smi or heap
2788 // number. 2788 // number.
2789 GenerateTypeTransition(masm); 2789 GenerateTypeTransition(masm);
2790 2790
2791 __ bind(&call_runtime); 2791 __ bind(&call_runtime);
2792 GenerateRegisterArgsPush(masm);
2792 GenerateCallRuntime(masm); 2793 GenerateCallRuntime(masm);
2793 } 2794 }
2794 2795
2795 2796
2796 void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
2797 ASSERT(operands_type_ == BinaryOpIC::STRING);
2798 ASSERT(op_ == Token::ADD);
2799 // Try to add arguments as strings, otherwise, transition to the generic
2800 // BinaryOpIC type.
2801 GenerateAddStrings(masm);
2802 GenerateTypeTransition(masm);
2803 }
2804
2805
2806 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { 2797 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) {
2807 Label call_runtime; 2798 Label call_runtime;
2808 ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); 2799 ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING);
2809 ASSERT(op_ == Token::ADD); 2800 ASSERT(op_ == Token::ADD);
2810 // If both arguments are strings, call the string add stub. 2801 // If both arguments are strings, call the string add stub.
2811 // Otherwise, do a transition. 2802 // Otherwise, do a transition.
2812 2803
2813 // Registers containing left and right operands respectively. 2804 // Registers containing left and right operands respectively.
2814 Register left = r1; 2805 Register left = r1;
2815 Register right = r0; 2806 Register right = r0;
2816 2807
2817 // Test if left operand is a string. 2808 // Test if left operand is a string.
2818 __ JumpIfSmi(left, &call_runtime); 2809 __ JumpIfSmi(left, &call_runtime);
2819 __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE); 2810 __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE);
2820 __ b(ge, &call_runtime); 2811 __ b(ge, &call_runtime);
2821 2812
2822 // Test if right operand is a string. 2813 // Test if right operand is a string.
2823 __ JumpIfSmi(right, &call_runtime); 2814 __ JumpIfSmi(right, &call_runtime);
2824 __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE); 2815 __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE);
2825 __ b(ge, &call_runtime); 2816 __ b(ge, &call_runtime);
2826 2817
2827 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); 2818 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB);
2828 GenerateRegisterArgsPush(masm); 2819 GenerateRegisterArgsPush(masm);
2829 __ TailCallStub(&string_add_stub); 2820 __ TailCallStub(&string_add_stub);
2830 2821
2831 __ bind(&call_runtime); 2822 __ bind(&call_runtime);
2832 GenerateTypeTransition(masm); 2823 GenerateTypeTransition(masm);
2833 } 2824 }
2834 2825
2835 2826
2836 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { 2827 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
2837 ASSERT(operands_type_ == BinaryOpIC::INT32); 2828 ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32);
2838 2829
2839 Register left = r1; 2830 Register left = r1;
2840 Register right = r0; 2831 Register right = r0;
2841 Register scratch1 = r7; 2832 Register scratch1 = r7;
2842 Register scratch2 = r9; 2833 Register scratch2 = r9;
2843 DwVfpRegister double_scratch = d0; 2834 DwVfpRegister double_scratch = d0;
2844 2835
2845 Register heap_number_result = no_reg; 2836 Register heap_number_result = no_reg;
2846 Register heap_number_map = r6; 2837 Register heap_number_map = r6;
2847 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); 2838 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2848 2839
2849 Label call_runtime; 2840 Label call_runtime;
2850 // Labels for type transition, used for wrong input or output types. 2841 // Labels for type transition, used for wrong input or output types.
2851 // Both label are currently actually bound to the same position. We use two 2842 // Both label are currently actually bound to the same position. We use two
2852 // different label to differentiate the cause leading to type transition. 2843 // different label to differentiate the cause leading to type transition.
2853 Label transition; 2844 Label transition;
2854 2845
2855 // Smi-smi fast case. 2846 // Smi-smi fast case.
2856 Label skip; 2847 Label skip;
2857 __ orr(scratch1, left, right); 2848 __ orr(scratch1, left, right);
2858 __ JumpIfNotSmi(scratch1, &skip); 2849 __ JumpIfNotSmi(scratch1, &skip);
2859 GenerateSmiSmiOperation(masm); 2850 BinaryOpStub_GenerateSmiSmiOperation(masm, op_);
2860 // Fall through if the result is not a smi. 2851 // Fall through if the result is not a smi.
2861 __ bind(&skip); 2852 __ bind(&skip);
2862 2853
2863 switch (op_) { 2854 switch (op_) {
2864 case Token::ADD: 2855 case Token::ADD:
2865 case Token::SUB: 2856 case Token::SUB:
2866 case Token::MUL: 2857 case Token::MUL:
2867 case Token::DIV: 2858 case Token::DIV:
2868 case Token::MOD: { 2859 case Token::MOD: {
2860 // It could be that only SMIs have been seen at either the left
2861 // or the right operand. For precise type feedback, patch the IC
2862 // again if this changes.
2863 if (left_type_ == BinaryOpIC::SMI) {
2864 __ JumpIfNotSmi(left, &transition);
2865 }
2866 if (right_type_ == BinaryOpIC::SMI) {
2867 __ JumpIfNotSmi(right, &transition);
2868 }
2869 // Load both operands and check that they are 32-bit integer. 2869 // Load both operands and check that they are 32-bit integer.
2870 // Jump to type transition if they are not. The registers r0 and r1 (right 2870 // Jump to type transition if they are not. The registers r0 and r1 (right
2871 // and left) are preserved for the runtime call. 2871 // and left) are preserved for the runtime call.
2872 FloatingPointHelper::Destination destination = 2872 FloatingPointHelper::Destination destination =
2873 (CpuFeatures::IsSupported(VFP2) && op_ != Token::MOD) 2873 (CpuFeatures::IsSupported(VFP2) && op_ != Token::MOD)
2874 ? FloatingPointHelper::kVFPRegisters 2874 ? FloatingPointHelper::kVFPRegisters
2875 : FloatingPointHelper::kCoreRegisters; 2875 : FloatingPointHelper::kCoreRegisters;
2876 2876
2877 FloatingPointHelper::LoadNumberAsInt32Double(masm, 2877 FloatingPointHelper::LoadNumberAsInt32Double(masm,
2878 right, 2878 right,
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
2957 // DIV just falls through to allocating a heap number. 2957 // DIV just falls through to allocating a heap number.
2958 } 2958 }
2959 2959
2960 __ bind(&return_heap_number); 2960 __ bind(&return_heap_number);
2961 // Return a heap number, or fall through to type transition or runtime 2961 // Return a heap number, or fall through to type transition or runtime
2962 // call if we can't. 2962 // call if we can't.
2963 if (result_type_ >= ((op_ == Token::DIV) ? BinaryOpIC::HEAP_NUMBER 2963 if (result_type_ >= ((op_ == Token::DIV) ? BinaryOpIC::HEAP_NUMBER
2964 : BinaryOpIC::INT32)) { 2964 : BinaryOpIC::INT32)) {
2965 // We are using vfp registers so r5 is available. 2965 // We are using vfp registers so r5 is available.
2966 heap_number_result = r5; 2966 heap_number_result = r5;
2967 GenerateHeapResultAllocation(masm, 2967 BinaryOpStub_GenerateHeapResultAllocation(masm,
2968 heap_number_result, 2968 heap_number_result,
2969 heap_number_map, 2969 heap_number_map,
2970 scratch1, 2970 scratch1,
2971 scratch2, 2971 scratch2,
2972 &call_runtime); 2972 &call_runtime,
2973 mode_);
2973 __ sub(r0, heap_number_result, Operand(kHeapObjectTag)); 2974 __ sub(r0, heap_number_result, Operand(kHeapObjectTag));
2974 __ vstr(d5, r0, HeapNumber::kValueOffset); 2975 __ vstr(d5, r0, HeapNumber::kValueOffset);
2975 __ mov(r0, heap_number_result); 2976 __ mov(r0, heap_number_result);
2976 __ Ret(); 2977 __ Ret();
2977 } 2978 }
2978 2979
2979 // A DIV operation expecting an integer result falls through 2980 // A DIV operation expecting an integer result falls through
2980 // to type transition. 2981 // to type transition.
2981 2982
2982 } else { 2983 } else {
2983 // We preserved r0 and r1 to be able to call runtime. 2984 // We preserved r0 and r1 to be able to call runtime.
2984 // Save the left value on the stack. 2985 // Save the left value on the stack.
2985 __ Push(r5, r4); 2986 __ Push(r5, r4);
2986 2987
2987 Label pop_and_call_runtime; 2988 Label pop_and_call_runtime;
2988 2989
2989 // Allocate a heap number to store the result. 2990 // Allocate a heap number to store the result.
2990 heap_number_result = r5; 2991 heap_number_result = r5;
2991 GenerateHeapResultAllocation(masm, 2992 BinaryOpStub_GenerateHeapResultAllocation(masm,
2992 heap_number_result, 2993 heap_number_result,
2993 heap_number_map, 2994 heap_number_map,
2994 scratch1, 2995 scratch1,
2995 scratch2, 2996 scratch2,
2996 &pop_and_call_runtime); 2997 &pop_and_call_runtime,
2998 mode_);
2997 2999
2998 // Load the left value from the value saved on the stack. 3000 // Load the left value from the value saved on the stack.
2999 __ Pop(r1, r0); 3001 __ Pop(r1, r0);
3000 3002
3001 // Call the C function to handle the double operation. 3003 // Call the C function to handle the double operation.
3002 FloatingPointHelper::CallCCodeForDoubleOperation( 3004 FloatingPointHelper::CallCCodeForDoubleOperation(
3003 masm, op_, heap_number_result, scratch1); 3005 masm, op_, heap_number_result, scratch1);
3004 if (FLAG_debug_code) { 3006 if (FLAG_debug_code) {
3005 __ stop("Unreachable code."); 3007 __ stop("Unreachable code.");
3006 } 3008 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
3091 // Check if the result fits in a smi. 3093 // Check if the result fits in a smi.
3092 __ add(scratch1, r2, Operand(0x40000000), SetCC); 3094 __ add(scratch1, r2, Operand(0x40000000), SetCC);
3093 // If not try to return a heap number. (We know the result is an int32.) 3095 // If not try to return a heap number. (We know the result is an int32.)
3094 __ b(mi, &return_heap_number); 3096 __ b(mi, &return_heap_number);
3095 // Tag the result and return. 3097 // Tag the result and return.
3096 __ SmiTag(r0, r2); 3098 __ SmiTag(r0, r2);
3097 __ Ret(); 3099 __ Ret();
3098 3100
3099 __ bind(&return_heap_number); 3101 __ bind(&return_heap_number);
3100 heap_number_result = r5; 3102 heap_number_result = r5;
3101 GenerateHeapResultAllocation(masm, 3103 BinaryOpStub_GenerateHeapResultAllocation(masm,
3102 heap_number_result, 3104 heap_number_result,
3103 heap_number_map, 3105 heap_number_map,
3104 scratch1, 3106 scratch1,
3105 scratch2, 3107 scratch2,
3106 &call_runtime); 3108 &call_runtime,
3109 mode_);
3107 3110
3108 if (CpuFeatures::IsSupported(VFP2)) { 3111 if (CpuFeatures::IsSupported(VFP2)) {
3109 CpuFeatures::Scope scope(VFP2); 3112 CpuFeatures::Scope scope(VFP2);
3110 if (op_ != Token::SHR) { 3113 if (op_ != Token::SHR) {
3111 // Convert the result to a floating point value. 3114 // Convert the result to a floating point value.
3112 __ vmov(double_scratch.low(), r2); 3115 __ vmov(double_scratch.low(), r2);
3113 __ vcvt_f64_s32(double_scratch, double_scratch.low()); 3116 __ vcvt_f64_s32(double_scratch, double_scratch.low());
3114 } else { 3117 } else {
3115 // The result must be interpreted as an unsigned 32-bit integer. 3118 // The result must be interpreted as an unsigned 32-bit integer.
3116 __ vmov(double_scratch.low(), r2); 3119 __ vmov(double_scratch.low(), r2);
(...skipping 23 matching lines...) Expand all
3140 // We never expect DIV to yield an integer result, so we always generate 3143 // We never expect DIV to yield an integer result, so we always generate
3141 // type transition code for DIV operations expecting an integer result: the 3144 // type transition code for DIV operations expecting an integer result: the
3142 // code will fall through to this type transition. 3145 // code will fall through to this type transition.
3143 if (transition.is_linked() || 3146 if (transition.is_linked() ||
3144 ((op_ == Token::DIV) && (result_type_ <= BinaryOpIC::INT32))) { 3147 ((op_ == Token::DIV) && (result_type_ <= BinaryOpIC::INT32))) {
3145 __ bind(&transition); 3148 __ bind(&transition);
3146 GenerateTypeTransition(masm); 3149 GenerateTypeTransition(masm);
3147 } 3150 }
3148 3151
3149 __ bind(&call_runtime); 3152 __ bind(&call_runtime);
3153 GenerateRegisterArgsPush(masm);
3150 GenerateCallRuntime(masm); 3154 GenerateCallRuntime(masm);
3151 } 3155 }
3152 3156
3153 3157
3154 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { 3158 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) {
3155 Label call_runtime; 3159 Label call_runtime;
3156 3160
3157 if (op_ == Token::ADD) { 3161 if (op_ == Token::ADD) {
3158 // Handle string addition here, because it is the only operation 3162 // Handle string addition here, because it is the only operation
3159 // that does not do a ToNumber conversion on the operands. 3163 // that does not do a ToNumber conversion on the operands.
(...skipping 18 matching lines...) Expand all
3178 } else { 3182 } else {
3179 __ LoadRoot(r0, Heap::kNanValueRootIndex); 3183 __ LoadRoot(r0, Heap::kNanValueRootIndex);
3180 } 3184 }
3181 __ bind(&done); 3185 __ bind(&done);
3182 3186
3183 GenerateHeapNumberStub(masm); 3187 GenerateHeapNumberStub(masm);
3184 } 3188 }
3185 3189
3186 3190
3187 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 3191 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
3188 Label call_runtime; 3192 Label call_runtime, transition;
3189 GenerateFPOperation(masm, false, &call_runtime, &call_runtime); 3193 BinaryOpStub_GenerateFPOperation(
3194 masm, left_type_, right_type_, false,
3195 &transition, &call_runtime, &transition, op_, mode_);
3196
3197 __ bind(&transition);
3198 GenerateTypeTransition(masm);
3190 3199
3191 __ bind(&call_runtime); 3200 __ bind(&call_runtime);
3201 GenerateRegisterArgsPush(masm);
3192 GenerateCallRuntime(masm); 3202 GenerateCallRuntime(masm);
3193 } 3203 }
3194 3204
3195 3205
3196 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { 3206 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
3197 Label call_runtime, call_string_add_or_runtime; 3207 Label call_runtime, call_string_add_or_runtime, transition;
3198 3208
3199 GenerateSmiCode(masm, &call_runtime, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 3209 BinaryOpStub_GenerateSmiCode(
3210 masm, &call_runtime, &call_runtime, op_, ALLOW_HEAPNUMBER_RESULTS, mode_);
3200 3211
3201 GenerateFPOperation(masm, false, &call_string_add_or_runtime, &call_runtime); 3212 BinaryOpStub_GenerateFPOperation(
3213 masm, left_type_, right_type_, false,
3214 &call_string_add_or_runtime, &call_runtime, &transition, op_, mode_);
3215
3216 __ bind(&transition);
3217 GenerateTypeTransition(masm);
3202 3218
3203 __ bind(&call_string_add_or_runtime); 3219 __ bind(&call_string_add_or_runtime);
3204 if (op_ == Token::ADD) { 3220 if (op_ == Token::ADD) {
3205 GenerateAddStrings(masm); 3221 GenerateAddStrings(masm);
3206 } 3222 }
3207 3223
3208 __ bind(&call_runtime); 3224 __ bind(&call_runtime);
3225 GenerateRegisterArgsPush(masm);
3209 GenerateCallRuntime(masm); 3226 GenerateCallRuntime(masm);
3210 } 3227 }
3211 3228
3212 3229
3213 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { 3230 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) {
3214 ASSERT(op_ == Token::ADD); 3231 ASSERT(op_ == Token::ADD);
3215 Label left_not_string, call_runtime; 3232 Label left_not_string, call_runtime;
3216 3233
3217 Register left = r1; 3234 Register left = r1;
3218 Register right = r0; 3235 Register right = r0;
(...skipping 15 matching lines...) Expand all
3234 3251
3235 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); 3252 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB);
3236 GenerateRegisterArgsPush(masm); 3253 GenerateRegisterArgsPush(masm);
3237 __ TailCallStub(&string_add_right_stub); 3254 __ TailCallStub(&string_add_right_stub);
3238 3255
3239 // At least one argument is not a string. 3256 // At least one argument is not a string.
3240 __ bind(&call_runtime); 3257 __ bind(&call_runtime);
3241 } 3258 }
3242 3259
3243 3260
3244 void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) { 3261 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm,
3245 GenerateRegisterArgsPush(masm); 3262 Register result,
3246 switch (op_) { 3263 Register heap_number_map,
3247 case Token::ADD: 3264 Register scratch1,
3248 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 3265 Register scratch2,
3249 break; 3266 Label* gc_required,
3250 case Token::SUB: 3267 OverwriteMode mode) {
3251 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION);
3252 break;
3253 case Token::MUL:
3254 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION);
3255 break;
3256 case Token::DIV:
3257 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION);
3258 break;
3259 case Token::MOD:
3260 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION);
3261 break;
3262 case Token::BIT_OR:
3263 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION);
3264 break;
3265 case Token::BIT_AND:
3266 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION);
3267 break;
3268 case Token::BIT_XOR:
3269 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION);
3270 break;
3271 case Token::SAR:
3272 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION);
3273 break;
3274 case Token::SHR:
3275 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION);
3276 break;
3277 case Token::SHL:
3278 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION);
3279 break;
3280 default:
3281 UNREACHABLE();
3282 }
3283 }
3284
3285
3286 void BinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm,
3287 Register result,
3288 Register heap_number_map,
3289 Register scratch1,
3290 Register scratch2,
3291 Label* gc_required) {
3292 // Code below will scratch result if allocation fails. To keep both arguments 3268 // Code below will scratch result if allocation fails. To keep both arguments
3293 // intact for the runtime call result cannot be one of these. 3269 // intact for the runtime call result cannot be one of these.
3294 ASSERT(!result.is(r0) && !result.is(r1)); 3270 ASSERT(!result.is(r0) && !result.is(r1));
3295 3271
3296 if (mode_ == OVERWRITE_LEFT || mode_ == OVERWRITE_RIGHT) { 3272 if (mode == OVERWRITE_LEFT || mode == OVERWRITE_RIGHT) {
3297 Label skip_allocation, allocated; 3273 Label skip_allocation, allocated;
3298 Register overwritable_operand = mode_ == OVERWRITE_LEFT ? r1 : r0; 3274 Register overwritable_operand = mode == OVERWRITE_LEFT ? r1 : r0;
3299 // If the overwritable operand is already an object, we skip the 3275 // If the overwritable operand is already an object, we skip the
3300 // allocation of a heap number. 3276 // allocation of a heap number.
3301 __ JumpIfNotSmi(overwritable_operand, &skip_allocation); 3277 __ JumpIfNotSmi(overwritable_operand, &skip_allocation);
3302 // Allocate a heap number for the result. 3278 // Allocate a heap number for the result.
3303 __ AllocateHeapNumber( 3279 __ AllocateHeapNumber(
3304 result, scratch1, scratch2, heap_number_map, gc_required); 3280 result, scratch1, scratch2, heap_number_map, gc_required);
3305 __ b(&allocated); 3281 __ b(&allocated);
3306 __ bind(&skip_allocation); 3282 __ bind(&skip_allocation);
3307 // Use object holding the overwritable operand for result. 3283 // Use object holding the overwritable operand for result.
3308 __ mov(result, Operand(overwritable_operand)); 3284 __ mov(result, Operand(overwritable_operand));
3309 __ bind(&allocated); 3285 __ bind(&allocated);
3310 } else { 3286 } else {
3311 ASSERT(mode_ == NO_OVERWRITE); 3287 ASSERT(mode == NO_OVERWRITE);
3312 __ AllocateHeapNumber( 3288 __ AllocateHeapNumber(
3313 result, scratch1, scratch2, heap_number_map, gc_required); 3289 result, scratch1, scratch2, heap_number_map, gc_required);
3314 } 3290 }
3315 } 3291 }
3316 3292
3317 3293
3318 void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { 3294 void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) {
3319 __ Push(r1, r0); 3295 __ Push(r1, r0);
3320 } 3296 }
3321 3297
(...skipping 2096 matching lines...) Expand 10 before | Expand all | Expand 10 after
5418 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 5394 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
5419 __ bind(&do_call); 5395 __ bind(&do_call);
5420 // Set expected number of arguments to zero (not changing r0). 5396 // Set expected number of arguments to zero (not changing r0).
5421 __ mov(r2, Operand(0, RelocInfo::NONE)); 5397 __ mov(r2, Operand(0, RelocInfo::NONE));
5422 __ SetCallKind(r5, CALL_AS_METHOD); 5398 __ SetCallKind(r5, CALL_AS_METHOD);
5423 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 5399 __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
5424 RelocInfo::CODE_TARGET); 5400 RelocInfo::CODE_TARGET);
5425 } 5401 }
5426 5402
5427 5403
5428 // Unfortunately you have to run without snapshots to see most of these
5429 // names in the profile since most compare stubs end up in the snapshot.
5430 void CompareStub::PrintName(StringStream* stream) {
5431 ASSERT((lhs_.is(r0) && rhs_.is(r1)) ||
5432 (lhs_.is(r1) && rhs_.is(r0)));
5433 const char* cc_name;
5434 switch (cc_) {
5435 case lt: cc_name = "LT"; break;
5436 case gt: cc_name = "GT"; break;
5437 case le: cc_name = "LE"; break;
5438 case ge: cc_name = "GE"; break;
5439 case eq: cc_name = "EQ"; break;
5440 case ne: cc_name = "NE"; break;
5441 default: cc_name = "UnknownCondition"; break;
5442 }
5443 bool is_equality = cc_ == eq || cc_ == ne;
5444 stream->Add("CompareStub_%s", cc_name);
5445 stream->Add(lhs_.is(r0) ? "_r0" : "_r1");
5446 stream->Add(rhs_.is(r0) ? "_r0" : "_r1");
5447 if (strict_ && is_equality) stream->Add("_STRICT");
5448 if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN");
5449 if (!include_number_compare_) stream->Add("_NO_NUMBER");
5450 if (!include_smi_compare_) stream->Add("_NO_SMI");
5451 }
5452
5453
5454 int CompareStub::MinorKey() {
5455 // Encode the three parameters in a unique 16 bit value. To avoid duplicate
5456 // stubs the never NaN NaN condition is only taken into account if the
5457 // condition is equals.
5458 ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 12));
5459 ASSERT((lhs_.is(r0) && rhs_.is(r1)) ||
5460 (lhs_.is(r1) && rhs_.is(r0)));
5461 return ConditionField::encode(static_cast<unsigned>(cc_) >> 28)
5462 | RegisterField::encode(lhs_.is(r0))
5463 | StrictField::encode(strict_)
5464 | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false)
5465 | IncludeNumberCompareField::encode(include_number_compare_)
5466 | IncludeSmiCompareField::encode(include_smi_compare_);
5467 }
5468
5469
5470 // StringCharCodeAtGenerator 5404 // StringCharCodeAtGenerator
5471 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { 5405 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
5472 Label flat_string; 5406 Label flat_string;
5473 Label ascii_string; 5407 Label ascii_string;
5474 Label got_char_code; 5408 Label got_char_code;
5475 Label sliced_string; 5409 Label sliced_string;
5476 5410
5477 // If the receiver is a smi trigger the non-string case. 5411 // If the receiver is a smi trigger the non-string case.
5478 __ JumpIfSmi(object_, receiver_not_string_); 5412 __ JumpIfSmi(object_, receiver_not_string_);
5479 5413
(...skipping 1181 matching lines...) Expand 10 before | Expand all | Expand 10 after
6661 Operand(1 << Map::kStringWrapperSafeForDefaultValueOf)); 6595 Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
6662 __ b(ne, slow); 6596 __ b(ne, slow);
6663 __ ldr(arg, FieldMemOperand(arg, JSValue::kValueOffset)); 6597 __ ldr(arg, FieldMemOperand(arg, JSValue::kValueOffset));
6664 __ str(arg, MemOperand(sp, stack_offset)); 6598 __ str(arg, MemOperand(sp, stack_offset));
6665 6599
6666 __ bind(&done); 6600 __ bind(&done);
6667 } 6601 }
6668 6602
6669 6603
6670 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { 6604 void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
6671 ASSERT(state_ == CompareIC::SMIS); 6605 ASSERT(state_ == CompareIC::SMI);
6672 Label miss; 6606 Label miss;
6673 __ orr(r2, r1, r0); 6607 __ orr(r2, r1, r0);
6674 __ JumpIfNotSmi(r2, &miss); 6608 __ JumpIfNotSmi(r2, &miss);
6675 6609
6676 if (GetCondition() == eq) { 6610 if (GetCondition() == eq) {
6677 // For equality we do not care about the sign of the result. 6611 // For equality we do not care about the sign of the result.
6678 __ sub(r0, r0, r1, SetCC); 6612 __ sub(r0, r0, r1, SetCC);
6679 } else { 6613 } else {
6680 // Untag before subtracting to avoid handling overflow. 6614 // Untag before subtracting to avoid handling overflow.
6681 __ SmiUntag(r1); 6615 __ SmiUntag(r1);
6682 __ sub(r0, r1, SmiUntagOperand(r0)); 6616 __ sub(r0, r1, SmiUntagOperand(r0));
6683 } 6617 }
6684 __ Ret(); 6618 __ Ret();
6685 6619
6686 __ bind(&miss); 6620 __ bind(&miss);
6687 GenerateMiss(masm); 6621 GenerateMiss(masm);
6688 } 6622 }
6689 6623
6690 6624
6691 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { 6625 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
6692 ASSERT(state_ == CompareIC::HEAP_NUMBERS); 6626 ASSERT(state_ == CompareIC::HEAP_NUMBER);
6693 6627
6694 Label generic_stub; 6628 Label generic_stub;
6695 Label unordered, maybe_undefined1, maybe_undefined2; 6629 Label unordered, maybe_undefined1, maybe_undefined2;
6696 Label miss; 6630 Label miss;
6697 __ and_(r2, r1, Operand(r0));
6698 __ JumpIfSmi(r2, &generic_stub);
6699 6631
6700 __ CompareObjectType(r0, r2, r2, HEAP_NUMBER_TYPE); 6632 if (left_ == CompareIC::SMI) {
6701 __ b(ne, &maybe_undefined1); 6633 __ JumpIfNotSmi(r1, &miss);
6702 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE); 6634 }
6703 __ b(ne, &maybe_undefined2); 6635 if (right_ == CompareIC::SMI) {
6636 __ JumpIfNotSmi(r0, &miss);
6637 }
6704 6638
6705 // Inlining the double comparison and falling back to the general compare 6639 // Inlining the double comparison and falling back to the general compare
6706 // stub if NaN is involved or VFP3 is unsupported. 6640 // stub if NaN is involved or VFP2 is unsupported.
6707 if (CpuFeatures::IsSupported(VFP2)) { 6641 if (CpuFeatures::IsSupported(VFP2)) {
6708 CpuFeatures::Scope scope(VFP2); 6642 CpuFeatures::Scope scope(VFP2);
6709 6643
6710 // Load left and right operand 6644 // Load left and right operand.
6645 Label done, left, left_smi, right_smi;
6646 __ JumpIfSmi(r0, &right_smi);
6647 __ CheckMap(r0, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined1,
6648 DONT_DO_SMI_CHECK);
6649 __ sub(r2, r0, Operand(kHeapObjectTag));
6650 __ vldr(d1, r2, HeapNumber::kValueOffset);
6651 __ b(&left);
6652 __ bind(&right_smi);
6653 __ SmiUntag(r2, r0); // Can't clobber r0 yet.
6654 SwVfpRegister single_scratch = d2.low();
6655 __ vmov(single_scratch, r2);
6656 __ vcvt_f64_s32(d1, single_scratch);
6657
6658 __ bind(&left);
6659 __ JumpIfSmi(r1, &left_smi);
6660 __ CheckMap(r1, r2, Heap::kHeapNumberMapRootIndex, &maybe_undefined2,
6661 DONT_DO_SMI_CHECK);
6711 __ sub(r2, r1, Operand(kHeapObjectTag)); 6662 __ sub(r2, r1, Operand(kHeapObjectTag));
6712 __ vldr(d0, r2, HeapNumber::kValueOffset); 6663 __ vldr(d0, r2, HeapNumber::kValueOffset);
6713 __ sub(r2, r0, Operand(kHeapObjectTag)); 6664 __ b(&done);
6714 __ vldr(d1, r2, HeapNumber::kValueOffset); 6665 __ bind(&left_smi);
6666 __ SmiUntag(r2, r1); // Can't clobber r1 yet.
6667 single_scratch = d3.low();
6668 __ vmov(single_scratch, r2);
6669 __ vcvt_f64_s32(d0, single_scratch);
6715 6670
6716 // Compare operands 6671 __ bind(&done);
6672 // Compare operands.
6717 __ VFPCompareAndSetFlags(d0, d1); 6673 __ VFPCompareAndSetFlags(d0, d1);
6718 6674
6719 // Don't base result on status bits when a NaN is involved. 6675 // Don't base result on status bits when a NaN is involved.
6720 __ b(vs, &unordered); 6676 __ b(vs, &unordered);
6721 6677
6722 // Return a result of -1, 0, or 1, based on status bits. 6678 // Return a result of -1, 0, or 1, based on status bits.
6723 __ mov(r0, Operand(EQUAL), LeaveCC, eq); 6679 __ mov(r0, Operand(EQUAL), LeaveCC, eq);
6724 __ mov(r0, Operand(LESS), LeaveCC, lt); 6680 __ mov(r0, Operand(LESS), LeaveCC, lt);
6725 __ mov(r0, Operand(GREATER), LeaveCC, gt); 6681 __ mov(r0, Operand(GREATER), LeaveCC, gt);
6726 __ Ret(); 6682 __ Ret();
6727 } 6683 }
6728 6684
6729 __ bind(&unordered); 6685 __ bind(&unordered);
6730 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
6731 __ bind(&generic_stub); 6686 __ bind(&generic_stub);
6687 ICCompareStub stub(op_, CompareIC::GENERIC, CompareIC::GENERIC,
6688 CompareIC::GENERIC);
6732 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET); 6689 __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
6733 6690
6734 __ bind(&maybe_undefined1); 6691 __ bind(&maybe_undefined1);
6735 if (Token::IsOrderedRelationalCompareOp(op_)) { 6692 if (Token::IsOrderedRelationalCompareOp(op_)) {
6736 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex); 6693 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
6737 __ b(ne, &miss); 6694 __ b(ne, &miss);
6695 __ JumpIfSmi(r1, &unordered);
6738 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE); 6696 __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
6739 __ b(ne, &maybe_undefined2); 6697 __ b(ne, &maybe_undefined2);
6740 __ jmp(&unordered); 6698 __ jmp(&unordered);
6741 } 6699 }
6742 6700
6743 __ bind(&maybe_undefined2); 6701 __ bind(&maybe_undefined2);
6744 if (Token::IsOrderedRelationalCompareOp(op_)) { 6702 if (Token::IsOrderedRelationalCompareOp(op_)) {
6745 __ CompareRoot(r1, Heap::kUndefinedValueRootIndex); 6703 __ CompareRoot(r1, Heap::kUndefinedValueRootIndex);
6746 __ b(eq, &unordered); 6704 __ b(eq, &unordered);
6747 } 6705 }
6748 6706
6749 __ bind(&miss); 6707 __ bind(&miss);
6750 GenerateMiss(masm); 6708 GenerateMiss(masm);
6751 } 6709 }
6752 6710
6753 6711
6754 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { 6712 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) {
6755 ASSERT(state_ == CompareIC::SYMBOLS); 6713 ASSERT(state_ == CompareIC::SYMBOL);
6756 Label miss; 6714 Label miss;
6757 6715
6758 // Registers containing left and right operands respectively. 6716 // Registers containing left and right operands respectively.
6759 Register left = r1; 6717 Register left = r1;
6760 Register right = r0; 6718 Register right = r0;
6761 Register tmp1 = r2; 6719 Register tmp1 = r2;
6762 Register tmp2 = r3; 6720 Register tmp2 = r3;
6763 6721
6764 // Check that both operands are heap objects. 6722 // Check that both operands are heap objects.
6765 __ JumpIfEitherSmi(left, right, &miss); 6723 __ JumpIfEitherSmi(left, right, &miss);
(...skipping 17 matching lines...) Expand all
6783 STATIC_ASSERT(kSmiTag == 0); 6741 STATIC_ASSERT(kSmiTag == 0);
6784 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); 6742 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq);
6785 __ Ret(); 6743 __ Ret();
6786 6744
6787 __ bind(&miss); 6745 __ bind(&miss);
6788 GenerateMiss(masm); 6746 GenerateMiss(masm);
6789 } 6747 }
6790 6748
6791 6749
6792 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { 6750 void ICCompareStub::GenerateStrings(MacroAssembler* masm) {
6793 ASSERT(state_ == CompareIC::STRINGS); 6751 ASSERT(state_ == CompareIC::STRING);
6794 Label miss; 6752 Label miss;
6795 6753
6796 bool equality = Token::IsEqualityOp(op_); 6754 bool equality = Token::IsEqualityOp(op_);
6797 6755
6798 // Registers containing left and right operands respectively. 6756 // Registers containing left and right operands respectively.
6799 Register left = r1; 6757 Register left = r1;
6800 Register right = r0; 6758 Register right = r0;
6801 Register tmp1 = r2; 6759 Register tmp1 = r2;
6802 Register tmp2 = r3; 6760 Register tmp2 = r3;
6803 Register tmp3 = r4; 6761 Register tmp3 = r4;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
6861 } else { 6819 } else {
6862 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 6820 __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
6863 } 6821 }
6864 6822
6865 __ bind(&miss); 6823 __ bind(&miss);
6866 GenerateMiss(masm); 6824 GenerateMiss(masm);
6867 } 6825 }
6868 6826
6869 6827
6870 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { 6828 void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
6871 ASSERT(state_ == CompareIC::OBJECTS); 6829 ASSERT(state_ == CompareIC::OBJECT);
6872 Label miss; 6830 Label miss;
6873 __ and_(r2, r1, Operand(r0)); 6831 __ and_(r2, r1, Operand(r0));
6874 __ JumpIfSmi(r2, &miss); 6832 __ JumpIfSmi(r2, &miss);
6875 6833
6876 __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE); 6834 __ CompareObjectType(r0, r2, r2, JS_OBJECT_TYPE);
6877 __ b(ne, &miss); 6835 __ b(ne, &miss);
6878 __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE); 6836 __ CompareObjectType(r1, r2, r2, JS_OBJECT_TYPE);
6879 __ b(ne, &miss); 6837 __ b(ne, &miss);
6880 6838
6881 ASSERT(GetCondition() == eq); 6839 ASSERT(GetCondition() == eq);
(...skipping 747 matching lines...) Expand 10 before | Expand all | Expand 10 after
7629 7587
7630 __ Pop(lr, r5, r1); 7588 __ Pop(lr, r5, r1);
7631 __ Ret(); 7589 __ Ret();
7632 } 7590 }
7633 7591
7634 #undef __ 7592 #undef __
7635 7593
7636 } } // namespace v8::internal 7594 } } // namespace v8::internal
7637 7595
7638 #endif // V8_TARGET_ARCH_ARM 7596 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « src/arm/code-stubs-arm.h ('k') | src/arm/full-codegen-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698