Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 1574 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1585 break; | 1585 break; |
| 1586 } | 1586 } |
| 1587 | 1587 |
| 1588 default: | 1588 default: |
| 1589 UNREACHABLE(); | 1589 UNREACHABLE(); |
| 1590 } | 1590 } |
| 1591 } | 1591 } |
| 1592 } | 1592 } |
| 1593 | 1593 |
| 1594 | 1594 |
| 1595 void CodeGenerator::VisitCountOperation(CountOperation* a) { | 1595 // The value in dst was optimistically incremented or decremented. The |
| 1596 UNIMPLEMENTED(); | 1596 // result overflowed or was not smi tagged. Undo the operation, call |
| 1597 // into the runtime to convert the argument to a number, and call the | |
| 1598 // specialized add or subtract stub. The result is left in dst. | |
| 1599 class DeferredPrefixCountOperation: public DeferredCode { | |
| 1600 public: | |
| 1601 DeferredPrefixCountOperation(Register dst, bool is_increment) | |
| 1602 : dst_(dst), is_increment_(is_increment) { | |
| 1603 set_comment("[ DeferredCountOperation"); | |
| 1604 } | |
| 1605 | |
| 1606 virtual void Generate(); | |
| 1607 | |
| 1608 private: | |
| 1609 Register dst_; | |
| 1610 bool is_increment_; | |
| 1611 }; | |
| 1612 | |
| 1613 | |
| 1614 void DeferredPrefixCountOperation::Generate() { | |
| 1615 // Undo the optimistic smi operation. | |
| 1616 if (is_increment_) { | |
| 1617 __ subq(dst_, Immediate(Smi::FromInt(1))); | |
| 1618 } else { | |
| 1619 __ addq(dst_, Immediate(Smi::FromInt(1))); | |
| 1620 } | |
| 1621 __ push(dst_); | |
| 1622 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | |
| 1623 __ push(rax); | |
| 1624 __ push(Immediate(Smi::FromInt(1))); | |
| 1625 if (is_increment_) { | |
| 1626 __ CallRuntime(Runtime::kNumberAdd, 2); | |
| 1627 } else { | |
| 1628 __ CallRuntime(Runtime::kNumberSub, 2); | |
| 1629 } | |
| 1630 if (!dst_.is(rax)) __ movq(dst_, rax); | |
| 1597 } | 1631 } |
| 1598 | 1632 |
| 1633 | |
| 1634 // The value in dst was optimistically incremented or decremented. The | |
| 1635 // result overflowed or was not smi tagged. Undo the operation and call | |
| 1636 // into the runtime to convert the argument to a number. Update the | |
| 1637 // original value in old. Call the specialized add or subtract stub. | |
| 1638 // The result is left in dst. | |
| 1639 class DeferredPostfixCountOperation: public DeferredCode { | |
| 1640 public: | |
| 1641 DeferredPostfixCountOperation(Register dst, Register old, bool is_increment) | |
| 1642 : dst_(dst), old_(old), is_increment_(is_increment) { | |
| 1643 set_comment("[ DeferredCountOperation"); | |
| 1644 } | |
| 1645 | |
| 1646 virtual void Generate(); | |
| 1647 | |
| 1648 private: | |
| 1649 Register dst_; | |
| 1650 Register old_; | |
| 1651 bool is_increment_; | |
| 1652 }; | |
| 1653 | |
| 1654 | |
| 1655 void DeferredPostfixCountOperation::Generate() { | |
| 1656 // Undo the optimistic smi operation. | |
| 1657 if (is_increment_) { | |
| 1658 __ subq(dst_, Immediate(Smi::FromInt(1))); | |
| 1659 } else { | |
| 1660 __ addq(dst_, Immediate(Smi::FromInt(1))); | |
| 1661 } | |
| 1662 __ push(dst_); | |
| 1663 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); | |
| 1664 | |
| 1665 // Save the result of ToNumber to use as the old value. | |
| 1666 __ push(rax); | |
| 1667 | |
| 1668 // Call the runtime for the addition or subtraction. | |
| 1669 __ push(rax); | |
| 1670 __ push(Immediate(Smi::FromInt(1))); | |
| 1671 if (is_increment_) { | |
| 1672 __ CallRuntime(Runtime::kNumberAdd, 2); | |
| 1673 } else { | |
| 1674 __ CallRuntime(Runtime::kNumberSub, 2); | |
| 1675 } | |
| 1676 if (!dst_.is(rax)) __ movq(dst_, rax); | |
| 1677 __ pop(old_); | |
| 1678 } | |
| 1679 | |
| 1680 | |
| 1681 void CodeGenerator::VisitCountOperation(CountOperation* node) { | |
| 1682 Comment cmnt(masm_, "[ CountOperation"); | |
| 1683 | |
| 1684 bool is_postfix = node->is_postfix(); | |
| 1685 bool is_increment = node->op() == Token::INC; | |
| 1686 | |
| 1687 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | |
| 1688 bool is_const = (var != NULL && var->mode() == Variable::CONST); | |
| 1689 | |
| 1690 // Postfix operations need a stack slot under the reference to hold | |
| 1691 // the old value while the new value is being stored. This is so that | |
| 1692 // in the case that storing the new value requires a call, the old | |
| 1693 // value will be in the frame to be spilled. | |
| 1694 if (is_postfix) frame_->Push(Smi::FromInt(0)); | |
| 1695 | |
| 1696 { Reference target(this, node->expression()); | |
| 1697 if (target.is_illegal()) { | |
| 1698 // Spoof the virtual frame to have the expected height (one higher | |
| 1699 // than on entry). | |
| 1700 if (!is_postfix) frame_->Push(Smi::FromInt(0)); | |
| 1701 return; | |
| 1702 } | |
| 1703 target.TakeValue(NOT_INSIDE_TYPEOF); | |
| 1704 | |
| 1705 Result new_value = frame_->Pop(); | |
| 1706 new_value.ToRegister(); | |
| 1707 | |
| 1708 Result old_value; // Only allocated in the postfix case. | |
| 1709 if (is_postfix) { | |
| 1710 // Allocate a temporary to preserve the old value. | |
| 1711 old_value = allocator_->Allocate(); | |
| 1712 ASSERT(old_value.is_valid()); | |
| 1713 __ movq(old_value.reg(), new_value.reg()); | |
| 1714 } | |
| 1715 // Ensure the new value is writable. | |
| 1716 frame_->Spill(new_value.reg()); | |
| 1717 | |
| 1718 // In order to combine the overflow and the smi tag check, we need | |
| 1719 // to be able to allocate a byte register. We attempt to do so | |
| 1720 // without spilling. If we fail, we will generate separate overflow | |
| 1721 // and smi tag checks. | |
| 1722 // | |
| 1723 // We allocate and clear the temporary register before | |
| 1724 // performing the count operation since clearing the register using | |
| 1725 // xor will clear the overflow flag. | |
| 1726 Result tmp = allocator_->AllocateWithoutSpilling(); | |
|
William Hesse
2009/06/25 10:46:05
The allocation and use of tmp can be replaced with
| |
| 1727 if (tmp.is_valid()) { | |
| 1728 // Clear tmp.reg() to prepare it for setcc after the operation below. | |
| 1729 __ xor_(tmp.reg(), tmp.reg()); | |
| 1730 } | |
| 1731 | |
| 1732 DeferredCode* deferred = NULL; | |
| 1733 if (is_postfix) { | |
| 1734 deferred = new DeferredPostfixCountOperation(new_value.reg(), | |
| 1735 old_value.reg(), | |
| 1736 is_increment); | |
| 1737 } else { | |
| 1738 deferred = new DeferredPrefixCountOperation(new_value.reg(), | |
| 1739 is_increment); | |
| 1740 } | |
| 1741 | |
| 1742 if (is_increment) { | |
| 1743 __ addq(new_value.reg(), Immediate(Smi::FromInt(1))); | |
| 1744 } else { | |
| 1745 __ subq(new_value.reg(), Immediate(Smi::FromInt(1))); | |
| 1746 } | |
| 1747 | |
| 1748 // If the count operation didn't overflow and the result is a valid | |
| 1749 // smi, we're done. Otherwise, we jump to the deferred slow-case | |
| 1750 // code. | |
| 1751 if (tmp.is_valid()) { | |
| 1752 // We combine the overflow and the smi tag check if we could | |
| 1753 // successfully allocate a temporary byte register. | |
| 1754 __ setcc(overflow, tmp.reg()); | |
| 1755 __ or_(tmp.reg(), new_value.reg()); | |
| 1756 __ testl(tmp.reg(), Immediate(kSmiTagMask)); | |
| 1757 tmp.Unuse(); | |
| 1758 deferred->Branch(not_zero); | |
| 1759 } else { | |
| 1760 // Otherwise we test separately for overflow and smi tag. | |
| 1761 deferred->Branch(overflow); | |
| 1762 __ testl(new_value.reg(), Immediate(kSmiTagMask)); | |
| 1763 deferred->Branch(not_zero); | |
| 1764 } | |
| 1765 deferred->BindExit(); | |
| 1766 | |
| 1767 // Postfix: store the old value in the allocated slot under the | |
| 1768 // reference. | |
| 1769 if (is_postfix) frame_->SetElementAt(target.size(), &old_value); | |
| 1770 | |
| 1771 frame_->Push(&new_value); | |
| 1772 // Non-constant: update the reference. | |
| 1773 if (!is_const) target.SetValue(NOT_CONST_INIT); | |
| 1774 } | |
| 1775 | |
| 1776 // Postfix: drop the new value and use the old. | |
| 1777 if (is_postfix) frame_->Drop(); | |
| 1778 } | |
| 1779 | |
| 1780 | |
| 1599 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 1781 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
| 1600 // TODO(X64): This code was copied verbatim from codegen-ia32. | 1782 // TODO(X64): This code was copied verbatim from codegen-ia32. |
| 1601 // Either find a reason to change it or move it to a shared location. | 1783 // Either find a reason to change it or move it to a shared location. |
| 1602 | 1784 |
| 1603 // Note that due to an optimization in comparison operations (typeof | 1785 // Note that due to an optimization in comparison operations (typeof |
| 1604 // compared to a string literal), we can evaluate a binary expression such | 1786 // compared to a string literal), we can evaluate a binary expression such |
| 1605 // as AND or OR and not leave a value on the frame or in the cc register. | 1787 // as AND or OR and not leave a value on the frame or in the cc register. |
| 1606 Comment cmnt(masm_, "[ BinaryOperation"); | 1788 Comment cmnt(masm_, "[ BinaryOperation"); |
| 1607 Token::Value op = node->op(); | 1789 Token::Value op = node->op(); |
| 1608 | 1790 |
| (...skipping 2047 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3656 cgen_->frame()->Push(&answer); | 3838 cgen_->frame()->Push(&answer); |
| 3657 break; | 3839 break; |
| 3658 } | 3840 } |
| 3659 | 3841 |
| 3660 default: | 3842 default: |
| 3661 UNREACHABLE(); | 3843 UNREACHABLE(); |
| 3662 } | 3844 } |
| 3663 } | 3845 } |
| 3664 | 3846 |
| 3665 | 3847 |
| 3848 void Reference::TakeValue(TypeofState typeof_state) { | |
| 3849 // TODO(X64): This function is completely architecture independent. Move | |
| 3850 // it somewhere shared. | |
| 3851 | |
| 3852 // For non-constant frame-allocated slots, we invalidate the value in the | |
| 3853 // slot. For all others, we fall back on GetValue. | |
| 3854 ASSERT(!cgen_->in_spilled_code()); | |
| 3855 ASSERT(!is_illegal()); | |
| 3856 if (type_ != SLOT) { | |
| 3857 GetValue(typeof_state); | |
| 3858 return; | |
| 3859 } | |
| 3860 | |
| 3861 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | |
| 3862 ASSERT(slot != NULL); | |
| 3863 if (slot->type() == Slot::LOOKUP || | |
| 3864 slot->type() == Slot::CONTEXT || | |
| 3865 slot->var()->mode() == Variable::CONST) { | |
| 3866 GetValue(typeof_state); | |
| 3867 return; | |
| 3868 } | |
| 3869 | |
| 3870 // Only non-constant, frame-allocated parameters and locals can reach | |
| 3871 // here. | |
| 3872 if (slot->type() == Slot::PARAMETER) { | |
| 3873 cgen_->frame()->TakeParameterAt(slot->index()); | |
| 3874 } else { | |
| 3875 ASSERT(slot->type() == Slot::LOCAL); | |
| 3876 cgen_->frame()->TakeLocalAt(slot->index()); | |
| 3877 } | |
| 3878 } | |
| 3879 | |
| 3880 | |
| 3666 void Reference::SetValue(InitState init_state) { | 3881 void Reference::SetValue(InitState init_state) { |
| 3667 ASSERT(cgen_->HasValidEntryRegisters()); | 3882 ASSERT(cgen_->HasValidEntryRegisters()); |
| 3668 ASSERT(!is_illegal()); | 3883 ASSERT(!is_illegal()); |
| 3669 MacroAssembler* masm = cgen_->masm(); | 3884 MacroAssembler* masm = cgen_->masm(); |
| 3670 switch (type_) { | 3885 switch (type_) { |
| 3671 case SLOT: { | 3886 case SLOT: { |
| 3672 Comment cmnt(masm, "[ Store to Slot"); | 3887 Comment cmnt(masm, "[ Store to Slot"); |
| 3673 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 3888 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
| 3674 ASSERT(slot != NULL); | 3889 ASSERT(slot != NULL); |
| 3675 cgen_->StoreToSlot(slot, init_state); | 3890 cgen_->StoreToSlot(slot, init_state); |
| (...skipping 1459 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5135 break; | 5350 break; |
| 5136 default: | 5351 default: |
| 5137 UNREACHABLE(); | 5352 UNREACHABLE(); |
| 5138 } | 5353 } |
| 5139 } | 5354 } |
| 5140 | 5355 |
| 5141 | 5356 |
| 5142 #undef __ | 5357 #undef __ |
| 5143 | 5358 |
| 5144 } } // namespace v8::internal | 5359 } } // namespace v8::internal |
| OLD | NEW |