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 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 #ifdef DEBUG | 332 #ifdef DEBUG |
333 // Check that the size of the code used for returning is large enough | 333 // Check that the size of the code used for returning is large enough |
334 // for the debugger's requirements. | 334 // for the debugger's requirements. |
335 ASSERT(Assembler::kJSReturnSequenceInstructions <= | 335 ASSERT(Assembler::kJSReturnSequenceInstructions <= |
336 masm_->InstructionsGeneratedSince(&check_exit_codesize)); | 336 masm_->InstructionsGeneratedSince(&check_exit_codesize)); |
337 #endif | 337 #endif |
338 } | 338 } |
339 } | 339 } |
340 | 340 |
341 | 341 |
342 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( | |
343 Token::Value op, Expression* left, Expression* right) { | |
344 ASSERT(ShouldInlineSmiCase(op)); | |
345 if (op == Token::DIV || op == Token::MOD || op == Token::MUL) { | |
346 // We never generate inlined constant smi operations for these. | |
347 return kNoConstants; | |
348 } else if (right->IsSmiLiteral()) { | |
349 return kRightConstant; | |
350 } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) { | |
351 // Don't inline shifts with constant left hand side. | |
352 return kLeftConstant; | |
353 } else { | |
354 return kNoConstants; | |
355 } | |
356 } | |
357 | |
358 | |
359 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { | 342 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { |
360 } | 343 } |
361 | 344 |
362 | 345 |
363 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { | 346 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { |
364 codegen()->Move(result_register(), slot); | 347 codegen()->Move(result_register(), slot); |
365 } | 348 } |
366 | 349 |
367 | 350 |
368 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { | 351 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { |
(...skipping 1258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1627 } | 1610 } |
1628 } | 1611 } |
1629 | 1612 |
1630 // For property compound assignments we need another deoptimization | 1613 // For property compound assignments we need another deoptimization |
1631 // point after the property load. | 1614 // point after the property load. |
1632 if (property != NULL) { | 1615 if (property != NULL) { |
1633 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); | 1616 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); |
1634 } | 1617 } |
1635 | 1618 |
1636 Token::Value op = expr->binary_op(); | 1619 Token::Value op = expr->binary_op(); |
1637 ConstantOperand constant = ShouldInlineSmiCase(op) | 1620 __ push(r0); // Left operand goes on the stack. |
1638 ? GetConstantOperand(op, expr->target(), expr->value()) | 1621 VisitForAccumulatorValue(expr->value()); |
1639 : kNoConstants; | |
1640 ASSERT(constant == kRightConstant || constant == kNoConstants); | |
1641 if (constant == kNoConstants) { | |
1642 __ push(r0); // Left operand goes on the stack. | |
1643 VisitForAccumulatorValue(expr->value()); | |
1644 } | |
1645 | 1622 |
1646 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1623 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
1647 ? OVERWRITE_RIGHT | 1624 ? OVERWRITE_RIGHT |
1648 : NO_OVERWRITE; | 1625 : NO_OVERWRITE; |
1649 SetSourcePosition(expr->position() + 1); | 1626 SetSourcePosition(expr->position() + 1); |
1650 AccumulatorValueContext context(this); | 1627 AccumulatorValueContext context(this); |
1651 if (ShouldInlineSmiCase(op)) { | 1628 if (ShouldInlineSmiCase(op)) { |
1652 EmitInlineSmiBinaryOp(expr, | 1629 EmitInlineSmiBinaryOp(expr, |
1653 op, | 1630 op, |
1654 mode, | 1631 mode, |
1655 expr->target(), | 1632 expr->target(), |
1656 expr->value(), | 1633 expr->value()); |
1657 constant); | |
1658 } else { | 1634 } else { |
1659 EmitBinaryOp(op, mode); | 1635 EmitBinaryOp(op, mode); |
1660 } | 1636 } |
1661 | 1637 |
1662 // Deoptimization point in case the binary operation may have side effects. | 1638 // Deoptimization point in case the binary operation may have side effects. |
1663 PrepareForBailout(expr->binary_operation(), TOS_REG); | 1639 PrepareForBailout(expr->binary_operation(), TOS_REG); |
1664 } else { | 1640 } else { |
1665 VisitForAccumulatorValue(expr->value()); | 1641 VisitForAccumulatorValue(expr->value()); |
1666 } | 1642 } |
1667 | 1643 |
(...skipping 29 matching lines...) Expand all Loading... |
1697 | 1673 |
1698 | 1674 |
1699 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1675 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
1700 SetSourcePosition(prop->position()); | 1676 SetSourcePosition(prop->position()); |
1701 // Call keyed load IC. It has arguments key and receiver in r0 and r1. | 1677 // Call keyed load IC. It has arguments key and receiver in r0 and r1. |
1702 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1678 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1703 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1679 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
1704 } | 1680 } |
1705 | 1681 |
1706 | 1682 |
1707 void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr, | |
1708 OverwriteMode mode, | |
1709 bool left_is_constant_smi, | |
1710 Smi* value) { | |
1711 Label call_stub, done; | |
1712 // Optimistically add smi value with unknown object. If result overflows or is | |
1713 // not a smi then we had either a smi overflow or added a smi with a tagged | |
1714 // pointer. | |
1715 __ mov(r1, Operand(value)); | |
1716 __ add(r2, r0, r1, SetCC); | |
1717 __ b(vs, &call_stub); | |
1718 JumpPatchSite patch_site(masm_); | |
1719 patch_site.EmitJumpIfNotSmi(r2, &call_stub); | |
1720 __ mov(r0, r2); | |
1721 __ b(&done); | |
1722 | |
1723 // Call the shared stub. | |
1724 __ bind(&call_stub); | |
1725 if (!left_is_constant_smi) { | |
1726 __ Swap(r0, r1, r2); | |
1727 } | |
1728 TypeRecordingBinaryOpStub stub(Token::ADD, mode); | |
1729 EmitCallIC(stub.GetCode(), &patch_site); | |
1730 | |
1731 __ bind(&done); | |
1732 context()->Plug(r0); | |
1733 } | |
1734 | |
1735 | |
1736 void FullCodeGenerator::EmitConstantSmiSub(Expression* expr, | |
1737 OverwriteMode mode, | |
1738 bool left_is_constant_smi, | |
1739 Smi* value) { | |
1740 Label call_stub, done; | |
1741 // Optimistically subtract smi value and unknown object. If result overflows | |
1742 // or is not a smi then we had either a smi overflow or subtraction between a | |
1743 // smi and a tagged pointer. | |
1744 __ mov(r1, Operand(value)); | |
1745 if (left_is_constant_smi) { | |
1746 __ sub(r2, r1, r0, SetCC); | |
1747 } else { | |
1748 __ sub(r2, r0, r1, SetCC); | |
1749 } | |
1750 __ b(vs, &call_stub); | |
1751 JumpPatchSite patch_site(masm_); | |
1752 patch_site.EmitJumpIfNotSmi(r2, &call_stub); | |
1753 __ mov(r0, r2); | |
1754 __ b(&done); | |
1755 | |
1756 // Call the shared stub. | |
1757 __ bind(&call_stub); | |
1758 if (!left_is_constant_smi) { | |
1759 __ Swap(r0, r1, r2); | |
1760 } | |
1761 TypeRecordingBinaryOpStub stub(Token::SUB, mode); | |
1762 EmitCallIC(stub.GetCode(), &patch_site); | |
1763 | |
1764 __ bind(&done); | |
1765 context()->Plug(r0); | |
1766 } | |
1767 | |
1768 | |
1769 void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr, | |
1770 Token::Value op, | |
1771 OverwriteMode mode, | |
1772 Smi* value) { | |
1773 Label call_stub, smi_case, done; | |
1774 int shift_value = value->value() & 0x1f; | |
1775 | |
1776 JumpPatchSite patch_site(masm_); | |
1777 patch_site.EmitJumpIfSmi(r0, &smi_case); | |
1778 | |
1779 // Call stub. | |
1780 __ bind(&call_stub); | |
1781 __ mov(r1, r0); | |
1782 __ mov(r0, Operand(value)); | |
1783 TypeRecordingBinaryOpStub stub(op, mode); | |
1784 EmitCallIC(stub.GetCode(), &patch_site); | |
1785 __ b(&done); | |
1786 | |
1787 // Smi case. | |
1788 __ bind(&smi_case); | |
1789 switch (op) { | |
1790 case Token::SHL: | |
1791 if (shift_value != 0) { | |
1792 __ mov(r1, r0); | |
1793 if (shift_value > 1) { | |
1794 __ mov(r1, Operand(r1, LSL, shift_value - 1)); | |
1795 } | |
1796 // Convert int result to smi, checking that it is in int range. | |
1797 __ SmiTag(r1, SetCC); | |
1798 __ b(vs, &call_stub); | |
1799 __ mov(r0, r1); // Put result back into r0. | |
1800 } | |
1801 break; | |
1802 case Token::SAR: | |
1803 if (shift_value != 0) { | |
1804 __ mov(r0, Operand(r0, ASR, shift_value)); | |
1805 __ bic(r0, r0, Operand(kSmiTagMask)); | |
1806 } | |
1807 break; | |
1808 case Token::SHR: | |
1809 // SHR must return a positive value. When shifting by 0 or 1 we need to | |
1810 // check that smi tagging the result will not create a negative value. | |
1811 if (shift_value < 2) { | |
1812 __ mov(r2, Operand(shift_value)); | |
1813 __ SmiUntag(r1, r0); | |
1814 if (shift_value != 0) { | |
1815 __ mov(r1, Operand(r1, LSR, shift_value)); | |
1816 } | |
1817 __ tst(r1, Operand(0xc0000000)); | |
1818 __ b(ne, &call_stub); | |
1819 __ SmiTag(r0, r1); // result in r0. | |
1820 } else { | |
1821 __ SmiUntag(r0); | |
1822 __ mov(r0, Operand(r0, LSR, shift_value)); | |
1823 __ SmiTag(r0); | |
1824 } | |
1825 break; | |
1826 default: | |
1827 UNREACHABLE(); | |
1828 } | |
1829 | |
1830 __ bind(&done); | |
1831 context()->Plug(r0); | |
1832 } | |
1833 | |
1834 | |
1835 void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr, | |
1836 Token::Value op, | |
1837 OverwriteMode mode, | |
1838 Smi* value) { | |
1839 Label smi_case, done; | |
1840 | |
1841 JumpPatchSite patch_site(masm_); | |
1842 patch_site.EmitJumpIfSmi(r0, &smi_case); | |
1843 | |
1844 // The order of the arguments does not matter for bit-ops with a | |
1845 // constant operand. | |
1846 __ mov(r1, Operand(value)); | |
1847 TypeRecordingBinaryOpStub stub(op, mode); | |
1848 EmitCallIC(stub.GetCode(), &patch_site); | |
1849 __ jmp(&done); | |
1850 | |
1851 // Smi case. | |
1852 __ bind(&smi_case); | |
1853 __ mov(r1, Operand(value)); | |
1854 switch (op) { | |
1855 case Token::BIT_OR: | |
1856 __ orr(r0, r0, Operand(r1)); | |
1857 break; | |
1858 case Token::BIT_XOR: | |
1859 __ eor(r0, r0, Operand(r1)); | |
1860 break; | |
1861 case Token::BIT_AND: | |
1862 __ and_(r0, r0, Operand(r1)); | |
1863 break; | |
1864 default: | |
1865 UNREACHABLE(); | |
1866 } | |
1867 | |
1868 __ bind(&done); | |
1869 context()->Plug(r0); | |
1870 } | |
1871 | |
1872 | |
1873 void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr, | |
1874 Token::Value op, | |
1875 OverwriteMode mode, | |
1876 bool left_is_constant_smi, | |
1877 Smi* value) { | |
1878 switch (op) { | |
1879 case Token::BIT_OR: | |
1880 case Token::BIT_XOR: | |
1881 case Token::BIT_AND: | |
1882 EmitConstantSmiBitOp(expr, op, mode, value); | |
1883 break; | |
1884 case Token::SHL: | |
1885 case Token::SAR: | |
1886 case Token::SHR: | |
1887 ASSERT(!left_is_constant_smi); | |
1888 EmitConstantSmiShiftOp(expr, op, mode, value); | |
1889 break; | |
1890 case Token::ADD: | |
1891 EmitConstantSmiAdd(expr, mode, left_is_constant_smi, value); | |
1892 break; | |
1893 case Token::SUB: | |
1894 EmitConstantSmiSub(expr, mode, left_is_constant_smi, value); | |
1895 break; | |
1896 default: | |
1897 UNREACHABLE(); | |
1898 } | |
1899 } | |
1900 | |
1901 | |
1902 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, | 1683 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, |
1903 Token::Value op, | 1684 Token::Value op, |
1904 OverwriteMode mode, | 1685 OverwriteMode mode, |
1905 Expression* left_expr, | 1686 Expression* left_expr, |
1906 Expression* right_expr, | 1687 Expression* right_expr) { |
1907 ConstantOperand constant) { | |
1908 if (constant == kRightConstant) { | |
1909 Smi* value = Smi::cast(*right_expr->AsLiteral()->handle()); | |
1910 EmitConstantSmiBinaryOp(expr, op, mode, false, value); | |
1911 return; | |
1912 } else if (constant == kLeftConstant) { | |
1913 Smi* value = Smi::cast(*left_expr->AsLiteral()->handle()); | |
1914 EmitConstantSmiBinaryOp(expr, op, mode, true, value); | |
1915 return; | |
1916 } | |
1917 | |
1918 Label done, smi_case, stub_call; | 1688 Label done, smi_case, stub_call; |
1919 | 1689 |
1920 Register scratch1 = r2; | 1690 Register scratch1 = r2; |
1921 Register scratch2 = r3; | 1691 Register scratch2 = r3; |
1922 | 1692 |
1923 // Get the arguments. | 1693 // Get the arguments. |
1924 Register left = r1; | 1694 Register left = r1; |
1925 Register right = r0; | 1695 Register right = r0; |
1926 __ pop(left); | 1696 __ pop(left); |
1927 | 1697 |
(...skipping 2251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4179 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. | 3949 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. |
4180 __ add(pc, r1, Operand(masm_->CodeObject())); | 3950 __ add(pc, r1, Operand(masm_->CodeObject())); |
4181 } | 3951 } |
4182 | 3952 |
4183 | 3953 |
4184 #undef __ | 3954 #undef __ |
4185 | 3955 |
4186 } } // namespace v8::internal | 3956 } } // namespace v8::internal |
4187 | 3957 |
4188 #endif // V8_TARGET_ARCH_ARM | 3958 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |