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 |