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 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 #ifdef ENABLE_DEBUGGER_SUPPORT | 315 #ifdef ENABLE_DEBUGGER_SUPPORT |
316 // Check that the size of the code used for returning is large enough | 316 // Check that the size of the code used for returning is large enough |
317 // for the debugger's requirements. | 317 // for the debugger's requirements. |
318 ASSERT(Assembler::kJSReturnSequenceLength <= | 318 ASSERT(Assembler::kJSReturnSequenceLength <= |
319 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 319 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
320 #endif | 320 #endif |
321 } | 321 } |
322 } | 322 } |
323 | 323 |
324 | 324 |
325 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( | |
326 Token::Value op, Expression* left, Expression* right) { | |
327 ASSERT(ShouldInlineSmiCase(op)); | |
328 if (op == Token::DIV || op == Token::MOD || op == Token::MUL) { | |
329 // We never generate inlined constant smi operations for these. | |
330 return kNoConstants; | |
331 } else if (right->IsSmiLiteral()) { | |
332 return kRightConstant; | |
333 } else if (left->IsSmiLiteral() && !Token::IsShiftOp(op)) { | |
334 // Don't inline shifts with constant left hand side. | |
335 return kLeftConstant; | |
336 } else { | |
337 return kNoConstants; | |
338 } | |
339 } | |
340 | |
341 | |
342 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { | 325 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { |
343 } | 326 } |
344 | 327 |
345 | 328 |
346 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { | 329 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { |
347 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); | 330 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); |
348 __ mov(result_register(), slot_operand); | 331 __ mov(result_register(), slot_operand); |
349 } | 332 } |
350 | 333 |
351 | 334 |
(...skipping 1213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1565 } | 1548 } |
1566 } | 1549 } |
1567 | 1550 |
1568 // For property compound assignments we need another deoptimization | 1551 // For property compound assignments we need another deoptimization |
1569 // point after the property load. | 1552 // point after the property load. |
1570 if (property != NULL) { | 1553 if (property != NULL) { |
1571 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); | 1554 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); |
1572 } | 1555 } |
1573 | 1556 |
1574 Token::Value op = expr->binary_op(); | 1557 Token::Value op = expr->binary_op(); |
1575 ConstantOperand constant = ShouldInlineSmiCase(op) | 1558 __ push(eax); // Left operand goes on the stack. |
1576 ? GetConstantOperand(op, expr->target(), expr->value()) | 1559 VisitForAccumulatorValue(expr->value()); |
1577 : kNoConstants; | |
1578 ASSERT(constant == kRightConstant || constant == kNoConstants); | |
1579 if (constant == kNoConstants) { | |
1580 __ push(eax); // Left operand goes on the stack. | |
1581 VisitForAccumulatorValue(expr->value()); | |
1582 } | |
1583 | 1560 |
1584 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1561 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
1585 ? OVERWRITE_RIGHT | 1562 ? OVERWRITE_RIGHT |
1586 : NO_OVERWRITE; | 1563 : NO_OVERWRITE; |
1587 SetSourcePosition(expr->position() + 1); | 1564 SetSourcePosition(expr->position() + 1); |
1588 AccumulatorValueContext context(this); | 1565 AccumulatorValueContext context(this); |
1589 if (ShouldInlineSmiCase(op)) { | 1566 if (ShouldInlineSmiCase(op)) { |
1590 EmitInlineSmiBinaryOp(expr, | 1567 EmitInlineSmiBinaryOp(expr, |
1591 op, | 1568 op, |
1592 mode, | 1569 mode, |
1593 expr->target(), | 1570 expr->target(), |
1594 expr->value(), | 1571 expr->value()); |
1595 constant); | |
1596 } else { | 1572 } else { |
1597 EmitBinaryOp(op, mode); | 1573 EmitBinaryOp(op, mode); |
1598 } | 1574 } |
1599 | 1575 |
1600 // Deoptimization point in case the binary operation may have side effects. | 1576 // Deoptimization point in case the binary operation may have side effects. |
1601 PrepareForBailout(expr->binary_operation(), TOS_REG); | 1577 PrepareForBailout(expr->binary_operation(), TOS_REG); |
1602 } else { | 1578 } else { |
1603 VisitForAccumulatorValue(expr->value()); | 1579 VisitForAccumulatorValue(expr->value()); |
1604 } | 1580 } |
1605 | 1581 |
(...skipping 27 matching lines...) Expand all Loading... |
1633 } | 1609 } |
1634 | 1610 |
1635 | 1611 |
1636 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1612 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
1637 SetSourcePosition(prop->position()); | 1613 SetSourcePosition(prop->position()); |
1638 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1614 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1639 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1615 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
1640 } | 1616 } |
1641 | 1617 |
1642 | 1618 |
1643 void FullCodeGenerator::EmitConstantSmiAdd(Expression* expr, | |
1644 OverwriteMode mode, | |
1645 bool left_is_constant_smi, | |
1646 Smi* value) { | |
1647 NearLabel call_stub, done; | |
1648 // Optimistically add smi value with unknown object. If result overflows or is | |
1649 // not a smi then we had either a smi overflow or added a smi with a tagged | |
1650 // pointer. | |
1651 __ add(Operand(eax), Immediate(value)); | |
1652 __ j(overflow, &call_stub); | |
1653 JumpPatchSite patch_site(masm_); | |
1654 patch_site.EmitJumpIfSmi(eax, &done); | |
1655 | |
1656 // Undo the optimistic add operation and call the shared stub. | |
1657 __ bind(&call_stub); | |
1658 __ sub(Operand(eax), Immediate(value)); | |
1659 TypeRecordingBinaryOpStub stub(Token::ADD, mode); | |
1660 if (left_is_constant_smi) { | |
1661 __ mov(edx, Immediate(value)); | |
1662 } else { | |
1663 __ mov(edx, eax); | |
1664 __ mov(eax, Immediate(value)); | |
1665 } | |
1666 EmitCallIC(stub.GetCode(), &patch_site); | |
1667 | |
1668 __ bind(&done); | |
1669 context()->Plug(eax); | |
1670 } | |
1671 | |
1672 | |
1673 void FullCodeGenerator::EmitConstantSmiSub(Expression* expr, | |
1674 OverwriteMode mode, | |
1675 bool left_is_constant_smi, | |
1676 Smi* value) { | |
1677 NearLabel call_stub, done; | |
1678 // Optimistically subtract smi value with unknown object. If result overflows | |
1679 // or is not a smi then we had either a smi overflow or added a smi with a | |
1680 // tagged pointer. | |
1681 if (left_is_constant_smi) { | |
1682 __ mov(ecx, eax); | |
1683 __ mov(eax, Immediate(value)); | |
1684 __ sub(Operand(eax), ecx); | |
1685 } else { | |
1686 __ sub(Operand(eax), Immediate(value)); | |
1687 } | |
1688 __ j(overflow, &call_stub); | |
1689 JumpPatchSite patch_site(masm_); | |
1690 patch_site.EmitJumpIfSmi(eax, &done); | |
1691 | |
1692 __ bind(&call_stub); | |
1693 if (left_is_constant_smi) { | |
1694 __ mov(edx, Immediate(value)); | |
1695 __ mov(eax, ecx); | |
1696 } else { | |
1697 __ add(Operand(eax), Immediate(value)); // Undo the subtraction. | |
1698 __ mov(edx, eax); | |
1699 __ mov(eax, Immediate(value)); | |
1700 } | |
1701 TypeRecordingBinaryOpStub stub(Token::SUB, mode); | |
1702 EmitCallIC(stub.GetCode(), &patch_site); | |
1703 | |
1704 __ bind(&done); | |
1705 context()->Plug(eax); | |
1706 } | |
1707 | |
1708 | |
1709 void FullCodeGenerator::EmitConstantSmiShiftOp(Expression* expr, | |
1710 Token::Value op, | |
1711 OverwriteMode mode, | |
1712 Smi* value) { | |
1713 NearLabel call_stub, smi_case, done; | |
1714 int shift_value = value->value() & 0x1f; | |
1715 | |
1716 JumpPatchSite patch_site(masm_); | |
1717 patch_site.EmitJumpIfSmi(eax, &smi_case); | |
1718 | |
1719 // Call stub. | |
1720 __ bind(&call_stub); | |
1721 __ mov(edx, eax); | |
1722 __ mov(eax, Immediate(value)); | |
1723 TypeRecordingBinaryOpStub stub(op, mode); | |
1724 EmitCallIC(stub.GetCode(), &patch_site); | |
1725 __ jmp(&done); | |
1726 | |
1727 // Smi case. | |
1728 __ bind(&smi_case); | |
1729 switch (op) { | |
1730 case Token::SHL: | |
1731 if (shift_value != 0) { | |
1732 __ mov(edx, eax); | |
1733 if (shift_value > 1) { | |
1734 __ shl(edx, shift_value - 1); | |
1735 } | |
1736 // Convert int result to smi, checking that it is in int range. | |
1737 STATIC_ASSERT(kSmiTagSize == 1); // Adjust code if not the case. | |
1738 __ add(edx, Operand(edx)); | |
1739 __ j(overflow, &call_stub); | |
1740 __ mov(eax, edx); // Put result back into eax. | |
1741 } | |
1742 break; | |
1743 case Token::SAR: | |
1744 if (shift_value != 0) { | |
1745 __ sar(eax, shift_value); | |
1746 __ and_(eax, ~kSmiTagMask); | |
1747 } | |
1748 break; | |
1749 case Token::SHR: | |
1750 // SHR must return a positive value. When shifting by 0 or 1 we need to | |
1751 // check that smi tagging the result will not create a negative value. | |
1752 if (shift_value < 2) { | |
1753 __ mov(edx, eax); | |
1754 __ SmiUntag(edx); | |
1755 __ shr(edx, shift_value); | |
1756 __ test(edx, Immediate(0xc0000000)); | |
1757 __ j(not_zero, &call_stub); | |
1758 __ SmiTag(edx); | |
1759 __ mov(eax, edx); // Put result back into eax. | |
1760 } else { | |
1761 __ SmiUntag(eax); | |
1762 __ shr(eax, shift_value); | |
1763 __ SmiTag(eax); | |
1764 } | |
1765 break; | |
1766 default: | |
1767 UNREACHABLE(); | |
1768 } | |
1769 | |
1770 __ bind(&done); | |
1771 context()->Plug(eax); | |
1772 } | |
1773 | |
1774 | |
1775 void FullCodeGenerator::EmitConstantSmiBitOp(Expression* expr, | |
1776 Token::Value op, | |
1777 OverwriteMode mode, | |
1778 Smi* value) { | |
1779 NearLabel smi_case, done; | |
1780 | |
1781 JumpPatchSite patch_site(masm_); | |
1782 patch_site.EmitJumpIfSmi(eax, &smi_case); | |
1783 | |
1784 // The order of the arguments does not matter for bit-ops with a | |
1785 // constant operand. | |
1786 __ mov(edx, Immediate(value)); | |
1787 TypeRecordingBinaryOpStub stub(op, mode); | |
1788 EmitCallIC(stub.GetCode(), &patch_site); | |
1789 __ jmp(&done); | |
1790 | |
1791 // Smi case. | |
1792 __ bind(&smi_case); | |
1793 switch (op) { | |
1794 case Token::BIT_OR: | |
1795 __ or_(Operand(eax), Immediate(value)); | |
1796 break; | |
1797 case Token::BIT_XOR: | |
1798 __ xor_(Operand(eax), Immediate(value)); | |
1799 break; | |
1800 case Token::BIT_AND: | |
1801 __ and_(Operand(eax), Immediate(value)); | |
1802 break; | |
1803 default: | |
1804 UNREACHABLE(); | |
1805 } | |
1806 | |
1807 __ bind(&done); | |
1808 context()->Plug(eax); | |
1809 } | |
1810 | |
1811 | |
1812 void FullCodeGenerator::EmitConstantSmiBinaryOp(Expression* expr, | |
1813 Token::Value op, | |
1814 OverwriteMode mode, | |
1815 bool left_is_constant_smi, | |
1816 Smi* value) { | |
1817 switch (op) { | |
1818 case Token::BIT_OR: | |
1819 case Token::BIT_XOR: | |
1820 case Token::BIT_AND: | |
1821 EmitConstantSmiBitOp(expr, op, mode, value); | |
1822 break; | |
1823 case Token::SHL: | |
1824 case Token::SAR: | |
1825 case Token::SHR: | |
1826 ASSERT(!left_is_constant_smi); | |
1827 EmitConstantSmiShiftOp(expr, op, mode, value); | |
1828 break; | |
1829 case Token::ADD: | |
1830 EmitConstantSmiAdd(expr, mode, left_is_constant_smi, value); | |
1831 break; | |
1832 case Token::SUB: | |
1833 EmitConstantSmiSub(expr, mode, left_is_constant_smi, value); | |
1834 break; | |
1835 default: | |
1836 UNREACHABLE(); | |
1837 } | |
1838 } | |
1839 | |
1840 | |
1841 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, | 1619 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, |
1842 Token::Value op, | 1620 Token::Value op, |
1843 OverwriteMode mode, | 1621 OverwriteMode mode, |
1844 Expression* left, | 1622 Expression* left, |
1845 Expression* right, | 1623 Expression* right) { |
1846 ConstantOperand constant) { | |
1847 if (constant == kRightConstant) { | |
1848 Smi* value = Smi::cast(*right->AsLiteral()->handle()); | |
1849 EmitConstantSmiBinaryOp(expr, op, mode, false, value); | |
1850 return; | |
1851 } else if (constant == kLeftConstant) { | |
1852 Smi* value = Smi::cast(*left->AsLiteral()->handle()); | |
1853 EmitConstantSmiBinaryOp(expr, op, mode, true, value); | |
1854 return; | |
1855 } | |
1856 | |
1857 // Do combined smi check of the operands. Left operand is on the | 1624 // Do combined smi check of the operands. Left operand is on the |
1858 // stack. Right operand is in eax. | 1625 // stack. Right operand is in eax. |
1859 NearLabel done, smi_case, stub_call; | 1626 NearLabel done, smi_case, stub_call; |
1860 __ pop(edx); | 1627 __ pop(edx); |
1861 __ mov(ecx, eax); | 1628 __ mov(ecx, eax); |
1862 __ or_(eax, Operand(edx)); | 1629 __ or_(eax, Operand(edx)); |
1863 JumpPatchSite patch_site(masm_); | 1630 JumpPatchSite patch_site(masm_); |
1864 patch_site.EmitJumpIfSmi(eax, &smi_case); | 1631 patch_site.EmitJumpIfSmi(eax, &smi_case); |
1865 | 1632 |
1866 __ bind(&stub_call); | 1633 __ bind(&stub_call); |
(...skipping 2586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4453 // And return. | 4220 // And return. |
4454 __ ret(0); | 4221 __ ret(0); |
4455 } | 4222 } |
4456 | 4223 |
4457 | 4224 |
4458 #undef __ | 4225 #undef __ |
4459 | 4226 |
4460 } } // namespace v8::internal | 4227 } } // namespace v8::internal |
4461 | 4228 |
4462 #endif // V8_TARGET_ARCH_IA32 | 4229 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |