Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 1667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1678 isolate()->factory()->empty_string(), | 1678 isolate()->factory()->empty_string(), |
| 1679 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), | 1679 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), |
| 1680 1)); | 1680 1)); |
| 1681 } | 1681 } |
| 1682 if_found.End(); | 1682 if_found.End(); |
| 1683 | 1683 |
| 1684 return Pop(); | 1684 return Pop(); |
| 1685 } | 1685 } |
| 1686 | 1686 |
| 1687 | 1687 |
| 1688 HValue* HGraphBuilder::BuildSeqStringSizeFor(HValue* length, | 1688 HAllocate* HGraphBuilder::BuildAllocate( |
|
Hannes Payer (out of office)
2013/12/11 13:12:22
I like that. Are you planning to refactor other pr
Benedikt Meurer
2013/12/11 13:55:43
Yep, that's the plan.
| |
| 1689 String::Encoding encoding) { | 1689 HValue* object_size, |
| 1690 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0); | 1690 HType type, |
| 1691 HValue* size = length; | 1691 InstanceType instance_type, |
| 1692 if (encoding == String::TWO_BYTE_ENCODING) { | 1692 HAllocationMode allocation_mode) { |
| 1693 size = AddUncasted<HShl>(length, graph()->GetConstant1()); | 1693 // Compute the effective allocation size. |
| 1694 HValue* size = object_size; | |
| 1695 if (allocation_mode.CreateAllocationMementos()) { | |
| 1696 size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize)); | |
| 1694 size->ClearFlag(HValue::kCanOverflow); | 1697 size->ClearFlag(HValue::kCanOverflow); |
| 1695 size->SetFlag(HValue::kUint32); | |
| 1696 } | 1698 } |
| 1697 size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>( | 1699 |
| 1698 SeqString::kHeaderSize + kObjectAlignmentMask))); | 1700 // Perform the actual allocation. |
| 1699 size->ClearFlag(HValue::kCanOverflow); | 1701 HAllocate* object = Add<HAllocate>( |
| 1700 size = AddUncasted<HBitwise>( | 1702 size, type, allocation_mode.GetPretenureMode(), |
| 1701 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( | 1703 instance_type, allocation_mode.feedback_site()); |
| 1702 ~kObjectAlignmentMask))); | 1704 |
| 1703 return size; | 1705 // Setup the allocation memento. |
| 1706 if (allocation_mode.CreateAllocationMementos()) { | |
| 1707 BuildCreateAllocationMemento( | |
| 1708 object, object_size, allocation_mode.current_site()); | |
| 1709 } | |
| 1710 | |
| 1711 return object; | |
| 1704 } | 1712 } |
| 1705 | 1713 |
| 1706 | 1714 |
| 1715 HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length, | |
| 1716 HValue* right_length) { | |
| 1717 // Compute the combined string length. If the result is larger than the max | |
| 1718 // supported string length, we bailout to the runtime. This is done implicitly | |
|
Hannes Payer (out of office)
2013/12/11 13:12:22
implicitly
Benedikt Meurer
2013/12/11 13:55:43
:-)
| |
| 1719 // when converting the result back to a smi in case the max string length | |
| 1720 // equals the max smi valie. Otherwise, for platforms with 32-bit smis, we do | |
|
mvstanton
2013/12/11 14:14:20
value, not valie.
Benedikt Meurer
2013/12/11 17:50:45
Done.
| |
| 1721 HValue* length = AddUncasted<HAdd>(left_length, right_length); | |
| 1722 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); | |
| 1723 if (String::kMaxLength != Smi::kMaxValue) { | |
| 1724 IfBuilder if_nooverflow(this); | |
| 1725 if_nooverflow.If<HCompareNumericAndBranch>( | |
| 1726 length, Add<HConstant>(String::kMaxLength), Token::LTE); | |
| 1727 if_nooverflow.Then(); | |
| 1728 if_nooverflow.ElseDeopt("String length exceeds limit"); | |
| 1729 } | |
| 1730 return length; | |
| 1731 } | |
| 1732 | |
| 1733 | |
| 1734 HValue* HGraphBuilder::BuildCreateConsString( | |
| 1735 HValue* length, | |
| 1736 HValue* left, | |
| 1737 HValue* right, | |
| 1738 HAllocationMode allocation_mode) { | |
| 1739 // Determine the string instance types. | |
| 1740 HInstruction* left_instance_type = AddLoadStringInstanceType(left); | |
| 1741 HInstruction* right_instance_type = AddLoadStringInstanceType(right); | |
| 1742 | |
| 1743 // Allocate the cons string object. HAllocate does not care whether we | |
| 1744 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use | |
| 1745 // CONS_STRING_TYPE here. Below we decide whether the cons string is | |
| 1746 // one-byte or two-byte and set the appropriate map. | |
|
Hannes Payer (out of office)
2013/12/11 13:12:22
Allocate should have the right instance type and w
Benedikt Meurer
2013/12/11 13:55:43
We don't need to. Discussed offline.
mvstanton
2013/12/11 14:14:20
Here you'll add the assert that the HAllocate flag
| |
| 1747 HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize), | |
| 1748 HType::String(), CONS_STRING_TYPE, | |
| 1749 allocation_mode); | |
| 1750 | |
| 1751 // Compute intersection and difference of instance types. | |
| 1752 HValue* anded_instance_types = AddUncasted<HBitwise>( | |
| 1753 Token::BIT_AND, left_instance_type, right_instance_type); | |
| 1754 HValue* xored_instance_types = AddUncasted<HBitwise>( | |
| 1755 Token::BIT_XOR, left_instance_type, right_instance_type); | |
| 1756 | |
| 1757 // We create a one-byte cons string if | |
| 1758 // 1. both strings are one-byte, or | |
| 1759 // 2. at least one of the strings is two-byte, but happens to contain only | |
| 1760 // one-byte characters. | |
| 1761 // To do this, we check | |
| 1762 // 1. if both strings are one-byte, or if the one-byte data hint is set in | |
| 1763 // both strings, or | |
| 1764 // 2. if one of the strings has the one-byte data hint set and the other | |
| 1765 // string is one-byte. | |
| 1766 IfBuilder if_onebyte(this); | |
| 1767 STATIC_ASSERT(kOneByteStringTag != 0); | |
| 1768 STATIC_ASSERT(kOneByteDataHintMask != 0); | |
| 1769 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1770 AddUncasted<HBitwise>( | |
| 1771 Token::BIT_AND, anded_instance_types, | |
| 1772 Add<HConstant>(static_cast<int32_t>( | |
| 1773 kStringEncodingMask | kOneByteDataHintMask))), | |
| 1774 graph()->GetConstant0(), Token::NE); | |
| 1775 if_onebyte.Or(); | |
| 1776 STATIC_ASSERT(kOneByteStringTag != 0 && | |
| 1777 kOneByteDataHintTag != 0 && | |
| 1778 kOneByteDataHintTag != kOneByteStringTag); | |
| 1779 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1780 AddUncasted<HBitwise>( | |
| 1781 Token::BIT_AND, xored_instance_types, | |
| 1782 Add<HConstant>(static_cast<int32_t>( | |
| 1783 kOneByteStringTag | kOneByteDataHintTag))), | |
| 1784 Add<HConstant>(static_cast<int32_t>( | |
| 1785 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); | |
| 1786 if_onebyte.Then(); | |
| 1787 { | |
| 1788 // We can safely skip the write barrier for storing the map here. | |
| 1789 Handle<Map> map = isolate()->factory()->cons_ascii_string_map(); | |
| 1790 AddStoreMapConstantNoWriteBarrier(result, map); | |
|
Hannes Payer (out of office)
2013/12/11 13:12:22
Why is there a write barrier emitted? We should be
Benedikt Meurer
2013/12/11 13:55:43
Not in case of pretenuring, unfortunately.
| |
| 1791 } | |
| 1792 if_onebyte.Else(); | |
| 1793 { | |
| 1794 // We can safely skip the write barrier for storing the map here. | |
| 1795 Handle<Map> map = isolate()->factory()->cons_string_map(); | |
|
Hannes Payer (out of office)
2013/12/11 13:12:22
Why is there a write barrier emitted?
Benedikt Meurer
2013/12/11 13:55:43
Not in case of pretenuring, unfortunately.
| |
| 1796 AddStoreMapConstantNoWriteBarrier(result, map); | |
| 1797 } | |
| 1798 if_onebyte.End(); | |
| 1799 | |
| 1800 // Initialize the cons string fields. | |
| 1801 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(), | |
| 1802 Add<HConstant>(String::kEmptyHashField)); | |
| 1803 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length); | |
| 1804 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left); | |
| 1805 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right); | |
| 1806 | |
| 1807 // Count the native string addition. | |
| 1808 AddIncrementCounter(isolate()->counters()->string_add_native()); | |
| 1809 | |
| 1810 return result; | |
| 1811 } | |
| 1812 | |
| 1813 | |
| 1707 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, | 1814 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, |
| 1708 HValue* src_offset, | 1815 HValue* src_offset, |
| 1709 String::Encoding src_encoding, | 1816 String::Encoding src_encoding, |
| 1710 HValue* dst, | 1817 HValue* dst, |
| 1711 HValue* dst_offset, | 1818 HValue* dst_offset, |
| 1712 String::Encoding dst_encoding, | 1819 String::Encoding dst_encoding, |
| 1713 HValue* length) { | 1820 HValue* length) { |
| 1714 ASSERT(dst_encoding != String::ONE_BYTE_ENCODING || | 1821 ASSERT(dst_encoding != String::ONE_BYTE_ENCODING || |
| 1715 src_encoding == String::ONE_BYTE_ENCODING); | 1822 src_encoding == String::ONE_BYTE_ENCODING); |
| 1716 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); | 1823 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); |
| 1717 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); | 1824 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); |
| 1718 { | 1825 { |
| 1719 HValue* src_index = AddUncasted<HAdd>(src_offset, index); | 1826 HValue* src_index = AddUncasted<HAdd>(src_offset, index); |
| 1720 HValue* value = | 1827 HValue* value = |
| 1721 AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index); | 1828 AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index); |
| 1722 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index); | 1829 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index); |
| 1723 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); | 1830 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); |
| 1724 } | 1831 } |
| 1725 loop.EndBody(); | 1832 loop.EndBody(); |
| 1726 } | 1833 } |
| 1727 | 1834 |
| 1728 | 1835 |
| 1729 HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left, | 1836 HValue* HGraphBuilder::BuildUncheckedStringAdd( |
| 1730 HValue* right, | 1837 HValue* left, |
| 1731 PretenureFlag pretenure_flag) { | 1838 HValue* right, |
| 1839 HAllocationMode allocation_mode) { | |
| 1732 // Determine the string lengths. | 1840 // Determine the string lengths. |
| 1733 HValue* left_length = Add<HLoadNamedField>( | 1841 HValue* left_length = AddLoadStringLength(left); |
| 1734 left, HObjectAccess::ForStringLength()); | 1842 HValue* right_length = AddLoadStringLength(right); |
| 1735 HValue* right_length = Add<HLoadNamedField>( | |
| 1736 right, HObjectAccess::ForStringLength()); | |
| 1737 | 1843 |
| 1738 // Compute the combined string length. If the result is larger than the max | 1844 // Compute the combined string length. |
| 1739 // supported string length, we bailout to the runtime. This is done implicitly | 1845 HValue* length = BuildAddStringLengths(left_length, right_length); |
| 1740 // when converting the result back to a smi in case the max string length | 1846 |
| 1741 // equals the max smi valie. Otherwise, for platforms with 32-bit smis, we do | 1847 // Do some manual constant folding here. |
| 1742 HValue* length = AddUncasted<HAdd>(left_length, right_length); | 1848 if (left_length->IsConstant()) { |
| 1743 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); | 1849 HConstant* c_left_length = HConstant::cast(left_length); |
| 1744 if (String::kMaxLength != Smi::kMaxValue) { | 1850 ASSERT_NE(0, c_left_length->Integer32Value()); |
| 1745 IfBuilder if_nooverflow(this); | 1851 if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) { |
| 1746 if_nooverflow.If<HCompareNumericAndBranch>( | 1852 // The right string contains at least one character. |
| 1747 length, Add<HConstant>(String::kMaxLength), Token::LTE); | 1853 return BuildCreateConsString(length, left, right, allocation_mode); |
| 1748 if_nooverflow.Then(); | 1854 } |
| 1749 if_nooverflow.ElseDeopt("String length exceeds limit"); | 1855 } else if (right_length->IsConstant()) { |
| 1856 HConstant* c_right_length = HConstant::cast(right_length); | |
| 1857 ASSERT_NE(0, c_right_length->Integer32Value()); | |
| 1858 if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) { | |
| 1859 // The left string contains at least one character. | |
| 1860 return BuildCreateConsString(length, left, right, allocation_mode); | |
| 1861 } | |
| 1750 } | 1862 } |
| 1751 | 1863 |
| 1752 // Determine the string instance types. | |
| 1753 HLoadNamedField* left_instance_type = Add<HLoadNamedField>( | |
| 1754 Add<HLoadNamedField>(left, HObjectAccess::ForMap()), | |
| 1755 HObjectAccess::ForMapInstanceType()); | |
| 1756 HLoadNamedField* right_instance_type = Add<HLoadNamedField>( | |
| 1757 Add<HLoadNamedField>(right, HObjectAccess::ForMap()), | |
| 1758 HObjectAccess::ForMapInstanceType()); | |
| 1759 | |
| 1760 // Compute difference of instance types. | |
| 1761 HValue* xored_instance_types = AddUncasted<HBitwise>( | |
| 1762 Token::BIT_XOR, left_instance_type, right_instance_type); | |
| 1763 | |
| 1764 // Check if we should create a cons string. | 1864 // Check if we should create a cons string. |
| 1765 IfBuilder if_createcons(this); | 1865 IfBuilder if_createcons(this); |
| 1766 if_createcons.If<HCompareNumericAndBranch>( | 1866 if_createcons.If<HCompareNumericAndBranch>( |
| 1767 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); | 1867 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); |
| 1768 if_createcons.Then(); | 1868 if_createcons.Then(); |
| 1769 { | 1869 { |
| 1770 // Allocate the cons string object. HAllocate does not care whether we | 1870 // Create a cons string. |
| 1771 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use | 1871 Push(BuildCreateConsString(length, left, right, allocation_mode)); |
| 1772 // CONS_STRING_TYPE here. Below we decide whether the cons string is | |
| 1773 // one-byte or two-byte and set the appropriate map. | |
| 1774 HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize), | |
| 1775 HType::String(), pretenure_flag, | |
| 1776 CONS_STRING_TYPE); | |
| 1777 | |
| 1778 // Compute the intersection of instance types. | |
| 1779 HValue* anded_instance_types = AddUncasted<HBitwise>( | |
| 1780 Token::BIT_AND, left_instance_type, right_instance_type); | |
| 1781 | |
| 1782 // We create a one-byte cons string if | |
| 1783 // 1. both strings are one-byte, or | |
| 1784 // 2. at least one of the strings is two-byte, but happens to contain only | |
| 1785 // one-byte characters. | |
| 1786 // To do this, we check | |
| 1787 // 1. if both strings are one-byte, or if the one-byte data hint is set in | |
| 1788 // both strings, or | |
| 1789 // 2. if one of the strings has the one-byte data hint set and the other | |
| 1790 // string is one-byte. | |
| 1791 IfBuilder if_onebyte(this); | |
| 1792 STATIC_ASSERT(kOneByteStringTag != 0); | |
| 1793 STATIC_ASSERT(kOneByteDataHintMask != 0); | |
| 1794 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1795 AddUncasted<HBitwise>( | |
| 1796 Token::BIT_AND, anded_instance_types, | |
| 1797 Add<HConstant>(static_cast<int32_t>( | |
| 1798 kStringEncodingMask | kOneByteDataHintMask))), | |
| 1799 graph()->GetConstant0(), Token::NE); | |
| 1800 if_onebyte.Or(); | |
| 1801 STATIC_ASSERT(kOneByteStringTag != 0 && | |
| 1802 kOneByteDataHintTag != 0 && | |
| 1803 kOneByteDataHintTag != kOneByteStringTag); | |
| 1804 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1805 AddUncasted<HBitwise>( | |
| 1806 Token::BIT_AND, xored_instance_types, | |
| 1807 Add<HConstant>(static_cast<int32_t>( | |
| 1808 kOneByteStringTag | kOneByteDataHintTag))), | |
| 1809 Add<HConstant>(static_cast<int32_t>( | |
| 1810 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); | |
| 1811 if_onebyte.Then(); | |
| 1812 { | |
| 1813 // We can safely skip the write barrier for storing the map here. | |
| 1814 Handle<Map> map = isolate()->factory()->cons_ascii_string_map(); | |
| 1815 AddStoreMapConstantNoWriteBarrier(string, map); | |
| 1816 } | |
| 1817 if_onebyte.Else(); | |
| 1818 { | |
| 1819 // We can safely skip the write barrier for storing the map here. | |
| 1820 Handle<Map> map = isolate()->factory()->cons_string_map(); | |
| 1821 AddStoreMapConstantNoWriteBarrier(string, map); | |
| 1822 } | |
| 1823 if_onebyte.End(); | |
| 1824 | |
| 1825 // Initialize the cons string fields. | |
| 1826 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), | |
| 1827 Add<HConstant>(String::kEmptyHashField)); | |
| 1828 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length); | |
| 1829 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left); | |
| 1830 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(), | |
| 1831 right); | |
| 1832 | |
| 1833 // Count the native string addition. | |
| 1834 AddIncrementCounter(isolate()->counters()->string_add_native()); | |
| 1835 | |
| 1836 // Cons string is result. | |
| 1837 Push(string); | |
| 1838 } | 1872 } |
| 1839 if_createcons.Else(); | 1873 if_createcons.Else(); |
| 1840 { | 1874 { |
| 1841 // Compute union of instance types. | 1875 // Determine the string instance types. |
| 1876 HValue* left_instance_type = AddLoadStringInstanceType(left); | |
| 1877 HValue* right_instance_type = AddLoadStringInstanceType(right); | |
| 1878 | |
| 1879 // Compute union and difference of instance types. | |
| 1842 HValue* ored_instance_types = AddUncasted<HBitwise>( | 1880 HValue* ored_instance_types = AddUncasted<HBitwise>( |
| 1843 Token::BIT_OR, left_instance_type, right_instance_type); | 1881 Token::BIT_OR, left_instance_type, right_instance_type); |
| 1882 HValue* xored_instance_types = AddUncasted<HBitwise>( | |
| 1883 Token::BIT_XOR, left_instance_type, right_instance_type); | |
| 1844 | 1884 |
| 1845 // Check if both strings have the same encoding and both are | 1885 // Check if both strings have the same encoding and both are |
| 1846 // sequential. | 1886 // sequential. |
| 1847 IfBuilder if_sameencodingandsequential(this); | 1887 IfBuilder if_sameencodingandsequential(this); |
| 1848 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | 1888 if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
| 1849 AddUncasted<HBitwise>( | 1889 AddUncasted<HBitwise>( |
| 1850 Token::BIT_AND, xored_instance_types, | 1890 Token::BIT_AND, xored_instance_types, |
| 1851 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | 1891 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
| 1852 graph()->GetConstant0(), Token::EQ); | 1892 graph()->GetConstant0(), Token::EQ); |
| 1853 if_sameencodingandsequential.And(); | 1893 if_sameencodingandsequential.And(); |
| 1854 STATIC_ASSERT(kSeqStringTag == 0); | 1894 STATIC_ASSERT(kSeqStringTag == 0); |
| 1855 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | 1895 if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
| 1856 AddUncasted<HBitwise>( | 1896 AddUncasted<HBitwise>( |
| 1857 Token::BIT_AND, ored_instance_types, | 1897 Token::BIT_AND, ored_instance_types, |
| 1858 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), | 1898 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), |
| 1859 graph()->GetConstant0(), Token::EQ); | 1899 graph()->GetConstant0(), Token::EQ); |
| 1860 if_sameencodingandsequential.Then(); | 1900 if_sameencodingandsequential.Then(); |
| 1861 { | 1901 { |
| 1862 // Check if the result is a one-byte string. | 1902 HConstant* string_map = |
| 1903 Add<HConstant>(isolate()->factory()->string_map()); | |
| 1904 HConstant* ascii_string_map = | |
| 1905 Add<HConstant>(isolate()->factory()->ascii_string_map()); | |
| 1906 | |
| 1907 // Determine map and size depending on whether result is one-byte string. | |
| 1863 IfBuilder if_onebyte(this); | 1908 IfBuilder if_onebyte(this); |
| 1864 STATIC_ASSERT(kOneByteStringTag != 0); | 1909 STATIC_ASSERT(kOneByteStringTag != 0); |
| 1865 if_onebyte.If<HCompareNumericAndBranch>( | 1910 if_onebyte.If<HCompareNumericAndBranch>( |
| 1866 AddUncasted<HBitwise>( | 1911 AddUncasted<HBitwise>( |
| 1867 Token::BIT_AND, ored_instance_types, | 1912 Token::BIT_AND, ored_instance_types, |
| 1868 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | 1913 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
| 1869 graph()->GetConstant0(), Token::NE); | 1914 graph()->GetConstant0(), Token::NE); |
| 1870 if_onebyte.Then(); | 1915 if_onebyte.Then(); |
| 1871 { | 1916 { |
| 1872 // Calculate the number of bytes needed for the characters in the | 1917 // Allocate sequential one-byte string object. |
| 1873 // string while observing object alignment. | 1918 Push(length); |
| 1874 HValue* size = BuildSeqStringSizeFor( | 1919 Push(ascii_string_map); |
| 1875 length, String::ONE_BYTE_ENCODING); | |
| 1876 | |
| 1877 // Allocate the ASCII string object. | |
| 1878 Handle<Map> map = isolate()->factory()->ascii_string_map(); | |
| 1879 HAllocate* string = Add<HAllocate>(size, HType::String(), | |
| 1880 pretenure_flag, ASCII_STRING_TYPE); | |
| 1881 string->set_known_initial_map(map); | |
| 1882 | |
| 1883 // We can safely skip the write barrier for storing map here. | |
| 1884 AddStoreMapConstantNoWriteBarrier(string, map); | |
| 1885 | |
| 1886 // Length must be stored into the string before we copy characters to | |
| 1887 // make debug verification code happy. | |
| 1888 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), | |
| 1889 length); | |
| 1890 | |
| 1891 // Copy bytes from the left string. | |
| 1892 BuildCopySeqStringChars( | |
| 1893 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1894 string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1895 left_length); | |
| 1896 | |
| 1897 // Copy bytes from the right string. | |
| 1898 BuildCopySeqStringChars( | |
| 1899 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1900 string, left_length, String::ONE_BYTE_ENCODING, | |
| 1901 right_length); | |
| 1902 | |
| 1903 // Count the native string addition. | |
| 1904 AddIncrementCounter(isolate()->counters()->string_add_native()); | |
| 1905 | |
| 1906 // Return the string. | |
| 1907 Push(string); | |
| 1908 } | 1920 } |
| 1909 if_onebyte.Else(); | 1921 if_onebyte.Else(); |
| 1910 { | 1922 { |
| 1911 // Calculate the number of bytes needed for the characters in the | 1923 // Allocate sequential two-byte string object. |
| 1912 // string while observing object alignment. | 1924 HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1()); |
|
mvstanton
2013/12/11 14:14:20
The shift instruction seems very low level. Any ch
Benedikt Meurer
2013/12/11 17:50:45
Using HMul generates less optimal code.
| |
| 1913 HValue* size = BuildSeqStringSizeFor( | 1925 size->ClearFlag(HValue::kCanOverflow); |
| 1914 length, String::TWO_BYTE_ENCODING); | 1926 size->SetFlag(HValue::kUint32); |
| 1927 Push(size); | |
| 1928 Push(string_map); | |
| 1929 } | |
| 1930 if_onebyte.End(); | |
| 1931 HValue* map = Pop(); | |
| 1915 | 1932 |
| 1916 // Allocate the two-byte string object. | 1933 // Calculate the number of bytes needed for the characters in the |
| 1917 Handle<Map> map = isolate()->factory()->string_map(); | 1934 // string while observing object alignment. |
| 1918 HAllocate* string = Add<HAllocate>(size, HType::String(), | 1935 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 1919 pretenure_flag, STRING_TYPE); | 1936 HValue* size = Pop(); |
| 1920 string->set_known_initial_map(map); | 1937 size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>( |
| 1938 SeqString::kHeaderSize + kObjectAlignmentMask))); | |
| 1939 size->ClearFlag(HValue::kCanOverflow); | |
| 1940 size = AddUncasted<HBitwise>( | |
| 1941 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( | |
| 1942 ~kObjectAlignmentMask))); | |
|
mvstanton
2013/12/11 14:14:20
Could this size computation be in a method, or is
Benedikt Meurer
2013/12/11 17:50:45
BuildSeqStringSizeFor() is gone. This is basically
| |
| 1921 | 1943 |
| 1922 // We can safely skip the write barrier for storing map here. | 1944 // Allocate the string object. HAllocate does not care whether we pass |
| 1923 AddStoreMapConstantNoWriteBarrier(string, map); | 1945 // STRING_TYPE or ASCII_STRING_TYPE here, so we just use STRING_TYPE here. |
| 1946 HAllocate* result = BuildAllocate( | |
| 1947 size, HType::String(), STRING_TYPE, allocation_mode); | |
| 1924 | 1948 |
| 1925 // Length must be stored into the string before we copy characters to | 1949 // We can safely skip the write barrier for storing map here. |
| 1926 // make debug verification code happy. | 1950 AddStoreMapNoWriteBarrier(result, map); |
|
Hannes Payer (out of office)
2013/12/11 13:12:22
Why is there a write barrier emitted?
Benedikt Meurer
2013/12/11 13:55:43
I don't know.
| |
| 1927 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), | |
| 1928 length); | |
| 1929 | 1951 |
| 1930 // Copy bytes from the left string. | 1952 // Initialize the string fields. |
| 1953 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(), | |
| 1954 Add<HConstant>(String::kEmptyHashField)); | |
| 1955 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length); | |
| 1956 | |
| 1957 // Copy characters to the result string. | |
| 1958 IfBuilder if_twobyte(this); | |
| 1959 if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map); | |
| 1960 if_twobyte.Then(); | |
| 1961 { | |
| 1962 // Copy characters from the left string. | |
| 1931 BuildCopySeqStringChars( | 1963 BuildCopySeqStringChars( |
| 1932 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | 1964 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1933 string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | 1965 result, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1934 left_length); | 1966 left_length); |
| 1935 | 1967 |
| 1936 // Copy bytes from the right string. | 1968 // Copy characters from the right string. |
| 1937 BuildCopySeqStringChars( | 1969 BuildCopySeqStringChars( |
| 1938 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | 1970 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1939 string, left_length, String::TWO_BYTE_ENCODING, | 1971 result, left_length, String::TWO_BYTE_ENCODING, |
| 1940 right_length); | 1972 right_length); |
| 1973 } | |
| 1974 if_twobyte.Else(); | |
| 1975 { | |
| 1976 // Copy characters from the left string. | |
| 1977 BuildCopySeqStringChars( | |
| 1978 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1979 result, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1980 left_length); | |
| 1941 | 1981 |
| 1942 // Return the string. | 1982 // Copy characters from the right string. |
| 1943 Push(string); | 1983 BuildCopySeqStringChars( |
| 1984 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1985 result, left_length, String::ONE_BYTE_ENCODING, | |
| 1986 right_length); | |
| 1944 } | 1987 } |
| 1945 if_onebyte.End(); | 1988 if_twobyte.End(); |
| 1946 | |
| 1947 // Initialize the (common) string fields. | |
| 1948 HValue* string = Pop(); | |
| 1949 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), | |
| 1950 Add<HConstant>(String::kEmptyHashField)); | |
| 1951 | 1989 |
| 1952 // Count the native string addition. | 1990 // Count the native string addition. |
| 1953 AddIncrementCounter(isolate()->counters()->string_add_native()); | 1991 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1954 | 1992 |
| 1955 Push(string); | 1993 // Return the sequential string. |
| 1994 Push(result); | |
| 1956 } | 1995 } |
| 1957 if_sameencodingandsequential.Else(); | 1996 if_sameencodingandsequential.Else(); |
| 1958 { | 1997 { |
| 1959 // Fallback to the runtime to add the two strings. | 1998 // Fallback to the runtime to add the two strings. |
| 1960 Add<HPushArgument>(left); | 1999 Add<HPushArgument>(left); |
| 1961 Add<HPushArgument>(right); | 2000 Add<HPushArgument>(right); |
| 1962 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), | 2001 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), |
| 1963 Runtime::FunctionForId(Runtime::kStringAdd), | 2002 Runtime::FunctionForId(Runtime::kStringAdd), |
| 1964 2)); | 2003 2)); |
| 1965 } | 2004 } |
| 1966 if_sameencodingandsequential.End(); | 2005 if_sameencodingandsequential.End(); |
| 1967 } | 2006 } |
| 1968 if_createcons.End(); | 2007 if_createcons.End(); |
| 1969 | 2008 |
| 1970 return Pop(); | 2009 return Pop(); |
| 1971 } | 2010 } |
| 1972 | 2011 |
| 1973 | 2012 |
| 1974 HValue* HGraphBuilder::BuildStringAdd(HValue* left, | 2013 HValue* HGraphBuilder::BuildStringAdd( |
| 1975 HValue* right, | 2014 HValue* left, |
| 1976 PretenureFlag pretenure_flag) { | 2015 HValue* right, |
| 1977 // Determine the string lengths. | 2016 HAllocationMode allocation_mode) { |
| 1978 HValue* left_length = Add<HLoadNamedField>( | 2017 NoObservableSideEffectsScope no_effects(this); |
| 1979 left, HObjectAccess::ForStringLength()); | 2018 |
| 1980 HValue* right_length = Add<HLoadNamedField>( | 2019 // Determine string lengths. |
| 1981 right, HObjectAccess::ForStringLength()); | 2020 HValue* left_length = AddLoadStringLength(left); |
| 2021 HValue* right_length = AddLoadStringLength(right); | |
| 1982 | 2022 |
| 1983 // Check if left string is empty. | 2023 // Check if left string is empty. |
| 1984 IfBuilder if_leftisempty(this); | 2024 IfBuilder if_leftempty(this); |
| 1985 if_leftisempty.If<HCompareNumericAndBranch>( | 2025 if_leftempty.If<HCompareNumericAndBranch>( |
| 1986 left_length, graph()->GetConstant0(), Token::EQ); | 2026 left_length, graph()->GetConstant0(), Token::EQ); |
| 1987 if_leftisempty.Then(); | 2027 if_leftempty.Then(); |
| 1988 { | 2028 { |
| 1989 // Count the native string addition. | 2029 // Count the native string addition. |
| 1990 AddIncrementCounter(isolate()->counters()->string_add_native()); | 2030 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1991 | 2031 |
| 1992 // Just return the right string. | 2032 // Just return the right string. |
| 1993 Push(right); | 2033 Push(right); |
| 1994 } | 2034 } |
| 1995 if_leftisempty.Else(); | 2035 if_leftempty.Else(); |
| 1996 { | 2036 { |
| 1997 // Check if right string is empty. | 2037 // Check if right string is empty. |
| 1998 IfBuilder if_rightisempty(this); | 2038 IfBuilder if_rightempty(this); |
| 1999 if_rightisempty.If<HCompareNumericAndBranch>( | 2039 if_rightempty.If<HCompareNumericAndBranch>( |
| 2000 right_length, graph()->GetConstant0(), Token::EQ); | 2040 right_length, graph()->GetConstant0(), Token::EQ); |
| 2001 if_rightisempty.Then(); | 2041 if_rightempty.Then(); |
| 2002 { | 2042 { |
| 2003 // Count the native string addition. | 2043 // Count the native string addition. |
| 2004 AddIncrementCounter(isolate()->counters()->string_add_native()); | 2044 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 2005 | 2045 |
| 2006 // Just return the left string. | 2046 // Just return the left string. |
| 2007 Push(left); | 2047 Push(left); |
| 2008 } | 2048 } |
| 2009 if_rightisempty.Else(); | 2049 if_rightempty.Else(); |
| 2010 { | 2050 { |
| 2011 // Concatenate the two non-empty strings. | 2051 // Add the two non-empty strings. |
| 2012 Push(BuildUncheckedStringAdd(left, right, pretenure_flag)); | 2052 Push(BuildUncheckedStringAdd(left, right, allocation_mode)); |
| 2013 } | 2053 } |
| 2014 if_rightisempty.End(); | 2054 if_rightempty.End(); |
| 2015 } | 2055 } |
| 2016 if_leftisempty.End(); | 2056 if_leftempty.End(); |
| 2017 | 2057 |
| 2018 return Pop(); | 2058 return Pop(); |
| 2019 } | 2059 } |
| 2020 | 2060 |
| 2021 | 2061 |
| 2022 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 2062 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 2023 HValue* checked_object, | 2063 HValue* checked_object, |
| 2024 HValue* key, | 2064 HValue* key, |
| 2025 HValue* val, | 2065 HValue* val, |
| 2026 bool is_js_array, | 2066 bool is_js_array, |
| (...skipping 4110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6137 return New<HLoadNamedField>(object, access); | 6177 return New<HLoadNamedField>(object, access); |
| 6138 } | 6178 } |
| 6139 | 6179 |
| 6140 | 6180 |
| 6141 HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object, | 6181 HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object, |
| 6142 HObjectAccess access) { | 6182 HObjectAccess access) { |
| 6143 return AddInstruction(BuildLoadNamedField(object, access)); | 6183 return AddInstruction(BuildLoadNamedField(object, access)); |
| 6144 } | 6184 } |
| 6145 | 6185 |
| 6146 | 6186 |
| 6147 HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* object, | 6187 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) { |
| 6148 HValue* checked_string) { | 6188 if (string->IsConstant()) { |
| 6149 if (FLAG_fold_constants && object->IsConstant()) { | 6189 HConstant* c_string = HConstant::cast(string); |
| 6150 HConstant* constant = HConstant::cast(object); | 6190 if (c_string->HasStringValue()) { |
| 6151 if (constant->HasStringValue()) { | 6191 return Add<HConstant>(c_string->StringValue()->map()->instance_type()); |
| 6152 return New<HConstant>(constant->StringValue()->length()); | |
| 6153 } | 6192 } |
| 6154 } | 6193 } |
| 6155 return BuildLoadNamedField(checked_string, HObjectAccess::ForStringLength()); | 6194 return AddLoadNamedField( |
| 6195 AddLoadNamedField(string, HObjectAccess::ForMap()), | |
| 6196 HObjectAccess::ForMapInstanceType()); | |
| 6156 } | 6197 } |
| 6157 | 6198 |
| 6158 | 6199 |
| 6200 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) { | |
| 6201 if (string->IsConstant()) { | |
| 6202 HConstant* c_string = HConstant::cast(string); | |
| 6203 if (c_string->HasStringValue()) { | |
| 6204 return Add<HConstant>(c_string->StringValue()->length()); | |
| 6205 } | |
| 6206 } | |
| 6207 return AddLoadNamedField(string, HObjectAccess::ForStringLength()); | |
| 6208 } | |
| 6209 | |
| 6210 | |
| 6159 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( | 6211 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( |
| 6160 HValue* object, | 6212 HValue* object, |
| 6161 Handle<String> name, | 6213 Handle<String> name, |
| 6162 Property* expr) { | 6214 Property* expr) { |
| 6163 if (expr->IsUninitialized()) { | 6215 if (expr->IsUninitialized()) { |
| 6164 Add<HDeoptimize>("Insufficient type feedback for generic named load", | 6216 Add<HDeoptimize>("Insufficient type feedback for generic named load", |
| 6165 Deoptimizer::SOFT); | 6217 Deoptimizer::SOFT); |
| 6166 } | 6218 } |
| 6167 return New<HLoadNamedGeneric>(object, name); | 6219 return New<HLoadNamedGeneric>(object, name); |
| 6168 } | 6220 } |
| (...skipping 2424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8593 HConstant* c_index = HConstant::cast(index); | 8645 HConstant* c_index = HConstant::cast(index); |
| 8594 if (c_string->HasStringValue() && c_index->HasNumberValue()) { | 8646 if (c_string->HasStringValue() && c_index->HasNumberValue()) { |
| 8595 int32_t i = c_index->NumberValueAsInteger32(); | 8647 int32_t i = c_index->NumberValueAsInteger32(); |
| 8596 Handle<String> s = c_string->StringValue(); | 8648 Handle<String> s = c_string->StringValue(); |
| 8597 if (i < 0 || i >= s->length()) { | 8649 if (i < 0 || i >= s->length()) { |
| 8598 return New<HConstant>(OS::nan_value()); | 8650 return New<HConstant>(OS::nan_value()); |
| 8599 } | 8651 } |
| 8600 return New<HConstant>(s->Get(i)); | 8652 return New<HConstant>(s->Get(i)); |
| 8601 } | 8653 } |
| 8602 } | 8654 } |
| 8603 BuildCheckHeapObject(string); | 8655 string = BuildCheckString(string); |
| 8604 HValue* checkstring = | 8656 index = Add<HBoundsCheck>(index, AddLoadStringLength(string)); |
| 8605 Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); | 8657 return New<HStringCharCodeAt>(string, index); |
| 8606 HInstruction* length = BuildLoadStringLength(string, checkstring); | |
| 8607 AddInstruction(length); | |
| 8608 HInstruction* checked_index = Add<HBoundsCheck>(index, length); | |
| 8609 return New<HStringCharCodeAt>(string, checked_index); | |
| 8610 } | 8658 } |
| 8611 | 8659 |
| 8612 | 8660 |
| 8613 // Checks if the given shift amounts have following forms: | 8661 // Checks if the given shift amounts have following forms: |
| 8614 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa). | 8662 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa). |
| 8615 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, | 8663 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, |
| 8616 HValue* const32_minus_sa) { | 8664 HValue* const32_minus_sa) { |
| 8617 if (sa->IsConstant() && const32_minus_sa->IsConstant()) { | 8665 if (sa->IsConstant() && const32_minus_sa->IsConstant()) { |
| 8618 const HConstant* c1 = HConstant::cast(sa); | 8666 const HConstant* c1 = HConstant::cast(sa); |
| 8619 const HConstant* c2 = HConstant::cast(const32_minus_sa); | 8667 const HConstant* c2 = HConstant::cast(const32_minus_sa); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8730 | 8778 |
| 8731 | 8779 |
| 8732 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( | 8780 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( |
| 8733 BinaryOperation* expr, | 8781 BinaryOperation* expr, |
| 8734 HValue* left, | 8782 HValue* left, |
| 8735 HValue* right) { | 8783 HValue* right) { |
| 8736 Handle<Type> left_type = expr->left()->bounds().lower; | 8784 Handle<Type> left_type = expr->left()->bounds().lower; |
| 8737 Handle<Type> right_type = expr->right()->bounds().lower; | 8785 Handle<Type> right_type = expr->right()->bounds().lower; |
| 8738 Handle<Type> result_type = expr->bounds().lower; | 8786 Handle<Type> result_type = expr->bounds().lower; |
| 8739 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); | 8787 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); |
| 8788 Handle<AllocationSite> allocation_site = expr->allocation_site(); | |
| 8789 | |
| 8790 HAllocationMode allocation_mode = | |
| 8791 FLAG_allocation_site_pretenuring | |
| 8792 ? (allocation_site.is_null() | |
| 8793 ? HAllocationMode(NOT_TENURED) | |
| 8794 : HAllocationMode(allocation_site)) | |
| 8795 : HAllocationMode(isolate()->heap()->GetPretenureMode()); | |
| 8740 | 8796 |
| 8741 HValue* result = HGraphBuilder::BuildBinaryOperation( | 8797 HValue* result = HGraphBuilder::BuildBinaryOperation( |
| 8742 expr->op(), left, right, left_type, right_type, | 8798 expr->op(), left, right, left_type, right_type, result_type, |
| 8743 result_type, fixed_right_arg); | 8799 fixed_right_arg, allocation_mode); |
| 8744 // Add a simulate after instructions with observable side effects, and | 8800 // Add a simulate after instructions with observable side effects, and |
| 8745 // after phis, which are the result of BuildBinaryOperation when we | 8801 // after phis, which are the result of BuildBinaryOperation when we |
| 8746 // inlined some complex subgraph. | 8802 // inlined some complex subgraph. |
| 8747 if (result->HasObservableSideEffects() || result->IsPhi()) { | 8803 if (result->HasObservableSideEffects() || result->IsPhi()) { |
| 8748 Push(result); | 8804 Push(result); |
| 8749 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 8805 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 8750 Drop(1); | 8806 Drop(1); |
| 8751 } | 8807 } |
| 8752 return result; | 8808 return result; |
| 8753 } | 8809 } |
| 8754 | 8810 |
| 8755 | 8811 |
| 8756 HValue* HGraphBuilder::BuildBinaryOperation( | 8812 HValue* HGraphBuilder::BuildBinaryOperation( |
| 8757 Token::Value op, | 8813 Token::Value op, |
| 8758 HValue* left, | 8814 HValue* left, |
| 8759 HValue* right, | 8815 HValue* right, |
| 8760 Handle<Type> left_type, | 8816 Handle<Type> left_type, |
| 8761 Handle<Type> right_type, | 8817 Handle<Type> right_type, |
| 8762 Handle<Type> result_type, | 8818 Handle<Type> result_type, |
| 8763 Maybe<int> fixed_right_arg) { | 8819 Maybe<int> fixed_right_arg, |
| 8820 HAllocationMode allocation_mode) { | |
| 8764 | 8821 |
| 8765 Representation left_rep = Representation::FromType(left_type); | 8822 Representation left_rep = Representation::FromType(left_type); |
| 8766 Representation right_rep = Representation::FromType(right_type); | 8823 Representation right_rep = Representation::FromType(right_type); |
| 8767 | 8824 |
| 8768 bool maybe_string_add = op == Token::ADD && | 8825 bool maybe_string_add = op == Token::ADD && |
| 8769 (left_type->Maybe(Type::String()) || | 8826 (left_type->Maybe(Type::String()) || |
| 8770 right_type->Maybe(Type::String())); | 8827 right_type->Maybe(Type::String())); |
| 8771 | 8828 |
| 8772 if (left_type->Is(Type::None())) { | 8829 if (left_type->Is(Type::None())) { |
| 8773 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", | 8830 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8819 ASSERT(left_type->Is(Type::String())); | 8876 ASSERT(left_type->Is(Type::String())); |
| 8820 right = BuildNumberToString(right, right_type); | 8877 right = BuildNumberToString(right, right_type); |
| 8821 } else if (!right_type->Is(Type::String())) { | 8878 } else if (!right_type->Is(Type::String())) { |
| 8822 ASSERT(left_type->Is(Type::String())); | 8879 ASSERT(left_type->Is(Type::String())); |
| 8823 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); | 8880 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); |
| 8824 Add<HPushArgument>(left); | 8881 Add<HPushArgument>(left); |
| 8825 Add<HPushArgument>(right); | 8882 Add<HPushArgument>(right); |
| 8826 return AddUncasted<HInvokeFunction>(function, 2); | 8883 return AddUncasted<HInvokeFunction>(function, 2); |
| 8827 } | 8884 } |
| 8828 | 8885 |
| 8829 return AddUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE); | 8886 // Inline the string addition into the stub when creating allocation |
| 8887 // mementos to gather allocation site feedback. | |
| 8888 if (graph()->info()->IsStub() && | |
| 8889 allocation_mode.CreateAllocationMementos()) { | |
| 8890 return BuildStringAdd(left, right, allocation_mode); | |
|
mvstanton
2013/12/11 14:14:20
If you are building a stub, can you count on havin
Benedikt Meurer
2013/12/11 17:50:45
No, because this code is also used for the BinaryO
| |
| 8891 } | |
| 8892 | |
| 8893 // Register the dependent code with the allocation site. | |
| 8894 if (!allocation_mode.feedback_site().is_null()) { | |
| 8895 ASSERT(!graph()->info()->IsStub()); | |
| 8896 allocation_mode.feedback_site()->AddDependentCompilationInfo( | |
| 8897 AllocationSite::TENURING, top_info()); | |
| 8898 } | |
| 8899 | |
| 8900 // Inline string addition if we know that we'll create a cons string. | |
| 8901 if (left->IsConstant()) { | |
| 8902 HConstant* c_left = HConstant::cast(left); | |
| 8903 if (c_left->HasStringValue()) { | |
| 8904 if (c_left->StringValue()->length() + 1 >= ConsString::kMinLength) { | |
|
mvstanton
2013/12/11 14:14:20
nit: put the "base case" of empty left string firs
Benedikt Meurer
2013/12/11 17:50:45
Done.
| |
| 8905 return BuildStringAdd(left, right, allocation_mode); | |
| 8906 } else if (c_left->StringValue()->length() == 0) { | |
| 8907 return right; | |
| 8908 } | |
| 8909 } | |
| 8910 } | |
| 8911 if (right->IsConstant()) { | |
| 8912 HConstant* c_right = HConstant::cast(right); | |
| 8913 if (c_right->HasStringValue()) { | |
| 8914 if (c_right->StringValue()->length() + 1 >= ConsString::kMinLength) { | |
|
mvstanton
2013/12/11 14:14:20
Same here.
Benedikt Meurer
2013/12/11 17:50:45
Done.
| |
| 8915 return BuildStringAdd(left, right, allocation_mode); | |
| 8916 } else if (c_right->StringValue()->length() == 0) { | |
| 8917 return left; | |
| 8918 } | |
| 8919 } | |
| 8920 } | |
| 8921 | |
| 8922 // Fallback to using the string add stub. | |
| 8923 return AddUncasted<HStringAdd>( | |
| 8924 left, right, allocation_mode.GetPretenureMode(), | |
| 8925 STRING_ADD_CHECK_NONE, allocation_mode.feedback_site()); | |
| 8830 } | 8926 } |
| 8831 | 8927 |
| 8832 if (graph()->info()->IsStub()) { | 8928 if (graph()->info()->IsStub()) { |
| 8833 left = EnforceNumberType(left, left_type); | 8929 left = EnforceNumberType(left, left_type); |
| 8834 right = EnforceNumberType(right, right_type); | 8930 right = EnforceNumberType(right, right_type); |
| 8835 } | 8931 } |
| 8836 | 8932 |
| 8837 Representation result_rep = Representation::FromType(result_type); | 8933 Representation result_rep = Representation::FromType(result_type); |
| 8838 | 8934 |
| 8839 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || | 8935 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || |
| (...skipping 1182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10022 } | 10118 } |
| 10023 | 10119 |
| 10024 | 10120 |
| 10025 // Fast support for StringAdd. | 10121 // Fast support for StringAdd. |
| 10026 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) { | 10122 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) { |
| 10027 ASSERT_EQ(2, call->arguments()->length()); | 10123 ASSERT_EQ(2, call->arguments()->length()); |
| 10028 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10124 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10029 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10125 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10030 HValue* right = Pop(); | 10126 HValue* right = Pop(); |
| 10031 HValue* left = Pop(); | 10127 HValue* left = Pop(); |
| 10032 HInstruction* result = | 10128 HInstruction* result = NewUncasted<HStringAdd>(left, right); |
| 10033 NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_BOTH); | |
| 10034 return ast_context()->ReturnInstruction(result, call->id()); | 10129 return ast_context()->ReturnInstruction(result, call->id()); |
| 10035 } | 10130 } |
| 10036 | 10131 |
| 10037 | 10132 |
| 10038 // Fast support for SubString. | 10133 // Fast support for SubString. |
| 10039 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) { | 10134 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) { |
| 10040 ASSERT_EQ(3, call->arguments()->length()); | 10135 ASSERT_EQ(3, call->arguments()->length()); |
| 10041 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 10136 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 10042 HCallStub* result = New<HCallStub>(CodeStub::SubString, 3); | 10137 HCallStub* result = New<HCallStub>(CodeStub::SubString, 3); |
| 10043 Drop(3); | 10138 Drop(3); |
| (...skipping 769 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10813 if (ShouldProduceTraceOutput()) { | 10908 if (ShouldProduceTraceOutput()) { |
| 10814 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10909 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 10815 } | 10910 } |
| 10816 | 10911 |
| 10817 #ifdef DEBUG | 10912 #ifdef DEBUG |
| 10818 graph_->Verify(false); // No full verify. | 10913 graph_->Verify(false); // No full verify. |
| 10819 #endif | 10914 #endif |
| 10820 } | 10915 } |
| 10821 | 10916 |
| 10822 } } // namespace v8::internal | 10917 } } // namespace v8::internal |
| OLD | NEW |