| 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 1715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1726 | 1726 |
| 1727 HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left, | 1727 HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left, |
| 1728 HValue* right, | 1728 HValue* right, |
| 1729 PretenureFlag pretenure_flag) { | 1729 PretenureFlag pretenure_flag) { |
| 1730 // Determine the string lengths. | 1730 // Determine the string lengths. |
| 1731 HValue* left_length = Add<HLoadNamedField>( | 1731 HValue* left_length = Add<HLoadNamedField>( |
| 1732 left, HObjectAccess::ForStringLength()); | 1732 left, HObjectAccess::ForStringLength()); |
| 1733 HValue* right_length = Add<HLoadNamedField>( | 1733 HValue* right_length = Add<HLoadNamedField>( |
| 1734 right, HObjectAccess::ForStringLength()); | 1734 right, HObjectAccess::ForStringLength()); |
| 1735 | 1735 |
| 1736 // Check if we concatenated the strings here, or if we have to resort to the | 1736 // Compute the combined string length. If the result is larger than the max |
| 1737 // runtime function. | 1737 // supported string length, we bailout to the runtime. This is done implicitly |
| 1738 HIfContinuation handled(graph()->CreateBasicBlock(), | 1738 // when converting the result back to a smi in case the max string length |
| 1739 graph()->CreateBasicBlock()); | 1739 // equals the max smi valie. Otherwise, for platforms with 32-bit smis, we do |
| 1740 | 1740 HValue* length = AddUncasted<HAdd>(left_length, right_length); |
| 1741 // Check if both parameters do not exceed half the max string length, because | 1741 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); |
| 1742 // exceptionally long strings should be handled in the runtime. Unfortunately | 1742 if (String::kMaxLength != Smi::kMaxValue) { |
| 1743 // we cannot actually check whether the combined length of both strings | 1743 IfBuilder if_nooverflow(this); |
| 1744 // exceeds String::kMaxLength (because of unclear results from the | 1744 if_nooverflow.If<HCompareNumericAndBranch>( |
| 1745 // representation inference phase), so we use a pessimistic approach here | 1745 length, Add<HConstant>(String::kMaxLength), Token::LTE); |
| 1746 // instead, checking that the length of either substring does not exceed half | 1746 if_nooverflow.Then(); |
| 1747 // of String::kMaxLength. | 1747 if_nooverflow.ElseDeopt("String length exceeds limit"); |
| 1748 HConstant* max_length = Add<HConstant>(String::kMaxLength / 2); | 1748 } |
| 1749 IfBuilder if_nooverflow(this); | 1749 |
| 1750 if_nooverflow.If<HCompareNumericAndBranch>( | 1750 // Determine the string instance types. |
| 1751 left_length, max_length, Token::LTE); | 1751 HLoadNamedField* left_instance_type = Add<HLoadNamedField>( |
| 1752 if_nooverflow.AndIf<HCompareNumericAndBranch>( | 1752 Add<HLoadNamedField>(left, HObjectAccess::ForMap()), |
| 1753 right_length, max_length, Token::LTE); | 1753 HObjectAccess::ForMapInstanceType()); |
| 1754 if_nooverflow.Then(); | 1754 HLoadNamedField* right_instance_type = Add<HLoadNamedField>( |
| 1755 Add<HLoadNamedField>(right, HObjectAccess::ForMap()), |
| 1756 HObjectAccess::ForMapInstanceType()); |
| 1757 |
| 1758 // Compute difference of instance types. |
| 1759 HValue* xored_instance_types = AddUncasted<HBitwise>( |
| 1760 Token::BIT_XOR, left_instance_type, right_instance_type); |
| 1761 |
| 1762 // Check if we should create a cons string. |
| 1763 IfBuilder if_createcons(this); |
| 1764 if_createcons.If<HCompareNumericAndBranch>( |
| 1765 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); |
| 1766 if_createcons.Then(); |
| 1755 { | 1767 { |
| 1756 // Determine the string instance types. | 1768 // Allocate the cons string object. HAllocate does not care whether we |
| 1757 HLoadNamedField* left_instance_type = Add<HLoadNamedField>( | 1769 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use |
| 1758 Add<HLoadNamedField>(left, HObjectAccess::ForMap()), | 1770 // CONS_STRING_TYPE here. Below we decide whether the cons string is |
| 1759 HObjectAccess::ForMapInstanceType()); | 1771 // one-byte or two-byte and set the appropriate map. |
| 1760 HLoadNamedField* right_instance_type = Add<HLoadNamedField>( | 1772 HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize), |
| 1761 Add<HLoadNamedField>(right, HObjectAccess::ForMap()), | 1773 HType::String(), pretenure_flag, |
| 1762 HObjectAccess::ForMapInstanceType()); | 1774 CONS_STRING_TYPE); |
| 1763 | 1775 |
| 1764 // Compute difference of instance types. | 1776 // Compute the intersection of instance types. |
| 1765 HValue* xored_instance_types = AddUncasted<HBitwise>( | 1777 HValue* anded_instance_types = AddUncasted<HBitwise>( |
| 1766 Token::BIT_XOR, left_instance_type, right_instance_type); | 1778 Token::BIT_AND, left_instance_type, right_instance_type); |
| 1767 | 1779 |
| 1768 // Compute the length of the resulting string. | 1780 // We create a one-byte cons string if |
| 1769 HValue* length = AddUncasted<HAdd>(left_length, right_length); | 1781 // 1. both strings are one-byte, or |
| 1770 | 1782 // 2. at least one of the strings is two-byte, but happens to contain only |
| 1771 // Check if we should create a cons string. | 1783 // one-byte characters. |
| 1772 IfBuilder if_createcons(this); | 1784 // To do this, we check |
| 1773 if_createcons.If<HCompareNumericAndBranch>( | 1785 // 1. if both strings are one-byte, or if the one-byte data hint is set in |
| 1774 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); | 1786 // both strings, or |
| 1775 if_createcons.Then(); | 1787 // 2. if one of the strings has the one-byte data hint set and the other |
| 1776 { | 1788 // string is one-byte. |
| 1777 // Allocate the cons string object. HAllocate does not care whether we | 1789 IfBuilder if_onebyte(this); |
| 1778 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use | 1790 STATIC_ASSERT(kOneByteStringTag != 0); |
| 1779 // CONS_STRING_TYPE here. Below we decide whether the cons string is | 1791 STATIC_ASSERT(kOneByteDataHintMask != 0); |
| 1780 // one-byte or two-byte and set the appropriate map. | 1792 if_onebyte.If<HCompareNumericAndBranch>( |
| 1781 HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize), | 1793 AddUncasted<HBitwise>( |
| 1782 HType::String(), pretenure_flag, | 1794 Token::BIT_AND, anded_instance_types, |
| 1783 CONS_STRING_TYPE); | 1795 Add<HConstant>(static_cast<int32_t>( |
| 1784 | 1796 kStringEncodingMask | kOneByteDataHintMask))), |
| 1785 // Compute the intersection of instance types. | 1797 graph()->GetConstant0(), Token::NE); |
| 1786 HValue* anded_instance_types = AddUncasted<HBitwise>( | 1798 if_onebyte.Or(); |
| 1787 Token::BIT_AND, left_instance_type, right_instance_type); | 1799 STATIC_ASSERT(kOneByteStringTag != 0 && |
| 1788 | 1800 kOneByteDataHintTag != 0 && |
| 1789 // We create a one-byte cons string if | 1801 kOneByteDataHintTag != kOneByteStringTag); |
| 1790 // 1. both strings are one-byte, or | 1802 if_onebyte.If<HCompareNumericAndBranch>( |
| 1791 // 2. at least one of the strings is two-byte, but happens to contain only | 1803 AddUncasted<HBitwise>( |
| 1792 // one-byte characters. | 1804 Token::BIT_AND, xored_instance_types, |
| 1793 // To do this, we check | 1805 Add<HConstant>(static_cast<int32_t>( |
| 1794 // 1. if both strings are one-byte, or if the one-byte data hint is set in | 1806 kOneByteStringTag | kOneByteDataHintTag))), |
| 1795 // both strings, or | 1807 Add<HConstant>(static_cast<int32_t>( |
| 1796 // 2. if one of the strings has the one-byte data hint set and the other | 1808 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); |
| 1797 // string is one-byte. | 1809 if_onebyte.Then(); |
| 1810 { |
| 1811 // We can safely skip the write barrier for storing the map here. |
| 1812 Handle<Map> map = isolate()->factory()->cons_ascii_string_map(); |
| 1813 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1814 } |
| 1815 if_onebyte.Else(); |
| 1816 { |
| 1817 // We can safely skip the write barrier for storing the map here. |
| 1818 Handle<Map> map = isolate()->factory()->cons_string_map(); |
| 1819 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1820 } |
| 1821 if_onebyte.End(); |
| 1822 |
| 1823 // Initialize the cons string fields. |
| 1824 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), |
| 1825 Add<HConstant>(String::kEmptyHashField)); |
| 1826 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length); |
| 1827 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left); |
| 1828 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(), |
| 1829 right); |
| 1830 |
| 1831 // Count the native string addition. |
| 1832 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1833 |
| 1834 // Cons string is result. |
| 1835 Push(string); |
| 1836 } |
| 1837 if_createcons.Else(); |
| 1838 { |
| 1839 // Compute union of instance types. |
| 1840 HValue* ored_instance_types = AddUncasted<HBitwise>( |
| 1841 Token::BIT_OR, left_instance_type, right_instance_type); |
| 1842 |
| 1843 // Check if both strings have the same encoding and both are |
| 1844 // sequential. |
| 1845 IfBuilder if_sameencodingandsequential(this); |
| 1846 if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
| 1847 AddUncasted<HBitwise>( |
| 1848 Token::BIT_AND, xored_instance_types, |
| 1849 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
| 1850 graph()->GetConstant0(), Token::EQ); |
| 1851 if_sameencodingandsequential.And(); |
| 1852 STATIC_ASSERT(kSeqStringTag == 0); |
| 1853 if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
| 1854 AddUncasted<HBitwise>( |
| 1855 Token::BIT_AND, ored_instance_types, |
| 1856 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), |
| 1857 graph()->GetConstant0(), Token::EQ); |
| 1858 if_sameencodingandsequential.Then(); |
| 1859 { |
| 1860 // Check if the result is a one-byte string. |
| 1798 IfBuilder if_onebyte(this); | 1861 IfBuilder if_onebyte(this); |
| 1799 STATIC_ASSERT(kOneByteStringTag != 0); | 1862 STATIC_ASSERT(kOneByteStringTag != 0); |
| 1800 STATIC_ASSERT(kOneByteDataHintMask != 0); | |
| 1801 if_onebyte.If<HCompareNumericAndBranch>( | 1863 if_onebyte.If<HCompareNumericAndBranch>( |
| 1802 AddUncasted<HBitwise>( | 1864 AddUncasted<HBitwise>( |
| 1803 Token::BIT_AND, anded_instance_types, | 1865 Token::BIT_AND, ored_instance_types, |
| 1804 Add<HConstant>(static_cast<int32_t>( | 1866 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
| 1805 kStringEncodingMask | kOneByteDataHintMask))), | |
| 1806 graph()->GetConstant0(), Token::NE); | 1867 graph()->GetConstant0(), Token::NE); |
| 1807 if_onebyte.Or(); | |
| 1808 STATIC_ASSERT(kOneByteStringTag != 0 && | |
| 1809 kOneByteDataHintTag != 0 && | |
| 1810 kOneByteDataHintTag != kOneByteStringTag); | |
| 1811 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1812 AddUncasted<HBitwise>( | |
| 1813 Token::BIT_AND, xored_instance_types, | |
| 1814 Add<HConstant>(static_cast<int32_t>( | |
| 1815 kOneByteStringTag | kOneByteDataHintTag))), | |
| 1816 Add<HConstant>(static_cast<int32_t>( | |
| 1817 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); | |
| 1818 if_onebyte.Then(); | 1868 if_onebyte.Then(); |
| 1819 { | 1869 { |
| 1820 // We can safely skip the write barrier for storing the map here. | 1870 // Calculate the number of bytes needed for the characters in the |
| 1821 Handle<Map> map = isolate()->factory()->cons_ascii_string_map(); | 1871 // string while observing object alignment. |
| 1872 HValue* size = BuildSeqStringSizeFor( |
| 1873 length, String::ONE_BYTE_ENCODING); |
| 1874 |
| 1875 // Allocate the ASCII string object. |
| 1876 Handle<Map> map = isolate()->factory()->ascii_string_map(); |
| 1877 HAllocate* string = Add<HAllocate>(size, HType::String(), |
| 1878 pretenure_flag, ASCII_STRING_TYPE); |
| 1879 string->set_known_initial_map(map); |
| 1880 |
| 1881 // We can safely skip the write barrier for storing map here. |
| 1822 AddStoreMapConstantNoWriteBarrier(string, map); | 1882 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1883 |
| 1884 // Length must be stored into the string before we copy characters to |
| 1885 // make debug verification code happy. |
| 1886 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), |
| 1887 length); |
| 1888 |
| 1889 // Copy bytes from the left string. |
| 1890 BuildCopySeqStringChars( |
| 1891 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1892 string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1893 left_length); |
| 1894 |
| 1895 // Copy bytes from the right string. |
| 1896 BuildCopySeqStringChars( |
| 1897 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1898 string, left_length, String::ONE_BYTE_ENCODING, |
| 1899 right_length); |
| 1900 |
| 1901 // Count the native string addition. |
| 1902 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1903 |
| 1904 // Return the string. |
| 1905 Push(string); |
| 1823 } | 1906 } |
| 1824 if_onebyte.Else(); | 1907 if_onebyte.Else(); |
| 1825 { | 1908 { |
| 1826 // We can safely skip the write barrier for storing the map here. | 1909 // Calculate the number of bytes needed for the characters in the |
| 1827 Handle<Map> map = isolate()->factory()->cons_string_map(); | 1910 // string while observing object alignment. |
| 1911 HValue* size = BuildSeqStringSizeFor( |
| 1912 length, String::TWO_BYTE_ENCODING); |
| 1913 |
| 1914 // Allocate the two-byte string object. |
| 1915 Handle<Map> map = isolate()->factory()->string_map(); |
| 1916 HAllocate* string = Add<HAllocate>(size, HType::String(), |
| 1917 pretenure_flag, STRING_TYPE); |
| 1918 string->set_known_initial_map(map); |
| 1919 |
| 1920 // We can safely skip the write barrier for storing map here. |
| 1828 AddStoreMapConstantNoWriteBarrier(string, map); | 1921 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1922 |
| 1923 // Length must be stored into the string before we copy characters to |
| 1924 // make debug verification code happy. |
| 1925 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), |
| 1926 length); |
| 1927 |
| 1928 // Copy bytes from the left string. |
| 1929 BuildCopySeqStringChars( |
| 1930 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1931 string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1932 left_length); |
| 1933 |
| 1934 // Copy bytes from the right string. |
| 1935 BuildCopySeqStringChars( |
| 1936 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1937 string, left_length, String::TWO_BYTE_ENCODING, |
| 1938 right_length); |
| 1939 |
| 1940 // Return the string. |
| 1941 Push(string); |
| 1829 } | 1942 } |
| 1830 if_onebyte.End(); | 1943 if_onebyte.End(); |
| 1831 | 1944 |
| 1832 // Initialize the cons string fields. | 1945 // Initialize the (common) string fields. |
| 1946 HValue* string = Pop(); |
| 1833 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), | 1947 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), |
| 1834 Add<HConstant>(String::kEmptyHashField)); | 1948 Add<HConstant>(String::kEmptyHashField)); |
| 1835 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length); | 1949 |
| 1836 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left); | 1950 // Count the native string addition. |
| 1837 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(), | 1951 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1838 right); | 1952 |
| 1839 | |
| 1840 // Cons string is result. | |
| 1841 Push(string); | 1953 Push(string); |
| 1842 } | 1954 } |
| 1843 if_createcons.Else(); | 1955 if_sameencodingandsequential.Else(); |
| 1844 { | 1956 { |
| 1845 // Compute union of instance types. | 1957 // Fallback to the runtime to add the two strings. |
| 1846 HValue* ored_instance_types = AddUncasted<HBitwise>( | 1958 Add<HPushArgument>(left); |
| 1847 Token::BIT_OR, left_instance_type, right_instance_type); | 1959 Add<HPushArgument>(right); |
| 1848 | 1960 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), |
| 1849 // Check if both strings have the same encoding and both are | 1961 Runtime::FunctionForId(Runtime::kStringAdd), |
| 1850 // sequential. | 1962 2)); |
| 1851 IfBuilder if_sameencodingandsequential(this); | 1963 } |
| 1852 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | 1964 if_sameencodingandsequential.End(); |
| 1853 AddUncasted<HBitwise>( | |
| 1854 Token::BIT_AND, xored_instance_types, | |
| 1855 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | |
| 1856 graph()->GetConstant0(), Token::EQ); | |
| 1857 if_sameencodingandsequential.And(); | |
| 1858 STATIC_ASSERT(kSeqStringTag == 0); | |
| 1859 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | |
| 1860 AddUncasted<HBitwise>( | |
| 1861 Token::BIT_AND, ored_instance_types, | |
| 1862 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), | |
| 1863 graph()->GetConstant0(), Token::EQ); | |
| 1864 if_sameencodingandsequential.Then(); | |
| 1865 { | |
| 1866 // Check if the result is a one-byte string. | |
| 1867 IfBuilder if_onebyte(this); | |
| 1868 STATIC_ASSERT(kOneByteStringTag != 0); | |
| 1869 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1870 AddUncasted<HBitwise>( | |
| 1871 Token::BIT_AND, ored_instance_types, | |
| 1872 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | |
| 1873 graph()->GetConstant0(), Token::NE); | |
| 1874 if_onebyte.Then(); | |
| 1875 { | |
| 1876 // Calculate the number of bytes needed for the characters in the | |
| 1877 // string while observing object alignment. | |
| 1878 HValue* size = BuildSeqStringSizeFor( | |
| 1879 length, String::ONE_BYTE_ENCODING); | |
| 1880 | |
| 1881 // Allocate the ASCII string object. | |
| 1882 Handle<Map> map = isolate()->factory()->ascii_string_map(); | |
| 1883 HAllocate* string = Add<HAllocate>(size, HType::String(), | |
| 1884 pretenure_flag, ASCII_STRING_TYPE); | |
| 1885 string->set_known_initial_map(map); | |
| 1886 | |
| 1887 // We can safely skip the write barrier for storing map here. | |
| 1888 AddStoreMapConstantNoWriteBarrier(string, map); | |
| 1889 | |
| 1890 // Length must be stored into the string before we copy characters to | |
| 1891 // make debug verification code happy. | |
| 1892 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), | |
| 1893 length); | |
| 1894 | |
| 1895 // Copy bytes from the left string. | |
| 1896 BuildCopySeqStringChars( | |
| 1897 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1898 string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1899 left_length); | |
| 1900 | |
| 1901 // Copy bytes from the right string. | |
| 1902 BuildCopySeqStringChars( | |
| 1903 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1904 string, left_length, String::ONE_BYTE_ENCODING, | |
| 1905 right_length); | |
| 1906 | |
| 1907 // Return the string. | |
| 1908 Push(string); | |
| 1909 } | |
| 1910 if_onebyte.Else(); | |
| 1911 { | |
| 1912 // Calculate the number of bytes needed for the characters in the | |
| 1913 // string while observing object alignment. | |
| 1914 HValue* size = BuildSeqStringSizeFor( | |
| 1915 length, String::TWO_BYTE_ENCODING); | |
| 1916 | |
| 1917 // Allocate the two-byte string object. | |
| 1918 Handle<Map> map = isolate()->factory()->string_map(); | |
| 1919 HAllocate* string = Add<HAllocate>(size, HType::String(), | |
| 1920 pretenure_flag, STRING_TYPE); | |
| 1921 string->set_known_initial_map(map); | |
| 1922 | |
| 1923 // We can safely skip the write barrier for storing map here. | |
| 1924 AddStoreMapConstantNoWriteBarrier(string, map); | |
| 1925 | |
| 1926 // Length must be stored into the string before we copy characters to | |
| 1927 // make debug verification code happy. | |
| 1928 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), | |
| 1929 length); | |
| 1930 | |
| 1931 // Copy bytes from the left string. | |
| 1932 BuildCopySeqStringChars( | |
| 1933 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
| 1934 string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
| 1935 left_length); | |
| 1936 | |
| 1937 // Copy bytes from the right string. | |
| 1938 BuildCopySeqStringChars( | |
| 1939 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
| 1940 string, left_length, String::TWO_BYTE_ENCODING, | |
| 1941 right_length); | |
| 1942 | |
| 1943 // Return the string. | |
| 1944 Push(string); | |
| 1945 } | |
| 1946 if_onebyte.End(); | |
| 1947 | |
| 1948 // Initialize the (common) string fields. | |
| 1949 HValue* string = Pop(); | |
| 1950 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), | |
| 1951 Add<HConstant>(String::kEmptyHashField)); | |
| 1952 Push(string); | |
| 1953 } | |
| 1954 if_sameencodingandsequential.JoinContinuation(&handled); | |
| 1955 } | |
| 1956 if_createcons.JoinContinuation(&handled); | |
| 1957 } | 1965 } |
| 1958 if_nooverflow.JoinContinuation(&handled); | 1966 if_createcons.End(); |
| 1959 | |
| 1960 // Check if the strings were concatenated successfully, otherwise fallback to | |
| 1961 // add the strings in the runtime. | |
| 1962 IfBuilder if_handled(this, &handled); | |
| 1963 if_handled.Then(); | |
| 1964 { | |
| 1965 // Count the native string addition. | |
| 1966 AddIncrementCounter(isolate()->counters()->string_add_native()); | |
| 1967 } | |
| 1968 if_handled.Else(); | |
| 1969 { | |
| 1970 // Fallback to the runtime to add the two strings. | |
| 1971 Add<HPushArgument>(left); | |
| 1972 Add<HPushArgument>(right); | |
| 1973 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), | |
| 1974 Runtime::FunctionForId(Runtime::kStringAdd), | |
| 1975 2)); | |
| 1976 } | |
| 1977 if_handled.End(); | |
| 1978 | 1967 |
| 1979 return Pop(); | 1968 return Pop(); |
| 1980 } | 1969 } |
| 1981 | 1970 |
| 1982 | 1971 |
| 1983 HValue* HGraphBuilder::BuildStringAdd(HValue* left, | 1972 HValue* HGraphBuilder::BuildStringAdd(HValue* left, |
| 1984 HValue* right, | 1973 HValue* right, |
| 1985 PretenureFlag pretenure_flag) { | 1974 PretenureFlag pretenure_flag) { |
| 1986 // Determine the string lengths. | 1975 // Determine the string lengths. |
| 1987 HValue* left_length = Add<HLoadNamedField>( | 1976 HValue* left_length = Add<HLoadNamedField>( |
| (...skipping 8677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10665 if (ShouldProduceTraceOutput()) { | 10654 if (ShouldProduceTraceOutput()) { |
| 10666 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10655 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 10667 } | 10656 } |
| 10668 | 10657 |
| 10669 #ifdef DEBUG | 10658 #ifdef DEBUG |
| 10670 graph_->Verify(false); // No full verify. | 10659 graph_->Verify(false); // No full verify. |
| 10671 #endif | 10660 #endif |
| 10672 } | 10661 } |
| 10673 | 10662 |
| 10674 } } // namespace v8::internal | 10663 } } // namespace v8::internal |
| OLD | NEW |