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 1454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1465 Label is_smi; | 1465 Label is_smi; |
1466 Label load_result_from_cache; | 1466 Label load_result_from_cache; |
1467 if (!object_is_smi) { | 1467 if (!object_is_smi) { |
1468 __ JumpIfSmi(object, &is_smi); | 1468 __ JumpIfSmi(object, &is_smi); |
1469 if (CpuFeatures::IsSupported(FPU)) { | 1469 if (CpuFeatures::IsSupported(FPU)) { |
1470 CpuFeatures::Scope scope(FPU); | 1470 CpuFeatures::Scope scope(FPU); |
1471 __ CheckMap(object, | 1471 __ CheckMap(object, |
1472 scratch1, | 1472 scratch1, |
1473 Heap::kHeapNumberMapRootIndex, | 1473 Heap::kHeapNumberMapRootIndex, |
1474 not_found, | 1474 not_found, |
1475 true); | 1475 DONT_DO_SMI_CHECK); |
1476 | 1476 |
1477 STATIC_ASSERT(8 == kDoubleSize); | 1477 STATIC_ASSERT(8 == kDoubleSize); |
1478 __ Addu(scratch1, | 1478 __ Addu(scratch1, |
1479 object, | 1479 object, |
1480 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); | 1480 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); |
1481 __ lw(scratch2, MemOperand(scratch1, kPointerSize)); | 1481 __ lw(scratch2, MemOperand(scratch1, kPointerSize)); |
1482 __ lw(scratch1, MemOperand(scratch1, 0)); | 1482 __ lw(scratch1, MemOperand(scratch1, 0)); |
1483 __ Xor(scratch1, scratch1, Operand(scratch2)); | 1483 __ Xor(scratch1, scratch1, Operand(scratch2)); |
1484 __ And(scratch1, scratch1, Operand(mask)); | 1484 __ And(scratch1, scratch1, Operand(mask)); |
1485 | 1485 |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1729 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) | 1729 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
1730 // tagged as a small integer. | 1730 // tagged as a small integer. |
1731 __ InvokeBuiltin(native, JUMP_FUNCTION); | 1731 __ InvokeBuiltin(native, JUMP_FUNCTION); |
1732 } | 1732 } |
1733 | 1733 |
1734 | 1734 |
1735 // This stub does not handle the inlined cases (Smis, Booleans, undefined). | 1735 // This stub does not handle the inlined cases (Smis, Booleans, undefined). |
1736 // The stub returns zero for false, and a non-zero value for true. | 1736 // The stub returns zero for false, and a non-zero value for true. |
1737 void ToBooleanStub::Generate(MacroAssembler* masm) { | 1737 void ToBooleanStub::Generate(MacroAssembler* masm) { |
1738 // This stub uses FPU instructions. | 1738 // This stub uses FPU instructions. |
1739 ASSERT(CpuFeatures::IsEnabled(FPU)); | 1739 CpuFeatures::Scope scope(FPU); |
1740 | 1740 |
1741 Label false_result; | 1741 Label false_result; |
1742 Label not_heap_number; | 1742 Label not_heap_number; |
1743 Register scratch0 = t5.is(tos_) ? t3 : t5; | 1743 Register scratch0 = t5.is(tos_) ? t3 : t5; |
1744 | 1744 |
| 1745 // undefined -> false |
| 1746 __ LoadRoot(scratch0, Heap::kUndefinedValueRootIndex); |
| 1747 __ Branch(&false_result, eq, tos_, Operand(scratch0)); |
| 1748 |
| 1749 // Boolean -> its value |
| 1750 __ LoadRoot(scratch0, Heap::kFalseValueRootIndex); |
| 1751 __ Branch(&false_result, eq, tos_, Operand(scratch0)); |
| 1752 __ LoadRoot(scratch0, Heap::kTrueValueRootIndex); |
| 1753 // "tos_" is a register and contains a non-zero value. Hence we implicitly |
| 1754 // return true if the equal condition is satisfied. |
| 1755 __ Ret(eq, tos_, Operand(scratch0)); |
| 1756 |
| 1757 // Smis: 0 -> false, all other -> true |
| 1758 __ And(scratch0, tos_, tos_); |
| 1759 __ Branch(&false_result, eq, scratch0, Operand(zero_reg)); |
| 1760 __ And(scratch0, tos_, Operand(kSmiTagMask)); |
| 1761 // "tos_" is a register and contains a non-zero value. Hence we implicitly |
| 1762 // return true if the not equal condition is satisfied. |
| 1763 __ Ret(eq, scratch0, Operand(zero_reg)); |
| 1764 |
| 1765 // 'null' -> false |
1745 __ LoadRoot(scratch0, Heap::kNullValueRootIndex); | 1766 __ LoadRoot(scratch0, Heap::kNullValueRootIndex); |
1746 __ Branch(&false_result, eq, tos_, Operand(scratch0)); | 1767 __ Branch(&false_result, eq, tos_, Operand(scratch0)); |
1747 | 1768 |
1748 // HeapNumber => false if +0, -0, or NaN. | 1769 // HeapNumber => false if +0, -0, or NaN. |
1749 __ lw(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset)); | 1770 __ lw(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset)); |
1750 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); | 1771 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); |
1751 __ Branch(¬_heap_number, ne, scratch0, Operand(at)); | 1772 __ Branch(¬_heap_number, ne, scratch0, Operand(at)); |
1752 | 1773 |
1753 __ Subu(at, tos_, Operand(kHeapObjectTag)); | 1774 __ ldc1(f12, FieldMemOperand(tos_, HeapNumber::kValueOffset)); |
1754 __ ldc1(f12, MemOperand(at, HeapNumber::kValueOffset)); | |
1755 __ fcmp(f12, 0.0, UEQ); | 1775 __ fcmp(f12, 0.0, UEQ); |
1756 | 1776 |
1757 // "tos_" is a register, and contains a non zero value by default. | 1777 // "tos_" is a register, and contains a non zero value by default. |
1758 // Hence we only need to overwrite "tos_" with zero to return false for | 1778 // Hence we only need to overwrite "tos_" with zero to return false for |
1759 // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true. | 1779 // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true. |
1760 __ movt(tos_, zero_reg); | 1780 __ movt(tos_, zero_reg); |
1761 __ Ret(); | 1781 __ Ret(); |
1762 | 1782 |
1763 __ bind(¬_heap_number); | 1783 __ bind(¬_heap_number); |
1764 | 1784 |
1765 // Check if the value is 'null'. | |
1766 // 'null' => false. | |
1767 __ LoadRoot(at, Heap::kNullValueRootIndex); | |
1768 __ Branch(&false_result, eq, tos_, Operand(at)); | |
1769 | |
1770 // It can be an undetectable object. | 1785 // It can be an undetectable object. |
1771 // Undetectable => false. | 1786 // Undetectable => false. |
1772 __ lw(at, FieldMemOperand(tos_, HeapObject::kMapOffset)); | 1787 __ lw(at, FieldMemOperand(tos_, HeapObject::kMapOffset)); |
1773 __ lbu(scratch0, FieldMemOperand(at, Map::kBitFieldOffset)); | 1788 __ lbu(scratch0, FieldMemOperand(at, Map::kBitFieldOffset)); |
1774 __ And(scratch0, scratch0, Operand(1 << Map::kIsUndetectable)); | 1789 __ And(scratch0, scratch0, Operand(1 << Map::kIsUndetectable)); |
1775 __ Branch(&false_result, eq, scratch0, Operand(1 << Map::kIsUndetectable)); | 1790 __ Branch(&false_result, eq, scratch0, Operand(1 << Map::kIsUndetectable)); |
1776 | 1791 |
1777 // JavaScript object => true. | 1792 // JavaScript object => true. |
1778 __ lw(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset)); | 1793 __ lw(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset)); |
1779 __ lbu(scratch0, FieldMemOperand(scratch0, Map::kInstanceTypeOffset)); | 1794 __ lbu(scratch0, FieldMemOperand(scratch0, Map::kInstanceTypeOffset)); |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1937 case Token::BIT_NOT: | 1952 case Token::BIT_NOT: |
1938 GenerateHeapNumberStubBitNot(masm); | 1953 GenerateHeapNumberStubBitNot(masm); |
1939 break; | 1954 break; |
1940 default: | 1955 default: |
1941 UNREACHABLE(); | 1956 UNREACHABLE(); |
1942 } | 1957 } |
1943 } | 1958 } |
1944 | 1959 |
1945 | 1960 |
1946 void TypeRecordingUnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { | 1961 void TypeRecordingUnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { |
1947 Label non_smi, slow; | 1962 Label non_smi, slow, call_builtin; |
1948 GenerateSmiCodeSub(masm, &non_smi, &slow); | 1963 GenerateSmiCodeSub(masm, &non_smi, &call_builtin); |
1949 __ bind(&non_smi); | 1964 __ bind(&non_smi); |
1950 GenerateHeapNumberCodeSub(masm, &slow); | 1965 GenerateHeapNumberCodeSub(masm, &slow); |
1951 __ bind(&slow); | 1966 __ bind(&slow); |
1952 GenerateTypeTransition(masm); | 1967 GenerateTypeTransition(masm); |
| 1968 __ bind(&call_builtin); |
| 1969 GenerateGenericCodeFallback(masm); |
1953 } | 1970 } |
1954 | 1971 |
1955 | 1972 |
1956 void TypeRecordingUnaryOpStub::GenerateHeapNumberStubBitNot( | 1973 void TypeRecordingUnaryOpStub::GenerateHeapNumberStubBitNot( |
1957 MacroAssembler* masm) { | 1974 MacroAssembler* masm) { |
1958 Label non_smi, slow; | 1975 Label non_smi, slow; |
1959 GenerateSmiCodeBitNot(masm, &non_smi); | 1976 GenerateSmiCodeBitNot(masm, &non_smi); |
1960 __ bind(&non_smi); | 1977 __ bind(&non_smi); |
1961 GenerateHeapNumberCodeBitNot(masm, &slow); | 1978 GenerateHeapNumberCodeBitNot(masm, &slow); |
1962 __ bind(&slow); | 1979 __ bind(&slow); |
(...skipping 1215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3178 __ mfc1(a2, f4); | 3195 __ mfc1(a2, f4); |
3179 __ mfc1(a3, f5); | 3196 __ mfc1(a3, f5); |
3180 __ Branch(&loaded); | 3197 __ Branch(&loaded); |
3181 | 3198 |
3182 __ bind(&input_not_smi); | 3199 __ bind(&input_not_smi); |
3183 // Check if input is a HeapNumber. | 3200 // Check if input is a HeapNumber. |
3184 __ CheckMap(a0, | 3201 __ CheckMap(a0, |
3185 a1, | 3202 a1, |
3186 Heap::kHeapNumberMapRootIndex, | 3203 Heap::kHeapNumberMapRootIndex, |
3187 &calculate, | 3204 &calculate, |
3188 true); | 3205 DONT_DO_SMI_CHECK); |
3189 // Input is a HeapNumber. Store the | 3206 // Input is a HeapNumber. Store the |
3190 // low and high words into a2, a3. | 3207 // low and high words into a2, a3. |
3191 __ lw(a2, FieldMemOperand(a0, HeapNumber::kValueOffset)); | 3208 __ lw(a2, FieldMemOperand(a0, HeapNumber::kValueOffset)); |
3192 __ lw(a3, FieldMemOperand(a0, HeapNumber::kValueOffset + 4)); | 3209 __ lw(a3, FieldMemOperand(a0, HeapNumber::kValueOffset + 4)); |
3193 } else { | 3210 } else { |
3194 // Input is untagged double in f4. Output goes to f4. | 3211 // Input is untagged double in f4. Output goes to f4. |
3195 __ mfc1(a2, f4); | 3212 __ mfc1(a2, f4); |
3196 __ mfc1(a3, f5); | 3213 __ mfc1(a3, f5); |
3197 } | 3214 } |
3198 __ bind(&loaded); | 3215 __ bind(&loaded); |
(...skipping 558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3757 // caller fp | | 3774 // caller fp | |
3758 // function slot | entry frame | 3775 // function slot | entry frame |
3759 // context slot | | 3776 // context slot | |
3760 // bad fp (0xff...f) | | 3777 // bad fp (0xff...f) | |
3761 // callee saved registers + ra | 3778 // callee saved registers + ra |
3762 // 4 args slots | 3779 // 4 args slots |
3763 // args | 3780 // args |
3764 | 3781 |
3765 #ifdef ENABLE_LOGGING_AND_PROFILING | 3782 #ifdef ENABLE_LOGGING_AND_PROFILING |
3766 // If this is the outermost JS call, set js_entry_sp value. | 3783 // If this is the outermost JS call, set js_entry_sp value. |
| 3784 Label non_outermost_js; |
3767 ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, | 3785 ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, |
3768 masm->isolate()); | 3786 masm->isolate()); |
3769 __ li(t1, Operand(ExternalReference(js_entry_sp))); | 3787 __ li(t1, Operand(ExternalReference(js_entry_sp))); |
3770 __ lw(t2, MemOperand(t1)); | 3788 __ lw(t2, MemOperand(t1)); |
3771 { | 3789 __ Branch(&non_outermost_js, ne, t2, Operand(zero_reg)); |
3772 Label skip; | 3790 __ sw(fp, MemOperand(t1)); |
3773 __ Branch(&skip, ne, t2, Operand(zero_reg)); | 3791 __ li(t0, Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); |
3774 __ sw(fp, MemOperand(t1)); | 3792 Label cont; |
3775 __ bind(&skip); | 3793 __ b(&cont); |
3776 } | 3794 __ nop(); // Branch delay slot nop. |
| 3795 __ bind(&non_outermost_js); |
| 3796 __ li(t0, Operand(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME))); |
| 3797 __ bind(&cont); |
| 3798 __ push(t0); |
3777 #endif | 3799 #endif |
3778 | 3800 |
3779 // Call a faked try-block that does the invoke. | 3801 // Call a faked try-block that does the invoke. |
3780 __ bal(&invoke); // bal exposes branch delay slot. | 3802 __ bal(&invoke); // bal exposes branch delay slot. |
3781 __ nop(); // Branch delay slot nop. | 3803 __ nop(); // Branch delay slot nop. |
3782 | 3804 |
3783 // Caught exception: Store result (exception) in the pending | 3805 // Caught exception: Store result (exception) in the pending |
3784 // exception field in the JSEnv and return a failure sentinel. | 3806 // exception field in the JSEnv and return a failure sentinel. |
3785 // Coming in here the fp will be invalid because the PushTryHandler below | 3807 // Coming in here the fp will be invalid because the PushTryHandler below |
3786 // sets it to 0 to signal the existence of the JSEntry frame. | 3808 // sets it to 0 to signal the existence of the JSEntry frame. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3832 } else { | 3854 } else { |
3833 ExternalReference entry(Builtins::kJSEntryTrampoline, masm->isolate()); | 3855 ExternalReference entry(Builtins::kJSEntryTrampoline, masm->isolate()); |
3834 __ li(t0, Operand(entry)); | 3856 __ li(t0, Operand(entry)); |
3835 } | 3857 } |
3836 __ lw(t9, MemOperand(t0)); // Deref address. | 3858 __ lw(t9, MemOperand(t0)); // Deref address. |
3837 | 3859 |
3838 // Call JSEntryTrampoline. | 3860 // Call JSEntryTrampoline. |
3839 __ addiu(t9, t9, Code::kHeaderSize - kHeapObjectTag); | 3861 __ addiu(t9, t9, Code::kHeaderSize - kHeapObjectTag); |
3840 __ Call(t9); | 3862 __ Call(t9); |
3841 | 3863 |
3842 // Unlink this frame from the handler chain. When reading the | 3864 // Unlink this frame from the handler chain. |
3843 // address of the next handler, there is no need to use the address | 3865 __ PopTryHandler(); |
3844 // displacement since the current stack pointer (sp) points directly | |
3845 // to the stack handler. | |
3846 __ lw(t1, MemOperand(sp, StackHandlerConstants::kNextOffset)); | |
3847 __ li(t0, Operand(ExternalReference(Isolate::k_handler_address, | |
3848 masm->isolate()))); | |
3849 __ sw(t1, MemOperand(t0)); | |
3850 | 3866 |
3851 // This restores sp to its position before PushTryHandler. | 3867 __ bind(&exit); // v0 holds result |
3852 __ addiu(sp, sp, StackHandlerConstants::kSize); | 3868 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 3869 // Check if the current stack frame is marked as the outermost JS frame. |
| 3870 Label non_outermost_js_2; |
| 3871 __ pop(t1); |
| 3872 __ Branch(&non_outermost_js_2, ne, t1, |
| 3873 Operand(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); |
| 3874 __ li(t1, Operand(ExternalReference(js_entry_sp))); |
| 3875 __ sw(zero_reg, MemOperand(t1)); |
| 3876 __ bind(&non_outermost_js_2); |
| 3877 #endif |
3853 | 3878 |
3854 #ifdef ENABLE_LOGGING_AND_PROFILING | |
3855 // If current FP value is the same as js_entry_sp value, it means that | |
3856 // the current function is the outermost. | |
3857 __ li(t1, Operand(ExternalReference(js_entry_sp))); | |
3858 __ lw(t2, MemOperand(t1)); | |
3859 { | |
3860 Label skip; | |
3861 __ Branch(&skip, ne, fp, Operand(t2)); | |
3862 __ sw(zero_reg, MemOperand(t1)); | |
3863 __ bind(&skip); | |
3864 } | |
3865 #endif | |
3866 | |
3867 __ bind(&exit); // v0 holds result. | |
3868 // Restore the top frame descriptors from the stack. | 3879 // Restore the top frame descriptors from the stack. |
3869 __ pop(t1); | 3880 __ pop(t1); |
3870 __ li(t0, Operand(ExternalReference(Isolate::k_c_entry_fp_address, | 3881 __ li(t0, Operand(ExternalReference(Isolate::k_c_entry_fp_address, |
3871 masm->isolate()))); | 3882 masm->isolate()))); |
3872 __ sw(t1, MemOperand(t0)); | 3883 __ sw(t1, MemOperand(t0)); |
3873 | 3884 |
3874 // Reset the stack to the callee saved registers. | 3885 // Reset the stack to the callee saved registers. |
3875 __ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset); | 3886 __ addiu(sp, sp, -EntryFrameConstants::kCallerFPOffset); |
3876 | 3887 |
3877 // Restore callee saved registers from the stack. | 3888 // Restore callee saved registers from the stack. |
(...skipping 961 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4839 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { | 4850 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
4840 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); | 4851 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); |
4841 | 4852 |
4842 // Index is not a smi. | 4853 // Index is not a smi. |
4843 __ bind(&index_not_smi_); | 4854 __ bind(&index_not_smi_); |
4844 // If index is a heap number, try converting it to an integer. | 4855 // If index is a heap number, try converting it to an integer. |
4845 __ CheckMap(index_, | 4856 __ CheckMap(index_, |
4846 scratch_, | 4857 scratch_, |
4847 Heap::kHeapNumberMapRootIndex, | 4858 Heap::kHeapNumberMapRootIndex, |
4848 index_not_number_, | 4859 index_not_number_, |
4849 true); | 4860 DONT_DO_SMI_CHECK); |
4850 call_helper.BeforeCall(masm); | 4861 call_helper.BeforeCall(masm); |
4851 // Consumed by runtime conversion function: | 4862 // Consumed by runtime conversion function: |
4852 __ Push(object_, index_, index_); | 4863 __ Push(object_, index_, index_); |
4853 if (index_flags_ == STRING_INDEX_IS_NUMBER) { | 4864 if (index_flags_ == STRING_INDEX_IS_NUMBER) { |
4854 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); | 4865 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); |
4855 } else { | 4866 } else { |
4856 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); | 4867 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); |
4857 // NumberToSmi discards numbers that are not exact integers. | 4868 // NumberToSmi discards numbers that are not exact integers. |
4858 __ CallRuntime(Runtime::kNumberToSmi, 1); | 4869 __ CallRuntime(Runtime::kNumberToSmi, 1); |
4859 } | 4870 } |
(...skipping 1746 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6606 __ mov(result, zero_reg); | 6617 __ mov(result, zero_reg); |
6607 __ Ret(); | 6618 __ Ret(); |
6608 } | 6619 } |
6609 | 6620 |
6610 | 6621 |
6611 #undef __ | 6622 #undef __ |
6612 | 6623 |
6613 } } // namespace v8::internal | 6624 } } // namespace v8::internal |
6614 | 6625 |
6615 #endif // V8_TARGET_ARCH_MIPS | 6626 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |