OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 820 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
831 | 831 |
832 // Push the current return address before the C call. Return will be | 832 // Push the current return address before the C call. Return will be |
833 // through pop(pc) below. | 833 // through pop(pc) below. |
834 __ push(lr); | 834 __ push(lr); |
835 __ PrepareCallCFunction(0, 2, scratch); | 835 __ PrepareCallCFunction(0, 2, scratch); |
836 if (masm->use_eabi_hardfloat()) { | 836 if (masm->use_eabi_hardfloat()) { |
837 CpuFeatures::Scope scope(VFP3); | 837 CpuFeatures::Scope scope(VFP3); |
838 __ vmov(d0, r0, r1); | 838 __ vmov(d0, r0, r1); |
839 __ vmov(d1, r2, r3); | 839 __ vmov(d1, r2, r3); |
840 } | 840 } |
841 // Call C routine that may not cause GC or other trouble. | 841 { |
842 __ CallCFunction(ExternalReference::double_fp_operation(op, masm->isolate()), | 842 AllowExternalCallThatCantCauseGC scope(masm); |
843 0, 2); | 843 __ CallCFunction( |
| 844 ExternalReference::double_fp_operation(op, masm->isolate()), 0, 2); |
| 845 } |
844 // Store answer in the overwritable heap number. Double returned in | 846 // Store answer in the overwritable heap number. Double returned in |
845 // registers r0 and r1 or in d0. | 847 // registers r0 and r1 or in d0. |
846 if (masm->use_eabi_hardfloat()) { | 848 if (masm->use_eabi_hardfloat()) { |
847 CpuFeatures::Scope scope(VFP3); | 849 CpuFeatures::Scope scope(VFP3); |
848 __ vstr(d0, | 850 __ vstr(d0, |
849 FieldMemOperand(heap_number_result, HeapNumber::kValueOffset)); | 851 FieldMemOperand(heap_number_result, HeapNumber::kValueOffset)); |
850 } else { | 852 } else { |
851 __ Strd(r0, r1, FieldMemOperand(heap_number_result, | 853 __ Strd(r0, r1, FieldMemOperand(heap_number_result, |
852 HeapNumber::kValueOffset)); | 854 HeapNumber::kValueOffset)); |
853 } | 855 } |
854 // Place heap_number_result in r0 and return to the pushed return address. | 856 // Place heap_number_result in r0 and return to the pushed return address. |
855 __ mov(r0, Operand(heap_number_result)); | 857 __ mov(r0, Operand(heap_number_result)); |
856 __ pop(pc); | 858 __ pop(pc); |
857 } | 859 } |
858 | 860 |
859 | 861 |
| 862 bool WriteInt32ToHeapNumberStub::IsPregenerated() { |
| 863 // These variants are compiled ahead of time. See next method. |
| 864 if (the_int_.is(r1) && the_heap_number_.is(r0) && scratch_.is(r2)) { |
| 865 return true; |
| 866 } |
| 867 if (the_int_.is(r2) && the_heap_number_.is(r0) && scratch_.is(r3)) { |
| 868 return true; |
| 869 } |
| 870 // Other register combinations are generated as and when they are needed, |
| 871 // so it is unsafe to call them from stubs (we can't generate a stub while |
| 872 // we are generating a stub). |
| 873 return false; |
| 874 } |
| 875 |
| 876 |
| 877 void WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime() { |
| 878 WriteInt32ToHeapNumberStub stub1(r1, r0, r2); |
| 879 WriteInt32ToHeapNumberStub stub2(r2, r0, r3); |
| 880 stub1.GetCode()->set_is_pregenerated(true); |
| 881 stub2.GetCode()->set_is_pregenerated(true); |
| 882 } |
| 883 |
| 884 |
860 // See comment for class. | 885 // See comment for class. |
861 void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { | 886 void WriteInt32ToHeapNumberStub::Generate(MacroAssembler* masm) { |
862 Label max_negative_int; | 887 Label max_negative_int; |
863 // the_int_ has the answer which is a signed int32 but not a Smi. | 888 // the_int_ has the answer which is a signed int32 but not a Smi. |
864 // We test for the special value that has a different exponent. This test | 889 // We test for the special value that has a different exponent. This test |
865 // has the neat side effect of setting the flags according to the sign. | 890 // has the neat side effect of setting the flags according to the sign. |
866 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u); | 891 STATIC_ASSERT(HeapNumber::kSignMask == 0x80000000u); |
867 __ cmp(the_int_, Operand(0x80000000u)); | 892 __ cmp(the_int_, Operand(0x80000000u)); |
868 __ b(eq, &max_negative_int); | 893 __ b(eq, &max_negative_int); |
869 // Set up the correct exponent in scratch_. All non-Smi int32s have the same. | 894 // Set up the correct exponent in scratch_. All non-Smi int32s have the same. |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1190 } else { | 1215 } else { |
1191 // Call a native function to do a comparison between two non-NaNs. | 1216 // Call a native function to do a comparison between two non-NaNs. |
1192 // Call C routine that may not cause GC or other trouble. | 1217 // Call C routine that may not cause GC or other trouble. |
1193 __ push(lr); | 1218 __ push(lr); |
1194 __ PrepareCallCFunction(0, 2, r5); | 1219 __ PrepareCallCFunction(0, 2, r5); |
1195 if (masm->use_eabi_hardfloat()) { | 1220 if (masm->use_eabi_hardfloat()) { |
1196 CpuFeatures::Scope scope(VFP3); | 1221 CpuFeatures::Scope scope(VFP3); |
1197 __ vmov(d0, r0, r1); | 1222 __ vmov(d0, r0, r1); |
1198 __ vmov(d1, r2, r3); | 1223 __ vmov(d1, r2, r3); |
1199 } | 1224 } |
| 1225 |
| 1226 AllowExternalCallThatCantCauseGC scope(masm); |
1200 __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()), | 1227 __ CallCFunction(ExternalReference::compare_doubles(masm->isolate()), |
1201 0, 2); | 1228 0, 2); |
1202 __ pop(pc); // Return. | 1229 __ pop(pc); // Return. |
1203 } | 1230 } |
1204 } | 1231 } |
1205 | 1232 |
1206 | 1233 |
1207 // See comment at call site. | 1234 // See comment at call site. |
1208 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 1235 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
1209 Register lhs, | 1236 Register lhs, |
1210 Register rhs) { | 1237 Register rhs) { |
1211 ASSERT((lhs.is(r0) && rhs.is(r1)) || | 1238 ASSERT((lhs.is(r0) && rhs.is(r1)) || |
1212 (lhs.is(r1) && rhs.is(r0))); | 1239 (lhs.is(r1) && rhs.is(r0))); |
1213 | 1240 |
1214 // If either operand is a JS object or an oddball value, then they are | 1241 // If either operand is a JS object or an oddball value, then they are |
1215 // not equal since their pointers are different. | 1242 // not equal since their pointers are different. |
1216 // There is no test for undetectability in strict equality. | 1243 // There is no test for undetectability in strict equality. |
1217 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); | 1244 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); |
1218 Label first_non_object; | 1245 Label first_non_object; |
1219 // Get the type of the first operand into r2 and compare it with | 1246 // Get the type of the first operand into r2 and compare it with |
1220 // FIRST_SPEC_OBJECT_TYPE. | 1247 // FIRST_SPEC_OBJECT_TYPE. |
1221 __ CompareObjectType(rhs, r2, r2, FIRST_SPEC_OBJECT_TYPE); | 1248 __ CompareObjectType(rhs, r2, r2, FIRST_SPEC_OBJECT_TYPE); |
1222 __ b(lt, &first_non_object); | 1249 __ b(lt, &first_non_object); |
1223 | 1250 |
1224 // Return non-zero (r0 is not zero) | 1251 // Return non-zero (r0 is not zero) |
1225 Label return_not_equal; | 1252 Label return_not_equal; |
1226 __ bind(&return_not_equal); | 1253 __ bind(&return_not_equal); |
1227 __ Ret(); | 1254 __ Ret(); |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1599 | 1626 |
1600 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 1627 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
1601 // tagged as a small integer. | 1628 // tagged as a small integer. |
1602 __ InvokeBuiltin(native, JUMP_FUNCTION); | 1629 __ InvokeBuiltin(native, JUMP_FUNCTION); |
1603 } | 1630 } |
1604 | 1631 |
1605 | 1632 |
1606 // The stub expects its argument in the tos_ register and returns its result in | 1633 // The stub expects its argument in the tos_ register and returns its result in |
1607 // it, too: zero for false, and a non-zero value for true. | 1634 // it, too: zero for false, and a non-zero value for true. |
1608 void ToBooleanStub::Generate(MacroAssembler* masm) { | 1635 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 1636 // This stub overrides SometimesSetsUpAFrame() to return false. That means |
| 1637 // we cannot call anything that could cause a GC from this stub. |
1609 // This stub uses VFP3 instructions. | 1638 // This stub uses VFP3 instructions. |
1610 CpuFeatures::Scope scope(VFP3); | 1639 CpuFeatures::Scope scope(VFP3); |
1611 | 1640 |
1612 Label patch; | 1641 Label patch; |
1613 const Register map = r9.is(tos_) ? r7 : r9; | 1642 const Register map = r9.is(tos_) ? r7 : r9; |
1614 | 1643 |
1615 // undefined -> false. | 1644 // undefined -> false. |
1616 CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); | 1645 CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); |
1617 | 1646 |
1618 // Boolean -> its value. | 1647 // Boolean -> its value. |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1706 __ Push(r3, r2, r1); | 1735 __ Push(r3, r2, r1); |
1707 // Patch the caller to an appropriate specialized stub and return the | 1736 // Patch the caller to an appropriate specialized stub and return the |
1708 // operation result to the caller of the stub. | 1737 // operation result to the caller of the stub. |
1709 __ TailCallExternalReference( | 1738 __ TailCallExternalReference( |
1710 ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), | 1739 ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), |
1711 3, | 1740 3, |
1712 1); | 1741 1); |
1713 } | 1742 } |
1714 | 1743 |
1715 | 1744 |
| 1745 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
| 1746 // We don't allow a GC during a store buffer overflow so there is no need to |
| 1747 // store the registers in any particular way, but we do have to store and |
| 1748 // restore them. |
| 1749 __ stm(db_w, sp, kCallerSaved | lr.bit()); |
| 1750 if (save_doubles_ == kSaveFPRegs) { |
| 1751 CpuFeatures::Scope scope(VFP3); |
| 1752 __ sub(sp, sp, Operand(kDoubleSize * DwVfpRegister::kNumRegisters)); |
| 1753 for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { |
| 1754 DwVfpRegister reg = DwVfpRegister::from_code(i); |
| 1755 __ vstr(reg, MemOperand(sp, i * kDoubleSize)); |
| 1756 } |
| 1757 } |
| 1758 const int argument_count = 1; |
| 1759 const int fp_argument_count = 0; |
| 1760 const Register scratch = r1; |
| 1761 |
| 1762 AllowExternalCallThatCantCauseGC scope(masm); |
| 1763 __ PrepareCallCFunction(argument_count, fp_argument_count, scratch); |
| 1764 __ mov(r0, Operand(ExternalReference::isolate_address())); |
| 1765 __ CallCFunction( |
| 1766 ExternalReference::store_buffer_overflow_function(masm->isolate()), |
| 1767 argument_count); |
| 1768 if (save_doubles_ == kSaveFPRegs) { |
| 1769 CpuFeatures::Scope scope(VFP3); |
| 1770 for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { |
| 1771 DwVfpRegister reg = DwVfpRegister::from_code(i); |
| 1772 __ vldr(reg, MemOperand(sp, i * kDoubleSize)); |
| 1773 } |
| 1774 __ add(sp, sp, Operand(kDoubleSize * DwVfpRegister::kNumRegisters)); |
| 1775 } |
| 1776 __ ldm(ia_w, sp, kCallerSaved | pc.bit()); // Also pop pc to get Ret(0). |
| 1777 } |
| 1778 |
| 1779 |
1716 void UnaryOpStub::PrintName(StringStream* stream) { | 1780 void UnaryOpStub::PrintName(StringStream* stream) { |
1717 const char* op_name = Token::Name(op_); | 1781 const char* op_name = Token::Name(op_); |
1718 const char* overwrite_name = NULL; // Make g++ happy. | 1782 const char* overwrite_name = NULL; // Make g++ happy. |
1719 switch (mode_) { | 1783 switch (mode_) { |
1720 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | 1784 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; |
1721 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; | 1785 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; |
1722 } | 1786 } |
1723 stream->Add("UnaryOpStub_%s_%s_%s", | 1787 stream->Add("UnaryOpStub_%s_%s_%s", |
1724 op_name, | 1788 op_name, |
1725 overwrite_name, | 1789 overwrite_name, |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1859 if (mode_ == UNARY_OVERWRITE) { | 1923 if (mode_ == UNARY_OVERWRITE) { |
1860 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 1924 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
1861 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. | 1925 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. |
1862 __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 1926 __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
1863 } else { | 1927 } else { |
1864 Label slow_allocate_heapnumber, heapnumber_allocated; | 1928 Label slow_allocate_heapnumber, heapnumber_allocated; |
1865 __ AllocateHeapNumber(r1, r2, r3, r6, &slow_allocate_heapnumber); | 1929 __ AllocateHeapNumber(r1, r2, r3, r6, &slow_allocate_heapnumber); |
1866 __ jmp(&heapnumber_allocated); | 1930 __ jmp(&heapnumber_allocated); |
1867 | 1931 |
1868 __ bind(&slow_allocate_heapnumber); | 1932 __ bind(&slow_allocate_heapnumber); |
1869 __ EnterInternalFrame(); | 1933 { |
1870 __ push(r0); | 1934 FrameScope scope(masm, StackFrame::INTERNAL); |
1871 __ CallRuntime(Runtime::kNumberAlloc, 0); | 1935 __ push(r0); |
1872 __ mov(r1, Operand(r0)); | 1936 __ CallRuntime(Runtime::kNumberAlloc, 0); |
1873 __ pop(r0); | 1937 __ mov(r1, Operand(r0)); |
1874 __ LeaveInternalFrame(); | 1938 __ pop(r0); |
| 1939 } |
1875 | 1940 |
1876 __ bind(&heapnumber_allocated); | 1941 __ bind(&heapnumber_allocated); |
1877 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); | 1942 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); |
1878 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 1943 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
1879 __ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset)); | 1944 __ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset)); |
1880 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. | 1945 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. |
1881 __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset)); | 1946 __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset)); |
1882 __ mov(r0, Operand(r1)); | 1947 __ mov(r0, Operand(r1)); |
1883 } | 1948 } |
1884 __ Ret(); | 1949 __ Ret(); |
(...skipping 20 matching lines...) Expand all Loading... |
1905 | 1970 |
1906 // Try to store the result in a heap number. | 1971 // Try to store the result in a heap number. |
1907 __ bind(&try_float); | 1972 __ bind(&try_float); |
1908 if (mode_ == UNARY_NO_OVERWRITE) { | 1973 if (mode_ == UNARY_NO_OVERWRITE) { |
1909 Label slow_allocate_heapnumber, heapnumber_allocated; | 1974 Label slow_allocate_heapnumber, heapnumber_allocated; |
1910 // Allocate a new heap number without zapping r0, which we need if it fails. | 1975 // Allocate a new heap number without zapping r0, which we need if it fails. |
1911 __ AllocateHeapNumber(r2, r3, r4, r6, &slow_allocate_heapnumber); | 1976 __ AllocateHeapNumber(r2, r3, r4, r6, &slow_allocate_heapnumber); |
1912 __ jmp(&heapnumber_allocated); | 1977 __ jmp(&heapnumber_allocated); |
1913 | 1978 |
1914 __ bind(&slow_allocate_heapnumber); | 1979 __ bind(&slow_allocate_heapnumber); |
1915 __ EnterInternalFrame(); | 1980 { |
1916 __ push(r0); // Push the heap number, not the untagged int32. | 1981 FrameScope scope(masm, StackFrame::INTERNAL); |
1917 __ CallRuntime(Runtime::kNumberAlloc, 0); | 1982 __ push(r0); // Push the heap number, not the untagged int32. |
1918 __ mov(r2, r0); // Move the new heap number into r2. | 1983 __ CallRuntime(Runtime::kNumberAlloc, 0); |
1919 // Get the heap number into r0, now that the new heap number is in r2. | 1984 __ mov(r2, r0); // Move the new heap number into r2. |
1920 __ pop(r0); | 1985 // Get the heap number into r0, now that the new heap number is in r2. |
1921 __ LeaveInternalFrame(); | 1986 __ pop(r0); |
| 1987 } |
1922 | 1988 |
1923 // Convert the heap number in r0 to an untagged integer in r1. | 1989 // Convert the heap number in r0 to an untagged integer in r1. |
1924 // This can't go slow-case because it's the same number we already | 1990 // This can't go slow-case because it's the same number we already |
1925 // converted once again. | 1991 // converted once again. |
1926 __ ConvertToInt32(r0, r1, r3, r4, d0, &impossible); | 1992 __ ConvertToInt32(r0, r1, r3, r4, d0, &impossible); |
1927 __ mvn(r1, Operand(r1)); | 1993 __ mvn(r1, Operand(r1)); |
1928 | 1994 |
1929 __ bind(&heapnumber_allocated); | 1995 __ bind(&heapnumber_allocated); |
1930 __ mov(r0, r2); // Move newly allocated heap number to r0. | 1996 __ mov(r0, r2); // Move newly allocated heap number to r0. |
1931 } | 1997 } |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2021 } | 2087 } |
2022 | 2088 |
2023 | 2089 |
2024 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs( | 2090 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs( |
2025 MacroAssembler* masm) { | 2091 MacroAssembler* masm) { |
2026 UNIMPLEMENTED(); | 2092 UNIMPLEMENTED(); |
2027 } | 2093 } |
2028 | 2094 |
2029 | 2095 |
2030 void BinaryOpStub::Generate(MacroAssembler* masm) { | 2096 void BinaryOpStub::Generate(MacroAssembler* masm) { |
| 2097 // Explicitly allow generation of nested stubs. It is safe here because |
| 2098 // generation code does not use any raw pointers. |
| 2099 AllowStubCallsScope allow_stub_calls(masm, true); |
| 2100 |
2031 switch (operands_type_) { | 2101 switch (operands_type_) { |
2032 case BinaryOpIC::UNINITIALIZED: | 2102 case BinaryOpIC::UNINITIALIZED: |
2033 GenerateTypeTransition(masm); | 2103 GenerateTypeTransition(masm); |
2034 break; | 2104 break; |
2035 case BinaryOpIC::SMI: | 2105 case BinaryOpIC::SMI: |
2036 GenerateSmiStub(masm); | 2106 GenerateSmiStub(masm); |
2037 break; | 2107 break; |
2038 case BinaryOpIC::INT32: | 2108 case BinaryOpIC::INT32: |
2039 GenerateInt32Stub(masm); | 2109 GenerateInt32Stub(masm); |
2040 break; | 2110 break; |
(...skipping 1085 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3126 __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); | 3196 __ vstr(d2, FieldMemOperand(r6, HeapNumber::kValueOffset)); |
3127 __ stm(ia, cache_entry, r2.bit() | r3.bit() | r6.bit()); | 3197 __ stm(ia, cache_entry, r2.bit() | r3.bit() | r6.bit()); |
3128 __ Ret(); | 3198 __ Ret(); |
3129 | 3199 |
3130 __ bind(&invalid_cache); | 3200 __ bind(&invalid_cache); |
3131 // The cache is invalid. Call runtime which will recreate the | 3201 // The cache is invalid. Call runtime which will recreate the |
3132 // cache. | 3202 // cache. |
3133 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); | 3203 __ LoadRoot(r5, Heap::kHeapNumberMapRootIndex); |
3134 __ AllocateHeapNumber(r0, scratch0, scratch1, r5, &skip_cache); | 3204 __ AllocateHeapNumber(r0, scratch0, scratch1, r5, &skip_cache); |
3135 __ vstr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); | 3205 __ vstr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
3136 __ EnterInternalFrame(); | 3206 { |
3137 __ push(r0); | 3207 FrameScope scope(masm, StackFrame::INTERNAL); |
3138 __ CallRuntime(RuntimeFunction(), 1); | 3208 __ push(r0); |
3139 __ LeaveInternalFrame(); | 3209 __ CallRuntime(RuntimeFunction(), 1); |
| 3210 } |
3140 __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); | 3211 __ vldr(d2, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
3141 __ Ret(); | 3212 __ Ret(); |
3142 | 3213 |
3143 __ bind(&skip_cache); | 3214 __ bind(&skip_cache); |
3144 // Call C function to calculate the result and answer directly | 3215 // Call C function to calculate the result and answer directly |
3145 // without updating the cache. | 3216 // without updating the cache. |
3146 GenerateCallCFunction(masm, scratch0); | 3217 GenerateCallCFunction(masm, scratch0); |
3147 __ GetCFunctionDoubleResult(d2); | 3218 __ GetCFunctionDoubleResult(d2); |
3148 __ bind(&no_update); | 3219 __ bind(&no_update); |
3149 | 3220 |
3150 // We return the value in d2 without adding it to the cache, but | 3221 // We return the value in d2 without adding it to the cache, but |
3151 // we cause a scavenging GC so that future allocations will succeed. | 3222 // we cause a scavenging GC so that future allocations will succeed. |
3152 __ EnterInternalFrame(); | 3223 { |
| 3224 FrameScope scope(masm, StackFrame::INTERNAL); |
3153 | 3225 |
3154 // Allocate an aligned object larger than a HeapNumber. | 3226 // Allocate an aligned object larger than a HeapNumber. |
3155 ASSERT(4 * kPointerSize >= HeapNumber::kSize); | 3227 ASSERT(4 * kPointerSize >= HeapNumber::kSize); |
3156 __ mov(scratch0, Operand(4 * kPointerSize)); | 3228 __ mov(scratch0, Operand(4 * kPointerSize)); |
3157 __ push(scratch0); | 3229 __ push(scratch0); |
3158 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); | 3230 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); |
3159 __ LeaveInternalFrame(); | 3231 } |
3160 __ Ret(); | 3232 __ Ret(); |
3161 } | 3233 } |
3162 } | 3234 } |
3163 | 3235 |
3164 | 3236 |
3165 void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm, | 3237 void TranscendentalCacheStub::GenerateCallCFunction(MacroAssembler* masm, |
3166 Register scratch) { | 3238 Register scratch) { |
3167 Isolate* isolate = masm->isolate(); | 3239 Isolate* isolate = masm->isolate(); |
3168 | 3240 |
3169 __ push(lr); | 3241 __ push(lr); |
3170 __ PrepareCallCFunction(0, 1, scratch); | 3242 __ PrepareCallCFunction(0, 1, scratch); |
3171 if (masm->use_eabi_hardfloat()) { | 3243 if (masm->use_eabi_hardfloat()) { |
3172 __ vmov(d0, d2); | 3244 __ vmov(d0, d2); |
3173 } else { | 3245 } else { |
3174 __ vmov(r0, r1, d2); | 3246 __ vmov(r0, r1, d2); |
3175 } | 3247 } |
| 3248 AllowExternalCallThatCantCauseGC scope(masm); |
3176 switch (type_) { | 3249 switch (type_) { |
3177 case TranscendentalCache::SIN: | 3250 case TranscendentalCache::SIN: |
3178 __ CallCFunction(ExternalReference::math_sin_double_function(isolate), | 3251 __ CallCFunction(ExternalReference::math_sin_double_function(isolate), |
3179 0, 1); | 3252 0, 1); |
3180 break; | 3253 break; |
3181 case TranscendentalCache::COS: | 3254 case TranscendentalCache::COS: |
3182 __ CallCFunction(ExternalReference::math_cos_double_function(isolate), | 3255 __ CallCFunction(ExternalReference::math_cos_double_function(isolate), |
3183 0, 1); | 3256 0, 1); |
3184 break; | 3257 break; |
3185 case TranscendentalCache::LOG: | 3258 case TranscendentalCache::LOG: |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3261 // C function for integer exponents. The register containing | 3334 // C function for integer exponents. The register containing |
3262 // the heap number is callee-saved. | 3335 // the heap number is callee-saved. |
3263 __ AllocateHeapNumber(heapnumber, | 3336 __ AllocateHeapNumber(heapnumber, |
3264 scratch, | 3337 scratch, |
3265 scratch2, | 3338 scratch2, |
3266 heapnumbermap, | 3339 heapnumbermap, |
3267 &call_runtime); | 3340 &call_runtime); |
3268 __ push(lr); | 3341 __ push(lr); |
3269 __ PrepareCallCFunction(1, 1, scratch); | 3342 __ PrepareCallCFunction(1, 1, scratch); |
3270 __ SetCallCDoubleArguments(double_base, exponent); | 3343 __ SetCallCDoubleArguments(double_base, exponent); |
3271 __ CallCFunction( | 3344 { |
3272 ExternalReference::power_double_int_function(masm->isolate()), | 3345 AllowExternalCallThatCantCauseGC scope(masm); |
3273 1, 1); | 3346 __ CallCFunction( |
3274 __ pop(lr); | 3347 ExternalReference::power_double_int_function(masm->isolate()), |
3275 __ GetCFunctionDoubleResult(double_result); | 3348 1, 1); |
| 3349 __ pop(lr); |
| 3350 __ GetCFunctionDoubleResult(double_result); |
| 3351 } |
3276 __ vstr(double_result, | 3352 __ vstr(double_result, |
3277 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); | 3353 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); |
3278 __ mov(r0, heapnumber); | 3354 __ mov(r0, heapnumber); |
3279 __ Ret(2 * kPointerSize); | 3355 __ Ret(2 * kPointerSize); |
3280 | 3356 |
3281 __ bind(&exponent_not_smi); | 3357 __ bind(&exponent_not_smi); |
3282 __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); | 3358 __ ldr(scratch, FieldMemOperand(exponent, JSObject::kMapOffset)); |
3283 __ cmp(scratch, heapnumbermap); | 3359 __ cmp(scratch, heapnumbermap); |
3284 __ b(ne, &call_runtime); | 3360 __ b(ne, &call_runtime); |
3285 // Exponent is a heapnumber. Load it into double register. | 3361 // Exponent is a heapnumber. Load it into double register. |
3286 __ vldr(double_exponent, | 3362 __ vldr(double_exponent, |
3287 FieldMemOperand(exponent, HeapNumber::kValueOffset)); | 3363 FieldMemOperand(exponent, HeapNumber::kValueOffset)); |
3288 | 3364 |
3289 // The base and the exponent are in double registers. | 3365 // The base and the exponent are in double registers. |
3290 // Allocate a heap number and call a C function for | 3366 // Allocate a heap number and call a C function for |
3291 // double exponents. The register containing | 3367 // double exponents. The register containing |
3292 // the heap number is callee-saved. | 3368 // the heap number is callee-saved. |
3293 __ AllocateHeapNumber(heapnumber, | 3369 __ AllocateHeapNumber(heapnumber, |
3294 scratch, | 3370 scratch, |
3295 scratch2, | 3371 scratch2, |
3296 heapnumbermap, | 3372 heapnumbermap, |
3297 &call_runtime); | 3373 &call_runtime); |
3298 __ push(lr); | 3374 __ push(lr); |
3299 __ PrepareCallCFunction(0, 2, scratch); | 3375 __ PrepareCallCFunction(0, 2, scratch); |
3300 __ SetCallCDoubleArguments(double_base, double_exponent); | 3376 __ SetCallCDoubleArguments(double_base, double_exponent); |
3301 __ CallCFunction( | 3377 { |
3302 ExternalReference::power_double_double_function(masm->isolate()), | 3378 AllowExternalCallThatCantCauseGC scope(masm); |
3303 0, 2); | 3379 __ CallCFunction( |
3304 __ pop(lr); | 3380 ExternalReference::power_double_double_function(masm->isolate()), |
3305 __ GetCFunctionDoubleResult(double_result); | 3381 0, 2); |
| 3382 __ pop(lr); |
| 3383 __ GetCFunctionDoubleResult(double_result); |
| 3384 } |
3306 __ vstr(double_result, | 3385 __ vstr(double_result, |
3307 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); | 3386 FieldMemOperand(heapnumber, HeapNumber::kValueOffset)); |
3308 __ mov(r0, heapnumber); | 3387 __ mov(r0, heapnumber); |
3309 __ Ret(2 * kPointerSize); | 3388 __ Ret(2 * kPointerSize); |
3310 } | 3389 } |
3311 | 3390 |
3312 __ bind(&call_runtime); | 3391 __ bind(&call_runtime); |
3313 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); | 3392 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); |
3314 } | 3393 } |
3315 | 3394 |
3316 | 3395 |
3317 bool CEntryStub::NeedsImmovableCode() { | 3396 bool CEntryStub::NeedsImmovableCode() { |
3318 return true; | 3397 return true; |
3319 } | 3398 } |
3320 | 3399 |
3321 | 3400 |
| 3401 bool CEntryStub::IsPregenerated() { |
| 3402 return (!save_doubles_ || ISOLATE->fp_stubs_generated()) && |
| 3403 result_size_ == 1; |
| 3404 } |
| 3405 |
| 3406 |
| 3407 void CodeStub::GenerateStubsAheadOfTime() { |
| 3408 CEntryStub::GenerateAheadOfTime(); |
| 3409 WriteInt32ToHeapNumberStub::GenerateFixedRegStubsAheadOfTime(); |
| 3410 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(); |
| 3411 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(); |
| 3412 } |
| 3413 |
| 3414 |
| 3415 void CodeStub::GenerateFPStubs() { |
| 3416 CEntryStub save_doubles(1, kSaveFPRegs); |
| 3417 Handle<Code> code = save_doubles.GetCode(); |
| 3418 code->set_is_pregenerated(true); |
| 3419 StoreBufferOverflowStub stub(kSaveFPRegs); |
| 3420 stub.GetCode()->set_is_pregenerated(true); |
| 3421 code->GetIsolate()->set_fp_stubs_generated(true); |
| 3422 } |
| 3423 |
| 3424 |
| 3425 void CEntryStub::GenerateAheadOfTime() { |
| 3426 CEntryStub stub(1, kDontSaveFPRegs); |
| 3427 Handle<Code> code = stub.GetCode(); |
| 3428 code->set_is_pregenerated(true); |
| 3429 } |
| 3430 |
| 3431 |
3322 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { | 3432 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { |
3323 __ Throw(r0); | 3433 __ Throw(r0); |
3324 } | 3434 } |
3325 | 3435 |
3326 | 3436 |
3327 void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, | 3437 void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm, |
3328 UncatchableExceptionType type) { | 3438 UncatchableExceptionType type) { |
3329 __ ThrowUncatchable(type, r0); | 3439 __ ThrowUncatchable(type, r0); |
3330 } | 3440 } |
3331 | 3441 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3423 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); | 3533 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); |
3424 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); | 3534 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); |
3425 __ b(eq, &retry); | 3535 __ b(eq, &retry); |
3426 | 3536 |
3427 // Special handling of out of memory exceptions. | 3537 // Special handling of out of memory exceptions. |
3428 Failure* out_of_memory = Failure::OutOfMemoryException(); | 3538 Failure* out_of_memory = Failure::OutOfMemoryException(); |
3429 __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); | 3539 __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); |
3430 __ b(eq, throw_out_of_memory_exception); | 3540 __ b(eq, throw_out_of_memory_exception); |
3431 | 3541 |
3432 // Retrieve the pending exception and clear the variable. | 3542 // Retrieve the pending exception and clear the variable. |
3433 __ mov(ip, Operand(ExternalReference::the_hole_value_location(isolate))); | 3543 __ mov(r3, Operand(isolate->factory()->the_hole_value())); |
3434 __ ldr(r3, MemOperand(ip)); | |
3435 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | 3544 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, |
3436 isolate))); | 3545 isolate))); |
3437 __ ldr(r0, MemOperand(ip)); | 3546 __ ldr(r0, MemOperand(ip)); |
3438 __ str(r3, MemOperand(ip)); | 3547 __ str(r3, MemOperand(ip)); |
3439 | 3548 |
3440 // Special handling of termination exceptions which are uncatchable | 3549 // Special handling of termination exceptions which are uncatchable |
3441 // by javascript code. | 3550 // by javascript code. |
3442 __ cmp(r0, Operand(isolate->factory()->termination_exception())); | 3551 __ cmp(r0, Operand(isolate->factory()->termination_exception())); |
3443 __ b(eq, throw_termination_exception); | 3552 __ b(eq, throw_termination_exception); |
3444 | 3553 |
(...skipping 17 matching lines...) Expand all Loading... |
3462 // NOTE: Invocations of builtins may return failure objects | 3571 // NOTE: Invocations of builtins may return failure objects |
3463 // instead of a proper result. The builtin entry handles | 3572 // instead of a proper result. The builtin entry handles |
3464 // this by performing a garbage collection and retrying the | 3573 // this by performing a garbage collection and retrying the |
3465 // builtin once. | 3574 // builtin once. |
3466 | 3575 |
3467 // Compute the argv pointer in a callee-saved register. | 3576 // Compute the argv pointer in a callee-saved register. |
3468 __ add(r6, sp, Operand(r0, LSL, kPointerSizeLog2)); | 3577 __ add(r6, sp, Operand(r0, LSL, kPointerSizeLog2)); |
3469 __ sub(r6, r6, Operand(kPointerSize)); | 3578 __ sub(r6, r6, Operand(kPointerSize)); |
3470 | 3579 |
3471 // Enter the exit frame that transitions from JavaScript to C++. | 3580 // Enter the exit frame that transitions from JavaScript to C++. |
| 3581 FrameScope scope(masm, StackFrame::MANUAL); |
3472 __ EnterExitFrame(save_doubles_); | 3582 __ EnterExitFrame(save_doubles_); |
3473 | 3583 |
3474 // Setup argc and the builtin function in callee-saved registers. | 3584 // Setup argc and the builtin function in callee-saved registers. |
3475 __ mov(r4, Operand(r0)); | 3585 __ mov(r4, Operand(r0)); |
3476 __ mov(r5, Operand(r1)); | 3586 __ mov(r5, Operand(r1)); |
3477 | 3587 |
3478 // r4: number of arguments (C callee-saved) | 3588 // r4: number of arguments (C callee-saved) |
3479 // r5: pointer to builtin function (C callee-saved) | 3589 // r5: pointer to builtin function (C callee-saved) |
3480 // r6: pointer to first argument (C callee-saved) | 3590 // r6: pointer to first argument (C callee-saved) |
3481 | 3591 |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3606 // Invoke: Link this frame into the handler chain. | 3716 // Invoke: Link this frame into the handler chain. |
3607 __ bind(&invoke); | 3717 __ bind(&invoke); |
3608 // Must preserve r0-r4, r5-r7 are available. | 3718 // Must preserve r0-r4, r5-r7 are available. |
3609 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); | 3719 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); |
3610 // If an exception not caught by another handler occurs, this handler | 3720 // If an exception not caught by another handler occurs, this handler |
3611 // returns control to the code after the bl(&invoke) above, which | 3721 // returns control to the code after the bl(&invoke) above, which |
3612 // restores all kCalleeSaved registers (including cp and fp) to their | 3722 // restores all kCalleeSaved registers (including cp and fp) to their |
3613 // saved values before returning a failure to C. | 3723 // saved values before returning a failure to C. |
3614 | 3724 |
3615 // Clear any pending exceptions. | 3725 // Clear any pending exceptions. |
3616 __ mov(ip, Operand(ExternalReference::the_hole_value_location(isolate))); | 3726 __ mov(r5, Operand(isolate->factory()->the_hole_value())); |
3617 __ ldr(r5, MemOperand(ip)); | |
3618 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | 3727 __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress, |
3619 isolate))); | 3728 isolate))); |
3620 __ str(r5, MemOperand(ip)); | 3729 __ str(r5, MemOperand(ip)); |
3621 | 3730 |
3622 // Invoke the function by calling through JS entry trampoline builtin. | 3731 // Invoke the function by calling through JS entry trampoline builtin. |
3623 // Notice that we cannot store a reference to the trampoline code directly in | 3732 // Notice that we cannot store a reference to the trampoline code directly in |
3624 // this stub, because runtime stubs are not traversed when doing GC. | 3733 // this stub, because runtime stubs are not traversed when doing GC. |
3625 | 3734 |
3626 // Expected registers by Builtins::JSEntryTrampoline | 3735 // Expected registers by Builtins::JSEntryTrampoline |
3627 // r0: code entry | 3736 // r0: code entry |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3844 __ Ret(HasArgsInRegisters() ? 0 : 2); | 3953 __ Ret(HasArgsInRegisters() ? 0 : 2); |
3845 | 3954 |
3846 // Slow-case. Tail call builtin. | 3955 // Slow-case. Tail call builtin. |
3847 __ bind(&slow); | 3956 __ bind(&slow); |
3848 if (!ReturnTrueFalseObject()) { | 3957 if (!ReturnTrueFalseObject()) { |
3849 if (HasArgsInRegisters()) { | 3958 if (HasArgsInRegisters()) { |
3850 __ Push(r0, r1); | 3959 __ Push(r0, r1); |
3851 } | 3960 } |
3852 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 3961 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
3853 } else { | 3962 } else { |
3854 __ EnterInternalFrame(); | 3963 { |
3855 __ Push(r0, r1); | 3964 FrameScope scope(masm, StackFrame::INTERNAL); |
3856 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); | 3965 __ Push(r0, r1); |
3857 __ LeaveInternalFrame(); | 3966 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); |
| 3967 } |
3858 __ cmp(r0, Operand::Zero()); | 3968 __ cmp(r0, Operand::Zero()); |
3859 __ LoadRoot(r0, Heap::kTrueValueRootIndex, eq); | 3969 __ LoadRoot(r0, Heap::kTrueValueRootIndex, eq); |
3860 __ LoadRoot(r0, Heap::kFalseValueRootIndex, ne); | 3970 __ LoadRoot(r0, Heap::kFalseValueRootIndex, ne); |
3861 __ Ret(HasArgsInRegisters() ? 0 : 2); | 3971 __ Ret(HasArgsInRegisters() ? 0 : 2); |
3862 } | 3972 } |
3863 } | 3973 } |
3864 | 3974 |
3865 | 3975 |
3866 Register InstanceofStub::left() { return r0; } | 3976 Register InstanceofStub::left() { return r0; } |
3867 | 3977 |
(...skipping 605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4473 __ add(r0, r0, Operand(r2)); | 4583 __ add(r0, r0, Operand(r2)); |
4474 __ str(r0, MemOperand(sp, 2 * kPointerSize)); | 4584 __ str(r0, MemOperand(sp, 2 * kPointerSize)); |
4475 | 4585 |
4476 // Argument 5 (sp[4]): static offsets vector buffer. | 4586 // Argument 5 (sp[4]): static offsets vector buffer. |
4477 __ mov(r0, | 4587 __ mov(r0, |
4478 Operand(ExternalReference::address_of_static_offsets_vector(isolate))); | 4588 Operand(ExternalReference::address_of_static_offsets_vector(isolate))); |
4479 __ str(r0, MemOperand(sp, 1 * kPointerSize)); | 4589 __ str(r0, MemOperand(sp, 1 * kPointerSize)); |
4480 | 4590 |
4481 // For arguments 4 and 3 get string length, calculate start of string data and | 4591 // For arguments 4 and 3 get string length, calculate start of string data and |
4482 // calculate the shift of the index (0 for ASCII and 1 for two byte). | 4592 // calculate the shift of the index (0 for ASCII and 1 for two byte). |
4483 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); | 4593 __ add(r8, subject, Operand(SeqString::kHeaderSize - kHeapObjectTag)); |
4484 __ add(r8, subject, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | |
4485 __ eor(r3, r3, Operand(1)); | 4594 __ eor(r3, r3, Operand(1)); |
4486 // Load the length from the original subject string from the previous stack | 4595 // Load the length from the original subject string from the previous stack |
4487 // frame. Therefore we have to use fp, which points exactly to two pointer | 4596 // frame. Therefore we have to use fp, which points exactly to two pointer |
4488 // sizes below the previous sp. (Because creating a new stack frame pushes | 4597 // sizes below the previous sp. (Because creating a new stack frame pushes |
4489 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) | 4598 // the previous fp onto the stack and moves up sp by 2 * kPointerSize.) |
4490 __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); | 4599 __ ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize)); |
4491 // If slice offset is not 0, load the length from the original sliced string. | 4600 // If slice offset is not 0, load the length from the original sliced string. |
4492 // Argument 4, r3: End of string data | 4601 // Argument 4, r3: End of string data |
4493 // Argument 3, r2: Start of string data | 4602 // Argument 3, r2: Start of string data |
4494 // Prepare start and end index of the input. | 4603 // Prepare start and end index of the input. |
(...skipping 30 matching lines...) Expand all Loading... |
4525 Label failure; | 4634 Label failure; |
4526 __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE)); | 4635 __ cmp(r0, Operand(NativeRegExpMacroAssembler::FAILURE)); |
4527 __ b(eq, &failure); | 4636 __ b(eq, &failure); |
4528 __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); | 4637 __ cmp(r0, Operand(NativeRegExpMacroAssembler::EXCEPTION)); |
4529 // If not exception it can only be retry. Handle that in the runtime system. | 4638 // If not exception it can only be retry. Handle that in the runtime system. |
4530 __ b(ne, &runtime); | 4639 __ b(ne, &runtime); |
4531 // Result must now be exception. If there is no pending exception already a | 4640 // Result must now be exception. If there is no pending exception already a |
4532 // stack overflow (on the backtrack stack) was detected in RegExp code but | 4641 // stack overflow (on the backtrack stack) was detected in RegExp code but |
4533 // haven't created the exception yet. Handle that in the runtime system. | 4642 // haven't created the exception yet. Handle that in the runtime system. |
4534 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | 4643 // TODO(592): Rerunning the RegExp to get the stack overflow exception. |
4535 __ mov(r1, Operand(ExternalReference::the_hole_value_location(isolate))); | 4644 __ mov(r1, Operand(isolate->factory()->the_hole_value())); |
4536 __ ldr(r1, MemOperand(r1, 0)); | |
4537 __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress, | 4645 __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress, |
4538 isolate))); | 4646 isolate))); |
4539 __ ldr(r0, MemOperand(r2, 0)); | 4647 __ ldr(r0, MemOperand(r2, 0)); |
4540 __ cmp(r0, r1); | 4648 __ cmp(r0, r1); |
4541 __ b(eq, &runtime); | 4649 __ b(eq, &runtime); |
4542 | 4650 |
4543 __ str(r1, MemOperand(r2, 0)); // Clear pending exception. | 4651 __ str(r1, MemOperand(r2, 0)); // Clear pending exception. |
4544 | 4652 |
4545 // Check if the exception is a termination. If so, throw as uncatchable. | 4653 // Check if the exception is a termination. If so, throw as uncatchable. |
4546 __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex); | 4654 __ CompareRoot(r0, Heap::kTerminationExceptionRootIndex); |
(...skipping 21 matching lines...) Expand all Loading... |
4568 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 4676 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
4569 __ add(r1, r1, Operand(2)); // r1 was a smi. | 4677 __ add(r1, r1, Operand(2)); // r1 was a smi. |
4570 | 4678 |
4571 // r1: number of capture registers | 4679 // r1: number of capture registers |
4572 // r4: subject string | 4680 // r4: subject string |
4573 // Store the capture count. | 4681 // Store the capture count. |
4574 __ mov(r2, Operand(r1, LSL, kSmiTagSize + kSmiShiftSize)); // To smi. | 4682 __ mov(r2, Operand(r1, LSL, kSmiTagSize + kSmiShiftSize)); // To smi. |
4575 __ str(r2, FieldMemOperand(last_match_info_elements, | 4683 __ str(r2, FieldMemOperand(last_match_info_elements, |
4576 RegExpImpl::kLastCaptureCountOffset)); | 4684 RegExpImpl::kLastCaptureCountOffset)); |
4577 // Store last subject and last input. | 4685 // Store last subject and last input. |
4578 __ mov(r3, last_match_info_elements); // Moved up to reduce latency. | |
4579 __ str(subject, | 4686 __ str(subject, |
4580 FieldMemOperand(last_match_info_elements, | 4687 FieldMemOperand(last_match_info_elements, |
4581 RegExpImpl::kLastSubjectOffset)); | 4688 RegExpImpl::kLastSubjectOffset)); |
4582 __ RecordWrite(r3, Operand(RegExpImpl::kLastSubjectOffset), r2, r7); | 4689 __ mov(r2, subject); |
| 4690 __ RecordWriteField(last_match_info_elements, |
| 4691 RegExpImpl::kLastSubjectOffset, |
| 4692 r2, |
| 4693 r7, |
| 4694 kLRHasNotBeenSaved, |
| 4695 kDontSaveFPRegs); |
4583 __ str(subject, | 4696 __ str(subject, |
4584 FieldMemOperand(last_match_info_elements, | 4697 FieldMemOperand(last_match_info_elements, |
4585 RegExpImpl::kLastInputOffset)); | 4698 RegExpImpl::kLastInputOffset)); |
4586 __ mov(r3, last_match_info_elements); | 4699 __ RecordWriteField(last_match_info_elements, |
4587 __ RecordWrite(r3, Operand(RegExpImpl::kLastInputOffset), r2, r7); | 4700 RegExpImpl::kLastInputOffset, |
| 4701 subject, |
| 4702 r7, |
| 4703 kLRHasNotBeenSaved, |
| 4704 kDontSaveFPRegs); |
4588 | 4705 |
4589 // Get the static offsets vector filled by the native regexp code. | 4706 // Get the static offsets vector filled by the native regexp code. |
4590 ExternalReference address_of_static_offsets_vector = | 4707 ExternalReference address_of_static_offsets_vector = |
4591 ExternalReference::address_of_static_offsets_vector(isolate); | 4708 ExternalReference::address_of_static_offsets_vector(isolate); |
4592 __ mov(r2, Operand(address_of_static_offsets_vector)); | 4709 __ mov(r2, Operand(address_of_static_offsets_vector)); |
4593 | 4710 |
4594 // r1: number of capture registers | 4711 // r1: number of capture registers |
4595 // r2: offsets vector | 4712 // r2: offsets vector |
4596 Label next_capture, done; | 4713 Label next_capture, done; |
4597 // Capture register counter starts from number of capture registers and | 4714 // Capture register counter starts from number of capture registers and |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4705 | 4822 |
4706 __ bind(&done); | 4823 __ bind(&done); |
4707 __ add(sp, sp, Operand(3 * kPointerSize)); | 4824 __ add(sp, sp, Operand(3 * kPointerSize)); |
4708 __ Ret(); | 4825 __ Ret(); |
4709 | 4826 |
4710 __ bind(&slowcase); | 4827 __ bind(&slowcase); |
4711 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); | 4828 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); |
4712 } | 4829 } |
4713 | 4830 |
4714 | 4831 |
| 4832 void CallFunctionStub::FinishCode(Code* code) { |
| 4833 code->set_has_function_cache(false); |
| 4834 } |
| 4835 |
| 4836 |
| 4837 void CallFunctionStub::Clear(Heap* heap, Address address) { |
| 4838 UNREACHABLE(); |
| 4839 } |
| 4840 |
| 4841 |
| 4842 Object* CallFunctionStub::GetCachedValue(Address address) { |
| 4843 UNREACHABLE(); |
| 4844 return NULL; |
| 4845 } |
| 4846 |
| 4847 |
4715 void CallFunctionStub::Generate(MacroAssembler* masm) { | 4848 void CallFunctionStub::Generate(MacroAssembler* masm) { |
4716 Label slow, non_function; | 4849 Label slow, non_function; |
4717 | 4850 |
4718 // The receiver might implicitly be the global object. This is | 4851 // The receiver might implicitly be the global object. This is |
4719 // indicated by passing the hole as the receiver to the call | 4852 // indicated by passing the hole as the receiver to the call |
4720 // function stub. | 4853 // function stub. |
4721 if (ReceiverMightBeImplicit()) { | 4854 if (ReceiverMightBeImplicit()) { |
4722 Label call; | 4855 Label call; |
4723 // Get the receiver from the stack. | 4856 // Get the receiver from the stack. |
4724 // function, receiver [, arguments] | 4857 // function, receiver [, arguments] |
(...skipping 1693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6418 } | 6551 } |
6419 | 6552 |
6420 | 6553 |
6421 void ICCompareStub::GenerateMiss(MacroAssembler* masm) { | 6554 void ICCompareStub::GenerateMiss(MacroAssembler* masm) { |
6422 __ Push(r1, r0); | 6555 __ Push(r1, r0); |
6423 __ push(lr); | 6556 __ push(lr); |
6424 | 6557 |
6425 // Call the runtime system in a fresh internal frame. | 6558 // Call the runtime system in a fresh internal frame. |
6426 ExternalReference miss = | 6559 ExternalReference miss = |
6427 ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate()); | 6560 ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate()); |
6428 __ EnterInternalFrame(); | 6561 { |
6429 __ Push(r1, r0); | 6562 FrameScope scope(masm, StackFrame::INTERNAL); |
6430 __ mov(ip, Operand(Smi::FromInt(op_))); | 6563 __ Push(r1, r0); |
6431 __ push(ip); | 6564 __ mov(ip, Operand(Smi::FromInt(op_))); |
6432 __ CallExternalReference(miss, 3); | 6565 __ push(ip); |
6433 __ LeaveInternalFrame(); | 6566 __ CallExternalReference(miss, 3); |
| 6567 } |
6434 // Compute the entry point of the rewritten stub. | 6568 // Compute the entry point of the rewritten stub. |
6435 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); | 6569 __ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); |
6436 // Restore registers. | 6570 // Restore registers. |
6437 __ pop(lr); | 6571 __ pop(lr); |
6438 __ pop(r0); | 6572 __ pop(r0); |
6439 __ pop(r1); | 6573 __ pop(r1); |
6440 __ Jump(r2); | 6574 __ Jump(r2); |
6441 } | 6575 } |
6442 | 6576 |
6443 | 6577 |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6606 __ tst(r0, Operand(r0)); | 6740 __ tst(r0, Operand(r0)); |
6607 __ mov(scratch2, Operand(r2)); | 6741 __ mov(scratch2, Operand(r2)); |
6608 __ ldm(ia_w, sp, spill_mask); | 6742 __ ldm(ia_w, sp, spill_mask); |
6609 | 6743 |
6610 __ b(ne, done); | 6744 __ b(ne, done); |
6611 __ b(eq, miss); | 6745 __ b(eq, miss); |
6612 } | 6746 } |
6613 | 6747 |
6614 | 6748 |
6615 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { | 6749 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { |
| 6750 // This stub overrides SometimesSetsUpAFrame() to return false. That means |
| 6751 // we cannot call anything that could cause a GC from this stub. |
6616 // Registers: | 6752 // Registers: |
6617 // result: StringDictionary to probe | 6753 // result: StringDictionary to probe |
6618 // r1: key | 6754 // r1: key |
6619 // : StringDictionary to probe. | 6755 // : StringDictionary to probe. |
6620 // index_: will hold an index of entry if lookup is successful. | 6756 // index_: will hold an index of entry if lookup is successful. |
6621 // might alias with result_. | 6757 // might alias with result_. |
6622 // Returns: | 6758 // Returns: |
6623 // result_ is zero if lookup failed, non zero otherwise. | 6759 // result_ is zero if lookup failed, non zero otherwise. |
6624 | 6760 |
6625 Register result = r0; | 6761 Register result = r0; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6695 __ bind(&in_dictionary); | 6831 __ bind(&in_dictionary); |
6696 __ mov(result, Operand(1)); | 6832 __ mov(result, Operand(1)); |
6697 __ Ret(); | 6833 __ Ret(); |
6698 | 6834 |
6699 __ bind(¬_in_dictionary); | 6835 __ bind(¬_in_dictionary); |
6700 __ mov(result, Operand::Zero()); | 6836 __ mov(result, Operand::Zero()); |
6701 __ Ret(); | 6837 __ Ret(); |
6702 } | 6838 } |
6703 | 6839 |
6704 | 6840 |
| 6841 struct AheadOfTimeWriteBarrierStubList { |
| 6842 Register object, value, address; |
| 6843 RememberedSetAction action; |
| 6844 }; |
| 6845 |
| 6846 |
| 6847 struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { |
| 6848 // Used in RegExpExecStub. |
| 6849 { r6, r4, r7, EMIT_REMEMBERED_SET }, |
| 6850 { r6, r2, r7, EMIT_REMEMBERED_SET }, |
| 6851 // Used in CompileArrayPushCall. |
| 6852 // Also used in StoreIC::GenerateNormal via GenerateDictionaryStore. |
| 6853 // Also used in KeyedStoreIC::GenerateGeneric. |
| 6854 { r3, r4, r5, EMIT_REMEMBERED_SET }, |
| 6855 // Used in CompileStoreGlobal. |
| 6856 { r4, r1, r2, OMIT_REMEMBERED_SET }, |
| 6857 // Used in StoreStubCompiler::CompileStoreField via GenerateStoreField. |
| 6858 { r1, r2, r3, EMIT_REMEMBERED_SET }, |
| 6859 { r3, r2, r1, EMIT_REMEMBERED_SET }, |
| 6860 // Used in KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField. |
| 6861 { r2, r1, r3, EMIT_REMEMBERED_SET }, |
| 6862 { r3, r1, r2, EMIT_REMEMBERED_SET }, |
| 6863 // KeyedStoreStubCompiler::GenerateStoreFastElement. |
| 6864 { r4, r2, r3, EMIT_REMEMBERED_SET }, |
| 6865 // Null termination. |
| 6866 { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET} |
| 6867 }; |
| 6868 |
| 6869 |
| 6870 bool RecordWriteStub::IsPregenerated() { |
| 6871 for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; |
| 6872 !entry->object.is(no_reg); |
| 6873 entry++) { |
| 6874 if (object_.is(entry->object) && |
| 6875 value_.is(entry->value) && |
| 6876 address_.is(entry->address) && |
| 6877 remembered_set_action_ == entry->action && |
| 6878 save_fp_regs_mode_ == kDontSaveFPRegs) { |
| 6879 return true; |
| 6880 } |
| 6881 } |
| 6882 return false; |
| 6883 } |
| 6884 |
| 6885 |
| 6886 bool StoreBufferOverflowStub::IsPregenerated() { |
| 6887 return save_doubles_ == kDontSaveFPRegs || ISOLATE->fp_stubs_generated(); |
| 6888 } |
| 6889 |
| 6890 |
| 6891 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime() { |
| 6892 StoreBufferOverflowStub stub1(kDontSaveFPRegs); |
| 6893 stub1.GetCode()->set_is_pregenerated(true); |
| 6894 } |
| 6895 |
| 6896 |
| 6897 void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { |
| 6898 for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; |
| 6899 !entry->object.is(no_reg); |
| 6900 entry++) { |
| 6901 RecordWriteStub stub(entry->object, |
| 6902 entry->value, |
| 6903 entry->address, |
| 6904 entry->action, |
| 6905 kDontSaveFPRegs); |
| 6906 stub.GetCode()->set_is_pregenerated(true); |
| 6907 } |
| 6908 } |
| 6909 |
| 6910 |
| 6911 // Takes the input in 3 registers: address_ value_ and object_. A pointer to |
| 6912 // the value has just been written into the object, now this stub makes sure |
| 6913 // we keep the GC informed. The word in the object where the value has been |
| 6914 // written is in the address register. |
| 6915 void RecordWriteStub::Generate(MacroAssembler* masm) { |
| 6916 Label skip_to_incremental_noncompacting; |
| 6917 Label skip_to_incremental_compacting; |
| 6918 |
| 6919 // The first two instructions are generated with labels so as to get the |
| 6920 // offset fixed up correctly by the bind(Label*) call. We patch it back and |
| 6921 // forth between a compare instructions (a nop in this position) and the |
| 6922 // real branch when we start and stop incremental heap marking. |
| 6923 // See RecordWriteStub::Patch for details. |
| 6924 __ b(&skip_to_incremental_noncompacting); |
| 6925 __ b(&skip_to_incremental_compacting); |
| 6926 |
| 6927 if (remembered_set_action_ == EMIT_REMEMBERED_SET) { |
| 6928 __ RememberedSetHelper(object_, |
| 6929 address_, |
| 6930 value_, |
| 6931 save_fp_regs_mode_, |
| 6932 MacroAssembler::kReturnAtEnd); |
| 6933 } |
| 6934 __ Ret(); |
| 6935 |
| 6936 __ bind(&skip_to_incremental_noncompacting); |
| 6937 GenerateIncremental(masm, INCREMENTAL); |
| 6938 |
| 6939 __ bind(&skip_to_incremental_compacting); |
| 6940 GenerateIncremental(masm, INCREMENTAL_COMPACTION); |
| 6941 |
| 6942 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY. |
| 6943 // Will be checked in IncrementalMarking::ActivateGeneratedStub. |
| 6944 ASSERT(Assembler::GetBranchOffset(masm->instr_at(0)) < (1 << 12)); |
| 6945 ASSERT(Assembler::GetBranchOffset(masm->instr_at(4)) < (1 << 12)); |
| 6946 PatchBranchIntoNop(masm, 0); |
| 6947 PatchBranchIntoNop(masm, Assembler::kInstrSize); |
| 6948 } |
| 6949 |
| 6950 |
| 6951 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { |
| 6952 regs_.Save(masm); |
| 6953 |
| 6954 if (remembered_set_action_ == EMIT_REMEMBERED_SET) { |
| 6955 Label dont_need_remembered_set; |
| 6956 |
| 6957 __ ldr(regs_.scratch0(), MemOperand(regs_.address(), 0)); |
| 6958 __ JumpIfNotInNewSpace(regs_.scratch0(), // Value. |
| 6959 regs_.scratch0(), |
| 6960 &dont_need_remembered_set); |
| 6961 |
| 6962 __ CheckPageFlag(regs_.object(), |
| 6963 regs_.scratch0(), |
| 6964 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
| 6965 ne, |
| 6966 &dont_need_remembered_set); |
| 6967 |
| 6968 // First notify the incremental marker if necessary, then update the |
| 6969 // remembered set. |
| 6970 CheckNeedsToInformIncrementalMarker( |
| 6971 masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode); |
| 6972 InformIncrementalMarker(masm, mode); |
| 6973 regs_.Restore(masm); |
| 6974 __ RememberedSetHelper(object_, |
| 6975 address_, |
| 6976 value_, |
| 6977 save_fp_regs_mode_, |
| 6978 MacroAssembler::kReturnAtEnd); |
| 6979 |
| 6980 __ bind(&dont_need_remembered_set); |
| 6981 } |
| 6982 |
| 6983 CheckNeedsToInformIncrementalMarker( |
| 6984 masm, kReturnOnNoNeedToInformIncrementalMarker, mode); |
| 6985 InformIncrementalMarker(masm, mode); |
| 6986 regs_.Restore(masm); |
| 6987 __ Ret(); |
| 6988 } |
| 6989 |
| 6990 |
| 6991 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { |
| 6992 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_); |
| 6993 int argument_count = 3; |
| 6994 __ PrepareCallCFunction(argument_count, regs_.scratch0()); |
| 6995 Register address = |
| 6996 r0.is(regs_.address()) ? regs_.scratch0() : regs_.address(); |
| 6997 ASSERT(!address.is(regs_.object())); |
| 6998 ASSERT(!address.is(r0)); |
| 6999 __ Move(address, regs_.address()); |
| 7000 __ Move(r0, regs_.object()); |
| 7001 if (mode == INCREMENTAL_COMPACTION) { |
| 7002 __ Move(r1, address); |
| 7003 } else { |
| 7004 ASSERT(mode == INCREMENTAL); |
| 7005 __ ldr(r1, MemOperand(address, 0)); |
| 7006 } |
| 7007 __ mov(r2, Operand(ExternalReference::isolate_address())); |
| 7008 |
| 7009 AllowExternalCallThatCantCauseGC scope(masm); |
| 7010 if (mode == INCREMENTAL_COMPACTION) { |
| 7011 __ CallCFunction( |
| 7012 ExternalReference::incremental_evacuation_record_write_function( |
| 7013 masm->isolate()), |
| 7014 argument_count); |
| 7015 } else { |
| 7016 ASSERT(mode == INCREMENTAL); |
| 7017 __ CallCFunction( |
| 7018 ExternalReference::incremental_marking_record_write_function( |
| 7019 masm->isolate()), |
| 7020 argument_count); |
| 7021 } |
| 7022 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_); |
| 7023 } |
| 7024 |
| 7025 |
| 7026 void RecordWriteStub::CheckNeedsToInformIncrementalMarker( |
| 7027 MacroAssembler* masm, |
| 7028 OnNoNeedToInformIncrementalMarker on_no_need, |
| 7029 Mode mode) { |
| 7030 Label on_black; |
| 7031 Label need_incremental; |
| 7032 Label need_incremental_pop_scratch; |
| 7033 |
| 7034 // Let's look at the color of the object: If it is not black we don't have |
| 7035 // to inform the incremental marker. |
| 7036 __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black); |
| 7037 |
| 7038 regs_.Restore(masm); |
| 7039 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { |
| 7040 __ RememberedSetHelper(object_, |
| 7041 address_, |
| 7042 value_, |
| 7043 save_fp_regs_mode_, |
| 7044 MacroAssembler::kReturnAtEnd); |
| 7045 } else { |
| 7046 __ Ret(); |
| 7047 } |
| 7048 |
| 7049 __ bind(&on_black); |
| 7050 |
| 7051 // Get the value from the slot. |
| 7052 __ ldr(regs_.scratch0(), MemOperand(regs_.address(), 0)); |
| 7053 |
| 7054 if (mode == INCREMENTAL_COMPACTION) { |
| 7055 Label ensure_not_white; |
| 7056 |
| 7057 __ CheckPageFlag(regs_.scratch0(), // Contains value. |
| 7058 regs_.scratch1(), // Scratch. |
| 7059 MemoryChunk::kEvacuationCandidateMask, |
| 7060 eq, |
| 7061 &ensure_not_white); |
| 7062 |
| 7063 __ CheckPageFlag(regs_.object(), |
| 7064 regs_.scratch1(), // Scratch. |
| 7065 MemoryChunk::kSkipEvacuationSlotsRecordingMask, |
| 7066 eq, |
| 7067 &need_incremental); |
| 7068 |
| 7069 __ bind(&ensure_not_white); |
| 7070 } |
| 7071 |
| 7072 // We need extra registers for this, so we push the object and the address |
| 7073 // register temporarily. |
| 7074 __ Push(regs_.object(), regs_.address()); |
| 7075 __ EnsureNotWhite(regs_.scratch0(), // The value. |
| 7076 regs_.scratch1(), // Scratch. |
| 7077 regs_.object(), // Scratch. |
| 7078 regs_.address(), // Scratch. |
| 7079 &need_incremental_pop_scratch); |
| 7080 __ Pop(regs_.object(), regs_.address()); |
| 7081 |
| 7082 regs_.Restore(masm); |
| 7083 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { |
| 7084 __ RememberedSetHelper(object_, |
| 7085 address_, |
| 7086 value_, |
| 7087 save_fp_regs_mode_, |
| 7088 MacroAssembler::kReturnAtEnd); |
| 7089 } else { |
| 7090 __ Ret(); |
| 7091 } |
| 7092 |
| 7093 __ bind(&need_incremental_pop_scratch); |
| 7094 __ Pop(regs_.object(), regs_.address()); |
| 7095 |
| 7096 __ bind(&need_incremental); |
| 7097 |
| 7098 // Fall through when we need to inform the incremental marker. |
| 7099 } |
| 7100 |
| 7101 |
6705 #undef __ | 7102 #undef __ |
6706 | 7103 |
6707 } } // namespace v8::internal | 7104 } } // namespace v8::internal |
6708 | 7105 |
6709 #endif // V8_TARGET_ARCH_ARM | 7106 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |