OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 } | 220 } |
221 | 221 |
222 | 222 |
223 void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( | 223 void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( |
224 Isolate* isolate, | 224 Isolate* isolate, |
225 CodeStubInterfaceDescriptor* descriptor) { | 225 CodeStubInterfaceDescriptor* descriptor) { |
226 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1); | 226 InitializeInternalArrayConstructorDescriptor(isolate, descriptor, -1); |
227 } | 227 } |
228 | 228 |
229 | 229 |
| 230 void UnaryOpStub::InitializeInterfaceDescriptor( |
| 231 Isolate* isolate, |
| 232 CodeStubInterfaceDescriptor* descriptor) { |
| 233 static Register registers[] = { a0 }; |
| 234 descriptor->register_param_count_ = 1; |
| 235 descriptor->register_params_ = registers; |
| 236 descriptor->deoptimization_handler_ = |
| 237 FUNCTION_ADDR(UnaryOpIC_Miss); |
| 238 } |
| 239 |
| 240 |
230 #define __ ACCESS_MASM(masm) | 241 #define __ ACCESS_MASM(masm) |
231 | 242 |
| 243 |
232 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 244 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
233 Label* slow, | 245 Label* slow, |
234 Condition cc); | 246 Condition cc); |
235 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 247 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
236 Register lhs, | 248 Register lhs, |
237 Register rhs, | 249 Register rhs, |
238 Label* rhs_not_nan, | 250 Label* rhs_not_nan, |
239 Label* slow, | 251 Label* slow, |
240 bool strict); | 252 bool strict); |
241 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 253 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
(...skipping 1337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1579 argument_count); | 1591 argument_count); |
1580 if (save_doubles_ == kSaveFPRegs) { | 1592 if (save_doubles_ == kSaveFPRegs) { |
1581 __ MultiPopFPU(kCallerSavedFPU); | 1593 __ MultiPopFPU(kCallerSavedFPU); |
1582 } | 1594 } |
1583 | 1595 |
1584 __ MultiPop(kJSCallerSaved | ra.bit()); | 1596 __ MultiPop(kJSCallerSaved | ra.bit()); |
1585 __ Ret(); | 1597 __ Ret(); |
1586 } | 1598 } |
1587 | 1599 |
1588 | 1600 |
1589 void UnaryOpStub::PrintName(StringStream* stream) { | |
1590 const char* op_name = Token::Name(op_); | |
1591 const char* overwrite_name = NULL; // Make g++ happy. | |
1592 switch (mode_) { | |
1593 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | |
1594 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; | |
1595 } | |
1596 stream->Add("UnaryOpStub_%s_%s_%s", | |
1597 op_name, | |
1598 overwrite_name, | |
1599 UnaryOpIC::GetName(operand_type_)); | |
1600 } | |
1601 | |
1602 | |
1603 // TODO(svenpanne): Use virtual functions instead of switch. | |
1604 void UnaryOpStub::Generate(MacroAssembler* masm) { | |
1605 switch (operand_type_) { | |
1606 case UnaryOpIC::UNINITIALIZED: | |
1607 GenerateTypeTransition(masm); | |
1608 break; | |
1609 case UnaryOpIC::SMI: | |
1610 GenerateSmiStub(masm); | |
1611 break; | |
1612 case UnaryOpIC::NUMBER: | |
1613 GenerateNumberStub(masm); | |
1614 break; | |
1615 case UnaryOpIC::GENERIC: | |
1616 GenerateGenericStub(masm); | |
1617 break; | |
1618 } | |
1619 } | |
1620 | |
1621 | |
1622 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | |
1623 // Argument is in a0 and v0 at this point, so we can overwrite a0. | |
1624 __ li(a2, Operand(Smi::FromInt(op_))); | |
1625 __ li(a1, Operand(Smi::FromInt(mode_))); | |
1626 __ li(a0, Operand(Smi::FromInt(operand_type_))); | |
1627 __ Push(v0, a2, a1, a0); | |
1628 | |
1629 __ TailCallExternalReference( | |
1630 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); | |
1631 } | |
1632 | |
1633 | |
1634 // TODO(svenpanne): Use virtual functions instead of switch. | |
1635 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | |
1636 switch (op_) { | |
1637 case Token::SUB: | |
1638 GenerateSmiStubSub(masm); | |
1639 break; | |
1640 case Token::BIT_NOT: | |
1641 GenerateSmiStubBitNot(masm); | |
1642 break; | |
1643 default: | |
1644 UNREACHABLE(); | |
1645 } | |
1646 } | |
1647 | |
1648 | |
1649 void UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { | |
1650 Label non_smi, slow; | |
1651 GenerateSmiCodeSub(masm, &non_smi, &slow); | |
1652 __ bind(&non_smi); | |
1653 __ bind(&slow); | |
1654 GenerateTypeTransition(masm); | |
1655 } | |
1656 | |
1657 | |
1658 void UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { | |
1659 Label non_smi; | |
1660 GenerateSmiCodeBitNot(masm, &non_smi); | |
1661 __ bind(&non_smi); | |
1662 GenerateTypeTransition(masm); | |
1663 } | |
1664 | |
1665 | |
1666 void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, | |
1667 Label* non_smi, | |
1668 Label* slow) { | |
1669 __ JumpIfNotSmi(a0, non_smi); | |
1670 | |
1671 // The result of negating zero or the smallest negative smi is not a smi. | |
1672 __ And(t0, a0, ~0x80000000); | |
1673 __ Branch(slow, eq, t0, Operand(zero_reg)); | |
1674 | |
1675 // Return '0 - value'. | |
1676 __ Ret(USE_DELAY_SLOT); | |
1677 __ subu(v0, zero_reg, a0); | |
1678 } | |
1679 | |
1680 | |
1681 void UnaryOpStub::GenerateSmiCodeBitNot(MacroAssembler* masm, | |
1682 Label* non_smi) { | |
1683 __ JumpIfNotSmi(a0, non_smi); | |
1684 | |
1685 // Flip bits and revert inverted smi-tag. | |
1686 __ Neg(v0, a0); | |
1687 __ And(v0, v0, ~kSmiTagMask); | |
1688 __ Ret(); | |
1689 } | |
1690 | |
1691 | |
1692 // TODO(svenpanne): Use virtual functions instead of switch. | |
1693 void UnaryOpStub::GenerateNumberStub(MacroAssembler* masm) { | |
1694 switch (op_) { | |
1695 case Token::SUB: | |
1696 GenerateNumberStubSub(masm); | |
1697 break; | |
1698 case Token::BIT_NOT: | |
1699 GenerateNumberStubBitNot(masm); | |
1700 break; | |
1701 default: | |
1702 UNREACHABLE(); | |
1703 } | |
1704 } | |
1705 | |
1706 | |
1707 void UnaryOpStub::GenerateNumberStubSub(MacroAssembler* masm) { | |
1708 Label non_smi, slow, call_builtin; | |
1709 GenerateSmiCodeSub(masm, &non_smi, &call_builtin); | |
1710 __ bind(&non_smi); | |
1711 GenerateHeapNumberCodeSub(masm, &slow); | |
1712 __ bind(&slow); | |
1713 GenerateTypeTransition(masm); | |
1714 __ bind(&call_builtin); | |
1715 GenerateGenericCodeFallback(masm); | |
1716 } | |
1717 | |
1718 | |
1719 void UnaryOpStub::GenerateNumberStubBitNot(MacroAssembler* masm) { | |
1720 Label non_smi, slow; | |
1721 GenerateSmiCodeBitNot(masm, &non_smi); | |
1722 __ bind(&non_smi); | |
1723 GenerateHeapNumberCodeBitNot(masm, &slow); | |
1724 __ bind(&slow); | |
1725 GenerateTypeTransition(masm); | |
1726 } | |
1727 | |
1728 | |
1729 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, | |
1730 Label* slow) { | |
1731 EmitCheckForHeapNumber(masm, a0, a1, t2, slow); | |
1732 // a0 is a heap number. Get a new heap number in a1. | |
1733 if (mode_ == UNARY_OVERWRITE) { | |
1734 __ lw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); | |
1735 __ Xor(a2, a2, Operand(HeapNumber::kSignMask)); // Flip sign. | |
1736 __ Ret(USE_DELAY_SLOT); | |
1737 __ sw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); | |
1738 } else { | |
1739 Label slow_allocate_heapnumber, heapnumber_allocated; | |
1740 __ AllocateHeapNumber(a1, a2, a3, t2, &slow_allocate_heapnumber); | |
1741 __ jmp(&heapnumber_allocated); | |
1742 | |
1743 __ bind(&slow_allocate_heapnumber); | |
1744 { | |
1745 FrameScope scope(masm, StackFrame::INTERNAL); | |
1746 __ push(a0); | |
1747 __ CallRuntime(Runtime::kNumberAlloc, 0); | |
1748 __ mov(a1, v0); | |
1749 __ pop(a0); | |
1750 } | |
1751 | |
1752 __ bind(&heapnumber_allocated); | |
1753 __ lw(a3, FieldMemOperand(a0, HeapNumber::kMantissaOffset)); | |
1754 __ lw(a2, FieldMemOperand(a0, HeapNumber::kExponentOffset)); | |
1755 __ sw(a3, FieldMemOperand(a1, HeapNumber::kMantissaOffset)); | |
1756 __ Xor(a2, a2, Operand(HeapNumber::kSignMask)); // Flip sign. | |
1757 __ sw(a2, FieldMemOperand(a1, HeapNumber::kExponentOffset)); | |
1758 __ Ret(USE_DELAY_SLOT); | |
1759 __ mov(v0, a1); | |
1760 } | |
1761 } | |
1762 | |
1763 | |
1764 void UnaryOpStub::GenerateHeapNumberCodeBitNot( | |
1765 MacroAssembler* masm, | |
1766 Label* slow) { | |
1767 Label impossible; | |
1768 | |
1769 EmitCheckForHeapNumber(masm, a0, a1, t2, slow); | |
1770 // Convert the heap number in a0 to an untagged integer in a1. | |
1771 __ ConvertToInt32(a0, a1, a2, a3, f0, slow); | |
1772 | |
1773 // Do the bitwise operation and check if the result fits in a smi. | |
1774 Label try_float; | |
1775 __ Neg(a1, a1); | |
1776 __ Addu(a2, a1, Operand(0x40000000)); | |
1777 __ Branch(&try_float, lt, a2, Operand(zero_reg)); | |
1778 | |
1779 // Tag the result as a smi and we're done. | |
1780 __ Ret(USE_DELAY_SLOT); // SmiTag emits one instruction in delay slot. | |
1781 __ SmiTag(v0, a1); | |
1782 | |
1783 // Try to store the result in a heap number. | |
1784 __ bind(&try_float); | |
1785 if (mode_ == UNARY_NO_OVERWRITE) { | |
1786 Label slow_allocate_heapnumber, heapnumber_allocated; | |
1787 // Allocate a new heap number without zapping v0, which we need if it fails. | |
1788 __ AllocateHeapNumber(a2, a3, t0, t2, &slow_allocate_heapnumber); | |
1789 __ jmp(&heapnumber_allocated); | |
1790 | |
1791 __ bind(&slow_allocate_heapnumber); | |
1792 { | |
1793 FrameScope scope(masm, StackFrame::INTERNAL); | |
1794 __ push(v0); // Push the heap number, not the untagged int32. | |
1795 __ CallRuntime(Runtime::kNumberAlloc, 0); | |
1796 __ mov(a2, v0); // Move the new heap number into a2. | |
1797 // Get the heap number into v0, now that the new heap number is in a2. | |
1798 __ pop(v0); | |
1799 } | |
1800 | |
1801 // Convert the heap number in v0 to an untagged integer in a1. | |
1802 // This can't go slow-case because it's the same number we already | |
1803 // converted once again. | |
1804 __ ConvertToInt32(v0, a1, a3, t0, f0, &impossible); | |
1805 // Negate the result. | |
1806 __ Xor(a1, a1, -1); | |
1807 | |
1808 __ bind(&heapnumber_allocated); | |
1809 __ mov(v0, a2); // Move newly allocated heap number to v0. | |
1810 } | |
1811 | |
1812 // Convert the int32 in a1 to the heap number in v0. a2 is corrupted. | |
1813 __ mtc1(a1, f0); | |
1814 __ cvt_d_w(f0, f0); | |
1815 __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset)); | |
1816 __ Ret(); | |
1817 | |
1818 __ bind(&impossible); | |
1819 if (FLAG_debug_code) { | |
1820 __ stop("Incorrect assumption in bit-not stub"); | |
1821 } | |
1822 } | |
1823 | |
1824 | |
1825 // TODO(svenpanne): Use virtual functions instead of switch. | |
1826 void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { | |
1827 switch (op_) { | |
1828 case Token::SUB: | |
1829 GenerateGenericStubSub(masm); | |
1830 break; | |
1831 case Token::BIT_NOT: | |
1832 GenerateGenericStubBitNot(masm); | |
1833 break; | |
1834 default: | |
1835 UNREACHABLE(); | |
1836 } | |
1837 } | |
1838 | |
1839 | |
1840 void UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { | |
1841 Label non_smi, slow; | |
1842 GenerateSmiCodeSub(masm, &non_smi, &slow); | |
1843 __ bind(&non_smi); | |
1844 GenerateHeapNumberCodeSub(masm, &slow); | |
1845 __ bind(&slow); | |
1846 GenerateGenericCodeFallback(masm); | |
1847 } | |
1848 | |
1849 | |
1850 void UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { | |
1851 Label non_smi, slow; | |
1852 GenerateSmiCodeBitNot(masm, &non_smi); | |
1853 __ bind(&non_smi); | |
1854 GenerateHeapNumberCodeBitNot(masm, &slow); | |
1855 __ bind(&slow); | |
1856 GenerateGenericCodeFallback(masm); | |
1857 } | |
1858 | |
1859 | |
1860 void UnaryOpStub::GenerateGenericCodeFallback( | |
1861 MacroAssembler* masm) { | |
1862 // Handle the slow case by jumping to the JavaScript builtin. | |
1863 __ push(a0); | |
1864 switch (op_) { | |
1865 case Token::SUB: | |
1866 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); | |
1867 break; | |
1868 case Token::BIT_NOT: | |
1869 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); | |
1870 break; | |
1871 default: | |
1872 UNREACHABLE(); | |
1873 } | |
1874 } | |
1875 | |
1876 | |
1877 void BinaryOpStub::Initialize() { | 1601 void BinaryOpStub::Initialize() { |
1878 platform_specific_bit_ = true; // FPU is a base requirement for V8. | 1602 platform_specific_bit_ = true; // FPU is a base requirement for V8. |
1879 } | 1603 } |
1880 | 1604 |
1881 | 1605 |
1882 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 1606 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
1883 Label get_result; | 1607 Label get_result; |
1884 | 1608 |
1885 __ Push(a1, a0); | 1609 __ Push(a1, a0); |
1886 | 1610 |
(...skipping 5964 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7851 __ bind(&fast_elements_case); | 7575 __ bind(&fast_elements_case); |
7852 GenerateCase(masm, FAST_ELEMENTS); | 7576 GenerateCase(masm, FAST_ELEMENTS); |
7853 } | 7577 } |
7854 | 7578 |
7855 | 7579 |
7856 #undef __ | 7580 #undef __ |
7857 | 7581 |
7858 } } // namespace v8::internal | 7582 } } // namespace v8::internal |
7859 | 7583 |
7860 #endif // V8_TARGET_ARCH_MIPS | 7584 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |