| 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 |