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 1675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1686 isolate()->factory()->empty_string(), | 1686 isolate()->factory()->empty_string(), |
1687 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), | 1687 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), |
1688 1)); | 1688 1)); |
1689 } | 1689 } |
1690 if_found.End(); | 1690 if_found.End(); |
1691 | 1691 |
1692 return Pop(); | 1692 return Pop(); |
1693 } | 1693 } |
1694 | 1694 |
1695 | 1695 |
1696 HAllocate* HGraphBuilder::BuildAllocate( | 1696 HValue* HGraphBuilder::BuildSeqStringSizeFor(HValue* length, |
1697 HValue* object_size, | 1697 String::Encoding encoding) { |
1698 HType type, | 1698 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0); |
1699 InstanceType instance_type, | 1699 HValue* size = length; |
1700 HAllocationMode allocation_mode) { | 1700 if (encoding == String::TWO_BYTE_ENCODING) { |
1701 // Compute the effective allocation size. | 1701 size = AddUncasted<HShl>(length, graph()->GetConstant1()); |
1702 HValue* size = object_size; | |
1703 if (allocation_mode.CreateAllocationMementos()) { | |
1704 size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize)); | |
1705 size->ClearFlag(HValue::kCanOverflow); | 1702 size->ClearFlag(HValue::kCanOverflow); |
| 1703 size->SetFlag(HValue::kUint32); |
1706 } | 1704 } |
1707 | 1705 size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>( |
1708 // Perform the actual allocation. | 1706 SeqString::kHeaderSize + kObjectAlignmentMask))); |
1709 HAllocate* object = Add<HAllocate>( | 1707 size->ClearFlag(HValue::kCanOverflow); |
1710 size, type, allocation_mode.GetPretenureMode(), | 1708 size = AddUncasted<HBitwise>( |
1711 instance_type, allocation_mode.feedback_site()); | 1709 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( |
1712 | 1710 ~kObjectAlignmentMask))); |
1713 // Setup the allocation memento. | 1711 return size; |
1714 if (allocation_mode.CreateAllocationMementos()) { | |
1715 BuildCreateAllocationMemento( | |
1716 object, object_size, allocation_mode.current_site()); | |
1717 } | |
1718 | |
1719 return object; | |
1720 } | 1712 } |
1721 | 1713 |
1722 | 1714 |
1723 HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length, | |
1724 HValue* right_length) { | |
1725 // Compute the combined string length. If the result is larger than the max | |
1726 // supported string length, we bailout to the runtime. This is done implicitly | |
1727 // when converting the result back to a smi in case the max string length | |
1728 // equals the max smi value. Otherwise, for platforms with 32-bit smis, we do | |
1729 HValue* length = AddUncasted<HAdd>(left_length, right_length); | |
1730 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); | |
1731 if (String::kMaxLength != Smi::kMaxValue) { | |
1732 IfBuilder if_nooverflow(this); | |
1733 if_nooverflow.If<HCompareNumericAndBranch>( | |
1734 length, Add<HConstant>(String::kMaxLength), Token::LTE); | |
1735 if_nooverflow.Then(); | |
1736 if_nooverflow.ElseDeopt("String length exceeds limit"); | |
1737 } | |
1738 return length; | |
1739 } | |
1740 | |
1741 | |
1742 HValue* HGraphBuilder::BuildCreateConsString( | |
1743 HValue* length, | |
1744 HValue* left, | |
1745 HValue* right, | |
1746 HAllocationMode allocation_mode) { | |
1747 // Determine the string instance types. | |
1748 HInstruction* left_instance_type = AddLoadStringInstanceType(left); | |
1749 HInstruction* right_instance_type = AddLoadStringInstanceType(right); | |
1750 | |
1751 // Allocate the cons string object. HAllocate does not care whether we | |
1752 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use | |
1753 // CONS_STRING_TYPE here. Below we decide whether the cons string is | |
1754 // one-byte or two-byte and set the appropriate map. | |
1755 ASSERT(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE, | |
1756 CONS_ASCII_STRING_TYPE)); | |
1757 HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize), | |
1758 HType::String(), CONS_STRING_TYPE, | |
1759 allocation_mode); | |
1760 | |
1761 // Compute intersection and difference of instance types. | |
1762 HValue* anded_instance_types = AddUncasted<HBitwise>( | |
1763 Token::BIT_AND, left_instance_type, right_instance_type); | |
1764 HValue* xored_instance_types = AddUncasted<HBitwise>( | |
1765 Token::BIT_XOR, left_instance_type, right_instance_type); | |
1766 | |
1767 // We create a one-byte cons string if | |
1768 // 1. both strings are one-byte, or | |
1769 // 2. at least one of the strings is two-byte, but happens to contain only | |
1770 // one-byte characters. | |
1771 // To do this, we check | |
1772 // 1. if both strings are one-byte, or if the one-byte data hint is set in | |
1773 // both strings, or | |
1774 // 2. if one of the strings has the one-byte data hint set and the other | |
1775 // string is one-byte. | |
1776 IfBuilder if_onebyte(this); | |
1777 STATIC_ASSERT(kOneByteStringTag != 0); | |
1778 STATIC_ASSERT(kOneByteDataHintMask != 0); | |
1779 if_onebyte.If<HCompareNumericAndBranch>( | |
1780 AddUncasted<HBitwise>( | |
1781 Token::BIT_AND, anded_instance_types, | |
1782 Add<HConstant>(static_cast<int32_t>( | |
1783 kStringEncodingMask | kOneByteDataHintMask))), | |
1784 graph()->GetConstant0(), Token::NE); | |
1785 if_onebyte.Or(); | |
1786 STATIC_ASSERT(kOneByteStringTag != 0 && | |
1787 kOneByteDataHintTag != 0 && | |
1788 kOneByteDataHintTag != kOneByteStringTag); | |
1789 if_onebyte.If<HCompareNumericAndBranch>( | |
1790 AddUncasted<HBitwise>( | |
1791 Token::BIT_AND, xored_instance_types, | |
1792 Add<HConstant>(static_cast<int32_t>( | |
1793 kOneByteStringTag | kOneByteDataHintTag))), | |
1794 Add<HConstant>(static_cast<int32_t>( | |
1795 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); | |
1796 if_onebyte.Then(); | |
1797 { | |
1798 // We can safely skip the write barrier for storing the map here. | |
1799 Handle<Map> map = isolate()->factory()->cons_ascii_string_map(); | |
1800 AddStoreMapConstantNoWriteBarrier(result, map); | |
1801 } | |
1802 if_onebyte.Else(); | |
1803 { | |
1804 // We can safely skip the write barrier for storing the map here. | |
1805 Handle<Map> map = isolate()->factory()->cons_string_map(); | |
1806 AddStoreMapConstantNoWriteBarrier(result, map); | |
1807 } | |
1808 if_onebyte.End(); | |
1809 | |
1810 // Initialize the cons string fields. | |
1811 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(), | |
1812 Add<HConstant>(String::kEmptyHashField)); | |
1813 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length); | |
1814 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left); | |
1815 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right); | |
1816 | |
1817 // Count the native string addition. | |
1818 AddIncrementCounter(isolate()->counters()->string_add_native()); | |
1819 | |
1820 return result; | |
1821 } | |
1822 | |
1823 | |
1824 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, | 1715 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, |
1825 HValue* src_offset, | 1716 HValue* src_offset, |
1826 String::Encoding src_encoding, | 1717 String::Encoding src_encoding, |
1827 HValue* dst, | 1718 HValue* dst, |
1828 HValue* dst_offset, | 1719 HValue* dst_offset, |
1829 String::Encoding dst_encoding, | 1720 String::Encoding dst_encoding, |
1830 HValue* length) { | 1721 HValue* length) { |
1831 ASSERT(dst_encoding != String::ONE_BYTE_ENCODING || | 1722 ASSERT(dst_encoding != String::ONE_BYTE_ENCODING || |
1832 src_encoding == String::ONE_BYTE_ENCODING); | 1723 src_encoding == String::ONE_BYTE_ENCODING); |
1833 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); | 1724 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); |
1834 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); | 1725 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); |
1835 { | 1726 { |
1836 HValue* src_index = AddUncasted<HAdd>(src_offset, index); | 1727 HValue* src_index = AddUncasted<HAdd>(src_offset, index); |
1837 HValue* value = | 1728 HValue* value = |
1838 AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index); | 1729 AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index); |
1839 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index); | 1730 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index); |
1840 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); | 1731 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); |
1841 } | 1732 } |
1842 loop.EndBody(); | 1733 loop.EndBody(); |
1843 } | 1734 } |
1844 | 1735 |
1845 | 1736 |
1846 HValue* HGraphBuilder::BuildUncheckedStringAdd( | 1737 HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left, |
1847 HValue* left, | 1738 HValue* right, |
1848 HValue* right, | 1739 PretenureFlag pretenure_flag) { |
1849 HAllocationMode allocation_mode) { | |
1850 // Determine the string lengths. | 1740 // Determine the string lengths. |
1851 HValue* left_length = AddLoadStringLength(left); | 1741 HValue* left_length = Add<HLoadNamedField>( |
1852 HValue* right_length = AddLoadStringLength(right); | 1742 left, HObjectAccess::ForStringLength()); |
| 1743 HValue* right_length = Add<HLoadNamedField>( |
| 1744 right, HObjectAccess::ForStringLength()); |
1853 | 1745 |
1854 // Compute the combined string length. | 1746 // Compute the combined string length. If the result is larger than the max |
1855 HValue* length = BuildAddStringLengths(left_length, right_length); | 1747 // supported string length, we bailout to the runtime. This is done implicitly |
| 1748 // when converting the result back to a smi in case the max string length |
| 1749 // equals the max smi valie. Otherwise, for platforms with 32-bit smis, we do |
| 1750 HValue* length = AddUncasted<HAdd>(left_length, right_length); |
| 1751 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); |
| 1752 if (String::kMaxLength != Smi::kMaxValue) { |
| 1753 IfBuilder if_nooverflow(this); |
| 1754 if_nooverflow.If<HCompareNumericAndBranch>( |
| 1755 length, Add<HConstant>(String::kMaxLength), Token::LTE); |
| 1756 if_nooverflow.Then(); |
| 1757 if_nooverflow.ElseDeopt("String length exceeds limit"); |
| 1758 } |
1856 | 1759 |
1857 // Do some manual constant folding here. | 1760 // Determine the string instance types. |
1858 if (left_length->IsConstant()) { | 1761 HLoadNamedField* left_instance_type = Add<HLoadNamedField>( |
1859 HConstant* c_left_length = HConstant::cast(left_length); | 1762 Add<HLoadNamedField>(left, HObjectAccess::ForMap()), |
1860 ASSERT_NE(0, c_left_length->Integer32Value()); | 1763 HObjectAccess::ForMapInstanceType()); |
1861 if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) { | 1764 HLoadNamedField* right_instance_type = Add<HLoadNamedField>( |
1862 // The right string contains at least one character. | 1765 Add<HLoadNamedField>(right, HObjectAccess::ForMap()), |
1863 return BuildCreateConsString(length, left, right, allocation_mode); | 1766 HObjectAccess::ForMapInstanceType()); |
1864 } | 1767 |
1865 } else if (right_length->IsConstant()) { | 1768 // Compute difference of instance types. |
1866 HConstant* c_right_length = HConstant::cast(right_length); | 1769 HValue* xored_instance_types = AddUncasted<HBitwise>( |
1867 ASSERT_NE(0, c_right_length->Integer32Value()); | 1770 Token::BIT_XOR, left_instance_type, right_instance_type); |
1868 if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) { | |
1869 // The left string contains at least one character. | |
1870 return BuildCreateConsString(length, left, right, allocation_mode); | |
1871 } | |
1872 } | |
1873 | 1771 |
1874 // Check if we should create a cons string. | 1772 // Check if we should create a cons string. |
1875 IfBuilder if_createcons(this); | 1773 IfBuilder if_createcons(this); |
1876 if_createcons.If<HCompareNumericAndBranch>( | 1774 if_createcons.If<HCompareNumericAndBranch>( |
1877 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); | 1775 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); |
1878 if_createcons.Then(); | 1776 if_createcons.Then(); |
1879 { | 1777 { |
1880 // Create a cons string. | 1778 // Allocate the cons string object. HAllocate does not care whether we |
1881 Push(BuildCreateConsString(length, left, right, allocation_mode)); | 1779 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use |
| 1780 // CONS_STRING_TYPE here. Below we decide whether the cons string is |
| 1781 // one-byte or two-byte and set the appropriate map. |
| 1782 ASSERT(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE, |
| 1783 CONS_ASCII_STRING_TYPE)); |
| 1784 HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize), |
| 1785 HType::String(), pretenure_flag, |
| 1786 CONS_STRING_TYPE); |
| 1787 |
| 1788 // Compute the intersection of instance types. |
| 1789 HValue* anded_instance_types = AddUncasted<HBitwise>( |
| 1790 Token::BIT_AND, left_instance_type, right_instance_type); |
| 1791 |
| 1792 // We create a one-byte cons string if |
| 1793 // 1. both strings are one-byte, or |
| 1794 // 2. at least one of the strings is two-byte, but happens to contain only |
| 1795 // one-byte characters. |
| 1796 // To do this, we check |
| 1797 // 1. if both strings are one-byte, or if the one-byte data hint is set in |
| 1798 // both strings, or |
| 1799 // 2. if one of the strings has the one-byte data hint set and the other |
| 1800 // string is one-byte. |
| 1801 IfBuilder if_onebyte(this); |
| 1802 STATIC_ASSERT(kOneByteStringTag != 0); |
| 1803 STATIC_ASSERT(kOneByteDataHintMask != 0); |
| 1804 if_onebyte.If<HCompareNumericAndBranch>( |
| 1805 AddUncasted<HBitwise>( |
| 1806 Token::BIT_AND, anded_instance_types, |
| 1807 Add<HConstant>(static_cast<int32_t>( |
| 1808 kStringEncodingMask | kOneByteDataHintMask))), |
| 1809 graph()->GetConstant0(), Token::NE); |
| 1810 if_onebyte.Or(); |
| 1811 STATIC_ASSERT(kOneByteStringTag != 0 && |
| 1812 kOneByteDataHintTag != 0 && |
| 1813 kOneByteDataHintTag != kOneByteStringTag); |
| 1814 if_onebyte.If<HCompareNumericAndBranch>( |
| 1815 AddUncasted<HBitwise>( |
| 1816 Token::BIT_AND, xored_instance_types, |
| 1817 Add<HConstant>(static_cast<int32_t>( |
| 1818 kOneByteStringTag | kOneByteDataHintTag))), |
| 1819 Add<HConstant>(static_cast<int32_t>( |
| 1820 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); |
| 1821 if_onebyte.Then(); |
| 1822 { |
| 1823 // We can safely skip the write barrier for storing the map here. |
| 1824 Handle<Map> map = isolate()->factory()->cons_ascii_string_map(); |
| 1825 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1826 } |
| 1827 if_onebyte.Else(); |
| 1828 { |
| 1829 // We can safely skip the write barrier for storing the map here. |
| 1830 Handle<Map> map = isolate()->factory()->cons_string_map(); |
| 1831 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1832 } |
| 1833 if_onebyte.End(); |
| 1834 |
| 1835 // Initialize the cons string fields. |
| 1836 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), |
| 1837 Add<HConstant>(String::kEmptyHashField)); |
| 1838 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length); |
| 1839 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left); |
| 1840 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(), |
| 1841 right); |
| 1842 |
| 1843 // Count the native string addition. |
| 1844 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1845 |
| 1846 // Cons string is result. |
| 1847 Push(string); |
1882 } | 1848 } |
1883 if_createcons.Else(); | 1849 if_createcons.Else(); |
1884 { | 1850 { |
1885 // Determine the string instance types. | 1851 // Compute union of instance types. |
1886 HValue* left_instance_type = AddLoadStringInstanceType(left); | |
1887 HValue* right_instance_type = AddLoadStringInstanceType(right); | |
1888 | |
1889 // Compute union and difference of instance types. | |
1890 HValue* ored_instance_types = AddUncasted<HBitwise>( | 1852 HValue* ored_instance_types = AddUncasted<HBitwise>( |
1891 Token::BIT_OR, left_instance_type, right_instance_type); | 1853 Token::BIT_OR, left_instance_type, right_instance_type); |
1892 HValue* xored_instance_types = AddUncasted<HBitwise>( | |
1893 Token::BIT_XOR, left_instance_type, right_instance_type); | |
1894 | 1854 |
1895 // Check if both strings have the same encoding and both are | 1855 // Check if both strings have the same encoding and both are |
1896 // sequential. | 1856 // sequential. |
1897 IfBuilder if_sameencodingandsequential(this); | 1857 IfBuilder if_sameencodingandsequential(this); |
1898 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | 1858 if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
1899 AddUncasted<HBitwise>( | 1859 AddUncasted<HBitwise>( |
1900 Token::BIT_AND, xored_instance_types, | 1860 Token::BIT_AND, xored_instance_types, |
1901 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | 1861 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
1902 graph()->GetConstant0(), Token::EQ); | 1862 graph()->GetConstant0(), Token::EQ); |
1903 if_sameencodingandsequential.And(); | 1863 if_sameencodingandsequential.And(); |
1904 STATIC_ASSERT(kSeqStringTag == 0); | 1864 STATIC_ASSERT(kSeqStringTag == 0); |
1905 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | 1865 if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
1906 AddUncasted<HBitwise>( | 1866 AddUncasted<HBitwise>( |
1907 Token::BIT_AND, ored_instance_types, | 1867 Token::BIT_AND, ored_instance_types, |
1908 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), | 1868 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), |
1909 graph()->GetConstant0(), Token::EQ); | 1869 graph()->GetConstant0(), Token::EQ); |
1910 if_sameencodingandsequential.Then(); | 1870 if_sameencodingandsequential.Then(); |
1911 { | 1871 { |
1912 HConstant* string_map = | 1872 // Check if the result is a one-byte string. |
1913 Add<HConstant>(isolate()->factory()->string_map()); | |
1914 HConstant* ascii_string_map = | |
1915 Add<HConstant>(isolate()->factory()->ascii_string_map()); | |
1916 | |
1917 // Determine map and size depending on whether result is one-byte string. | |
1918 IfBuilder if_onebyte(this); | 1873 IfBuilder if_onebyte(this); |
1919 STATIC_ASSERT(kOneByteStringTag != 0); | 1874 STATIC_ASSERT(kOneByteStringTag != 0); |
1920 if_onebyte.If<HCompareNumericAndBranch>( | 1875 if_onebyte.If<HCompareNumericAndBranch>( |
1921 AddUncasted<HBitwise>( | 1876 AddUncasted<HBitwise>( |
1922 Token::BIT_AND, ored_instance_types, | 1877 Token::BIT_AND, ored_instance_types, |
1923 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | 1878 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
1924 graph()->GetConstant0(), Token::NE); | 1879 graph()->GetConstant0(), Token::NE); |
1925 if_onebyte.Then(); | 1880 if_onebyte.Then(); |
1926 { | 1881 { |
1927 // Allocate sequential one-byte string object. | 1882 // Calculate the number of bytes needed for the characters in the |
1928 Push(length); | 1883 // string while observing object alignment. |
1929 Push(ascii_string_map); | 1884 HValue* size = BuildSeqStringSizeFor( |
| 1885 length, String::ONE_BYTE_ENCODING); |
| 1886 |
| 1887 // Allocate the ASCII string object. |
| 1888 Handle<Map> map = isolate()->factory()->ascii_string_map(); |
| 1889 HAllocate* string = Add<HAllocate>(size, HType::String(), |
| 1890 pretenure_flag, ASCII_STRING_TYPE); |
| 1891 string->set_known_initial_map(map); |
| 1892 |
| 1893 // We can safely skip the write barrier for storing map here. |
| 1894 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1895 |
| 1896 // Length must be stored into the string before we copy characters to |
| 1897 // make debug verification code happy. |
| 1898 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), |
| 1899 length); |
| 1900 |
| 1901 // Copy bytes from the left string. |
| 1902 BuildCopySeqStringChars( |
| 1903 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1904 string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1905 left_length); |
| 1906 |
| 1907 // Copy bytes from the right string. |
| 1908 BuildCopySeqStringChars( |
| 1909 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1910 string, left_length, String::ONE_BYTE_ENCODING, |
| 1911 right_length); |
| 1912 |
| 1913 // Count the native string addition. |
| 1914 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1915 |
| 1916 // Return the string. |
| 1917 Push(string); |
1930 } | 1918 } |
1931 if_onebyte.Else(); | 1919 if_onebyte.Else(); |
1932 { | 1920 { |
1933 // Allocate sequential two-byte string object. | 1921 // Calculate the number of bytes needed for the characters in the |
1934 HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1()); | 1922 // string while observing object alignment. |
1935 size->ClearFlag(HValue::kCanOverflow); | 1923 HValue* size = BuildSeqStringSizeFor( |
1936 size->SetFlag(HValue::kUint32); | 1924 length, String::TWO_BYTE_ENCODING); |
1937 Push(size); | 1925 |
1938 Push(string_map); | 1926 // Allocate the two-byte string object. |
| 1927 Handle<Map> map = isolate()->factory()->string_map(); |
| 1928 HAllocate* string = Add<HAllocate>(size, HType::String(), |
| 1929 pretenure_flag, STRING_TYPE); |
| 1930 string->set_known_initial_map(map); |
| 1931 |
| 1932 // We can safely skip the write barrier for storing map here. |
| 1933 AddStoreMapConstantNoWriteBarrier(string, map); |
| 1934 |
| 1935 // Length must be stored into the string before we copy characters to |
| 1936 // make debug verification code happy. |
| 1937 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), |
| 1938 length); |
| 1939 |
| 1940 // Copy bytes from the left string. |
| 1941 BuildCopySeqStringChars( |
| 1942 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1943 string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1944 left_length); |
| 1945 |
| 1946 // Copy bytes from the right string. |
| 1947 BuildCopySeqStringChars( |
| 1948 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1949 string, left_length, String::TWO_BYTE_ENCODING, |
| 1950 right_length); |
| 1951 |
| 1952 // Return the string. |
| 1953 Push(string); |
1939 } | 1954 } |
1940 if_onebyte.End(); | 1955 if_onebyte.End(); |
1941 HValue* map = Pop(); | |
1942 | 1956 |
1943 // Calculate the number of bytes needed for the characters in the | 1957 // Initialize the (common) string fields. |
1944 // string while observing object alignment. | 1958 HValue* string = Pop(); |
1945 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0); | 1959 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), |
1946 HValue* size = Pop(); | |
1947 size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>( | |
1948 SeqString::kHeaderSize + kObjectAlignmentMask))); | |
1949 size->ClearFlag(HValue::kCanOverflow); | |
1950 size = AddUncasted<HBitwise>( | |
1951 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( | |
1952 ~kObjectAlignmentMask))); | |
1953 | |
1954 // Allocate the string object. HAllocate does not care whether we pass | |
1955 // STRING_TYPE or ASCII_STRING_TYPE here, so we just use STRING_TYPE here. | |
1956 HAllocate* result = BuildAllocate( | |
1957 size, HType::String(), STRING_TYPE, allocation_mode); | |
1958 | |
1959 // We can safely skip the write barrier for storing map here. | |
1960 AddStoreMapNoWriteBarrier(result, map); | |
1961 | |
1962 // Initialize the string fields. | |
1963 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(), | |
1964 Add<HConstant>(String::kEmptyHashField)); | 1960 Add<HConstant>(String::kEmptyHashField)); |
1965 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length); | |
1966 | |
1967 // Copy characters to the result string. | |
1968 IfBuilder if_twobyte(this); | |
1969 if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map); | |
1970 if_twobyte.Then(); | |
1971 { | |
1972 // Copy characters from the left string. | |
1973 BuildCopySeqStringChars( | |
1974 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
1975 result, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
1976 left_length); | |
1977 | |
1978 // Copy characters from the right string. | |
1979 BuildCopySeqStringChars( | |
1980 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
1981 result, left_length, String::TWO_BYTE_ENCODING, | |
1982 right_length); | |
1983 } | |
1984 if_twobyte.Else(); | |
1985 { | |
1986 // Copy characters from the left string. | |
1987 BuildCopySeqStringChars( | |
1988 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
1989 result, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
1990 left_length); | |
1991 | |
1992 // Copy characters from the right string. | |
1993 BuildCopySeqStringChars( | |
1994 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
1995 result, left_length, String::ONE_BYTE_ENCODING, | |
1996 right_length); | |
1997 } | |
1998 if_twobyte.End(); | |
1999 | 1961 |
2000 // Count the native string addition. | 1962 // Count the native string addition. |
2001 AddIncrementCounter(isolate()->counters()->string_add_native()); | 1963 AddIncrementCounter(isolate()->counters()->string_add_native()); |
2002 | 1964 |
2003 // Return the sequential string. | 1965 Push(string); |
2004 Push(result); | |
2005 } | 1966 } |
2006 if_sameencodingandsequential.Else(); | 1967 if_sameencodingandsequential.Else(); |
2007 { | 1968 { |
2008 // Fallback to the runtime to add the two strings. | 1969 // Fallback to the runtime to add the two strings. |
2009 Add<HPushArgument>(left); | 1970 Add<HPushArgument>(left); |
2010 Add<HPushArgument>(right); | 1971 Add<HPushArgument>(right); |
2011 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), | 1972 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), |
2012 Runtime::FunctionForId(Runtime::kStringAdd), | 1973 Runtime::FunctionForId(Runtime::kStringAdd), |
2013 2)); | 1974 2)); |
2014 } | 1975 } |
2015 if_sameencodingandsequential.End(); | 1976 if_sameencodingandsequential.End(); |
2016 } | 1977 } |
2017 if_createcons.End(); | 1978 if_createcons.End(); |
2018 | 1979 |
2019 return Pop(); | 1980 return Pop(); |
2020 } | 1981 } |
2021 | 1982 |
2022 | 1983 |
2023 HValue* HGraphBuilder::BuildStringAdd( | 1984 HValue* HGraphBuilder::BuildStringAdd(HValue* left, |
2024 HValue* left, | 1985 HValue* right, |
2025 HValue* right, | 1986 PretenureFlag pretenure_flag) { |
2026 HAllocationMode allocation_mode) { | 1987 // Determine the string lengths. |
2027 NoObservableSideEffectsScope no_effects(this); | 1988 HValue* left_length = Add<HLoadNamedField>( |
2028 | 1989 left, HObjectAccess::ForStringLength()); |
2029 // Determine string lengths. | 1990 HValue* right_length = Add<HLoadNamedField>( |
2030 HValue* left_length = AddLoadStringLength(left); | 1991 right, HObjectAccess::ForStringLength()); |
2031 HValue* right_length = AddLoadStringLength(right); | |
2032 | 1992 |
2033 // Check if left string is empty. | 1993 // Check if left string is empty. |
2034 IfBuilder if_leftempty(this); | 1994 IfBuilder if_leftisempty(this); |
2035 if_leftempty.If<HCompareNumericAndBranch>( | 1995 if_leftisempty.If<HCompareNumericAndBranch>( |
2036 left_length, graph()->GetConstant0(), Token::EQ); | 1996 left_length, graph()->GetConstant0(), Token::EQ); |
2037 if_leftempty.Then(); | 1997 if_leftisempty.Then(); |
2038 { | 1998 { |
2039 // Count the native string addition. | 1999 // Count the native string addition. |
2040 AddIncrementCounter(isolate()->counters()->string_add_native()); | 2000 AddIncrementCounter(isolate()->counters()->string_add_native()); |
2041 | 2001 |
2042 // Just return the right string. | 2002 // Just return the right string. |
2043 Push(right); | 2003 Push(right); |
2044 } | 2004 } |
2045 if_leftempty.Else(); | 2005 if_leftisempty.Else(); |
2046 { | 2006 { |
2047 // Check if right string is empty. | 2007 // Check if right string is empty. |
2048 IfBuilder if_rightempty(this); | 2008 IfBuilder if_rightisempty(this); |
2049 if_rightempty.If<HCompareNumericAndBranch>( | 2009 if_rightisempty.If<HCompareNumericAndBranch>( |
2050 right_length, graph()->GetConstant0(), Token::EQ); | 2010 right_length, graph()->GetConstant0(), Token::EQ); |
2051 if_rightempty.Then(); | 2011 if_rightisempty.Then(); |
2052 { | 2012 { |
2053 // Count the native string addition. | 2013 // Count the native string addition. |
2054 AddIncrementCounter(isolate()->counters()->string_add_native()); | 2014 AddIncrementCounter(isolate()->counters()->string_add_native()); |
2055 | 2015 |
2056 // Just return the left string. | 2016 // Just return the left string. |
2057 Push(left); | 2017 Push(left); |
2058 } | 2018 } |
2059 if_rightempty.Else(); | 2019 if_rightisempty.Else(); |
2060 { | 2020 { |
2061 // Add the two non-empty strings. | 2021 // Concatenate the two non-empty strings. |
2062 Push(BuildUncheckedStringAdd(left, right, allocation_mode)); | 2022 Push(BuildUncheckedStringAdd(left, right, pretenure_flag)); |
2063 } | 2023 } |
2064 if_rightempty.End(); | 2024 if_rightisempty.End(); |
2065 } | 2025 } |
2066 if_leftempty.End(); | 2026 if_leftisempty.End(); |
2067 | 2027 |
2068 return Pop(); | 2028 return Pop(); |
2069 } | 2029 } |
2070 | 2030 |
2071 | 2031 |
2072 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 2032 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
2073 HValue* checked_object, | 2033 HValue* checked_object, |
2074 HValue* key, | 2034 HValue* key, |
2075 HValue* val, | 2035 HValue* val, |
2076 bool is_js_array, | 2036 bool is_js_array, |
(...skipping 4056 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6133 return New<HLoadNamedField>(object, access); | 6093 return New<HLoadNamedField>(object, access); |
6134 } | 6094 } |
6135 | 6095 |
6136 | 6096 |
6137 HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object, | 6097 HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object, |
6138 HObjectAccess access) { | 6098 HObjectAccess access) { |
6139 return AddInstruction(BuildLoadNamedField(object, access)); | 6099 return AddInstruction(BuildLoadNamedField(object, access)); |
6140 } | 6100 } |
6141 | 6101 |
6142 | 6102 |
6143 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) { | 6103 HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* object, |
6144 if (string->IsConstant()) { | 6104 HValue* checked_string) { |
6145 HConstant* c_string = HConstant::cast(string); | 6105 if (FLAG_fold_constants && object->IsConstant()) { |
6146 if (c_string->HasStringValue()) { | 6106 HConstant* constant = HConstant::cast(object); |
6147 return Add<HConstant>(c_string->StringValue()->map()->instance_type()); | 6107 if (constant->HasStringValue()) { |
| 6108 return New<HConstant>(constant->StringValue()->length()); |
6148 } | 6109 } |
6149 } | 6110 } |
6150 return AddLoadNamedField( | 6111 return BuildLoadNamedField(checked_string, HObjectAccess::ForStringLength()); |
6151 AddLoadNamedField(string, HObjectAccess::ForMap()), | |
6152 HObjectAccess::ForMapInstanceType()); | |
6153 } | 6112 } |
6154 | 6113 |
6155 | 6114 |
6156 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) { | |
6157 if (string->IsConstant()) { | |
6158 HConstant* c_string = HConstant::cast(string); | |
6159 if (c_string->HasStringValue()) { | |
6160 return Add<HConstant>(c_string->StringValue()->length()); | |
6161 } | |
6162 } | |
6163 return AddLoadNamedField(string, HObjectAccess::ForStringLength()); | |
6164 } | |
6165 | |
6166 | |
6167 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( | 6115 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( |
6168 HValue* object, | 6116 HValue* object, |
6169 Handle<String> name, | 6117 Handle<String> name, |
6170 Property* expr) { | 6118 Property* expr) { |
6171 if (expr->IsUninitialized()) { | 6119 if (expr->IsUninitialized()) { |
6172 Add<HDeoptimize>("Insufficient type feedback for generic named load", | 6120 Add<HDeoptimize>("Insufficient type feedback for generic named load", |
6173 Deoptimizer::SOFT); | 6121 Deoptimizer::SOFT); |
6174 } | 6122 } |
6175 return New<HLoadNamedGeneric>(object, name); | 6123 return New<HLoadNamedGeneric>(object, name); |
6176 } | 6124 } |
(...skipping 2424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8601 HConstant* c_index = HConstant::cast(index); | 8549 HConstant* c_index = HConstant::cast(index); |
8602 if (c_string->HasStringValue() && c_index->HasNumberValue()) { | 8550 if (c_string->HasStringValue() && c_index->HasNumberValue()) { |
8603 int32_t i = c_index->NumberValueAsInteger32(); | 8551 int32_t i = c_index->NumberValueAsInteger32(); |
8604 Handle<String> s = c_string->StringValue(); | 8552 Handle<String> s = c_string->StringValue(); |
8605 if (i < 0 || i >= s->length()) { | 8553 if (i < 0 || i >= s->length()) { |
8606 return New<HConstant>(OS::nan_value()); | 8554 return New<HConstant>(OS::nan_value()); |
8607 } | 8555 } |
8608 return New<HConstant>(s->Get(i)); | 8556 return New<HConstant>(s->Get(i)); |
8609 } | 8557 } |
8610 } | 8558 } |
8611 string = BuildCheckString(string); | 8559 BuildCheckHeapObject(string); |
8612 index = Add<HBoundsCheck>(index, AddLoadStringLength(string)); | 8560 HValue* checkstring = |
8613 return New<HStringCharCodeAt>(string, index); | 8561 Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); |
| 8562 HInstruction* length = BuildLoadStringLength(string, checkstring); |
| 8563 AddInstruction(length); |
| 8564 HInstruction* checked_index = Add<HBoundsCheck>(index, length); |
| 8565 return New<HStringCharCodeAt>(string, checked_index); |
8614 } | 8566 } |
8615 | 8567 |
8616 | 8568 |
8617 // Checks if the given shift amounts have following forms: | 8569 // Checks if the given shift amounts have following forms: |
8618 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa). | 8570 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa). |
8619 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, | 8571 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, |
8620 HValue* const32_minus_sa) { | 8572 HValue* const32_minus_sa) { |
8621 if (sa->IsConstant() && const32_minus_sa->IsConstant()) { | 8573 if (sa->IsConstant() && const32_minus_sa->IsConstant()) { |
8622 const HConstant* c1 = HConstant::cast(sa); | 8574 const HConstant* c1 = HConstant::cast(sa); |
8623 const HConstant* c2 = HConstant::cast(const32_minus_sa); | 8575 const HConstant* c2 = HConstant::cast(const32_minus_sa); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8734 | 8686 |
8735 | 8687 |
8736 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( | 8688 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( |
8737 BinaryOperation* expr, | 8689 BinaryOperation* expr, |
8738 HValue* left, | 8690 HValue* left, |
8739 HValue* right) { | 8691 HValue* right) { |
8740 Handle<Type> left_type = expr->left()->bounds().lower; | 8692 Handle<Type> left_type = expr->left()->bounds().lower; |
8741 Handle<Type> right_type = expr->right()->bounds().lower; | 8693 Handle<Type> right_type = expr->right()->bounds().lower; |
8742 Handle<Type> result_type = expr->bounds().lower; | 8694 Handle<Type> result_type = expr->bounds().lower; |
8743 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); | 8695 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); |
8744 Handle<AllocationSite> allocation_site = expr->allocation_site(); | |
8745 | |
8746 HAllocationMode allocation_mode = | |
8747 FLAG_allocation_site_pretenuring | |
8748 ? (allocation_site.is_null() | |
8749 ? HAllocationMode(NOT_TENURED) | |
8750 : HAllocationMode(allocation_site)) | |
8751 : HAllocationMode(isolate()->heap()->GetPretenureMode()); | |
8752 | 8696 |
8753 HValue* result = HGraphBuilder::BuildBinaryOperation( | 8697 HValue* result = HGraphBuilder::BuildBinaryOperation( |
8754 expr->op(), left, right, left_type, right_type, result_type, | 8698 expr->op(), left, right, left_type, right_type, |
8755 fixed_right_arg, allocation_mode); | 8699 result_type, fixed_right_arg); |
8756 // Add a simulate after instructions with observable side effects, and | 8700 // Add a simulate after instructions with observable side effects, and |
8757 // after phis, which are the result of BuildBinaryOperation when we | 8701 // after phis, which are the result of BuildBinaryOperation when we |
8758 // inlined some complex subgraph. | 8702 // inlined some complex subgraph. |
8759 if (result->HasObservableSideEffects() || result->IsPhi()) { | 8703 if (result->HasObservableSideEffects() || result->IsPhi()) { |
8760 Push(result); | 8704 Push(result); |
8761 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 8705 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
8762 Drop(1); | 8706 Drop(1); |
8763 } | 8707 } |
8764 return result; | 8708 return result; |
8765 } | 8709 } |
8766 | 8710 |
8767 | 8711 |
8768 HValue* HGraphBuilder::BuildBinaryOperation( | 8712 HValue* HGraphBuilder::BuildBinaryOperation( |
8769 Token::Value op, | 8713 Token::Value op, |
8770 HValue* left, | 8714 HValue* left, |
8771 HValue* right, | 8715 HValue* right, |
8772 Handle<Type> left_type, | 8716 Handle<Type> left_type, |
8773 Handle<Type> right_type, | 8717 Handle<Type> right_type, |
8774 Handle<Type> result_type, | 8718 Handle<Type> result_type, |
8775 Maybe<int> fixed_right_arg, | 8719 Maybe<int> fixed_right_arg) { |
8776 HAllocationMode allocation_mode) { | |
8777 | 8720 |
8778 Representation left_rep = Representation::FromType(left_type); | 8721 Representation left_rep = Representation::FromType(left_type); |
8779 Representation right_rep = Representation::FromType(right_type); | 8722 Representation right_rep = Representation::FromType(right_type); |
8780 | 8723 |
8781 bool maybe_string_add = op == Token::ADD && | 8724 bool maybe_string_add = op == Token::ADD && |
8782 (left_type->Maybe(Type::String()) || | 8725 (left_type->Maybe(Type::String()) || |
8783 right_type->Maybe(Type::String())); | 8726 right_type->Maybe(Type::String())); |
8784 | 8727 |
8785 if (left_type->Is(Type::None())) { | 8728 if (left_type->Is(Type::None())) { |
8786 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", | 8729 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8832 ASSERT(left_type->Is(Type::String())); | 8775 ASSERT(left_type->Is(Type::String())); |
8833 right = BuildNumberToString(right, right_type); | 8776 right = BuildNumberToString(right, right_type); |
8834 } else if (!right_type->Is(Type::String())) { | 8777 } else if (!right_type->Is(Type::String())) { |
8835 ASSERT(left_type->Is(Type::String())); | 8778 ASSERT(left_type->Is(Type::String())); |
8836 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); | 8779 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); |
8837 Add<HPushArgument>(left); | 8780 Add<HPushArgument>(left); |
8838 Add<HPushArgument>(right); | 8781 Add<HPushArgument>(right); |
8839 return AddUncasted<HInvokeFunction>(function, 2); | 8782 return AddUncasted<HInvokeFunction>(function, 2); |
8840 } | 8783 } |
8841 | 8784 |
8842 // Inline the string addition into the stub when creating allocation | 8785 return AddUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE); |
8843 // mementos to gather allocation site feedback. | |
8844 if (graph()->info()->IsStub() && | |
8845 allocation_mode.CreateAllocationMementos()) { | |
8846 return BuildStringAdd(left, right, allocation_mode); | |
8847 } | |
8848 | |
8849 // Register the dependent code with the allocation site. | |
8850 if (!allocation_mode.feedback_site().is_null()) { | |
8851 ASSERT(!graph()->info()->IsStub()); | |
8852 allocation_mode.feedback_site()->AddDependentCompilationInfo( | |
8853 AllocationSite::TENURING, top_info()); | |
8854 } | |
8855 | |
8856 // Inline string addition if we know that we'll create a cons string. | |
8857 if (left->IsConstant()) { | |
8858 HConstant* c_left = HConstant::cast(left); | |
8859 if (c_left->HasStringValue()) { | |
8860 int c_left_length = c_left->StringValue()->length(); | |
8861 if (c_left_length == 0) { | |
8862 return right; | |
8863 } else if (c_left_length + 1 >= ConsString::kMinLength) { | |
8864 return BuildStringAdd(left, right, allocation_mode); | |
8865 } | |
8866 } | |
8867 } | |
8868 if (right->IsConstant()) { | |
8869 HConstant* c_right = HConstant::cast(right); | |
8870 if (c_right->HasStringValue()) { | |
8871 int c_right_length = c_right->StringValue()->length(); | |
8872 if (c_right_length == 0) { | |
8873 return left; | |
8874 } else if (c_right_length + 1 >= ConsString::kMinLength) { | |
8875 return BuildStringAdd(left, right, allocation_mode); | |
8876 } | |
8877 } | |
8878 } | |
8879 | |
8880 // Fallback to using the string add stub. | |
8881 return AddUncasted<HStringAdd>( | |
8882 left, right, allocation_mode.GetPretenureMode(), | |
8883 STRING_ADD_CHECK_NONE, allocation_mode.feedback_site()); | |
8884 } | 8786 } |
8885 | 8787 |
8886 if (graph()->info()->IsStub()) { | 8788 if (graph()->info()->IsStub()) { |
8887 left = EnforceNumberType(left, left_type); | 8789 left = EnforceNumberType(left, left_type); |
8888 right = EnforceNumberType(right, right_type); | 8790 right = EnforceNumberType(right, right_type); |
8889 } | 8791 } |
8890 | 8792 |
8891 Representation result_rep = Representation::FromType(result_type); | 8793 Representation result_rep = Representation::FromType(result_type); |
8892 | 8794 |
8893 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || | 8795 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || |
(...skipping 1208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10102 } | 10004 } |
10103 | 10005 |
10104 | 10006 |
10105 // Fast support for StringAdd. | 10007 // Fast support for StringAdd. |
10106 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) { | 10008 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) { |
10107 ASSERT_EQ(2, call->arguments()->length()); | 10009 ASSERT_EQ(2, call->arguments()->length()); |
10108 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10010 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
10109 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10011 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
10110 HValue* right = Pop(); | 10012 HValue* right = Pop(); |
10111 HValue* left = Pop(); | 10013 HValue* left = Pop(); |
10112 HInstruction* result = NewUncasted<HStringAdd>(left, right); | 10014 HInstruction* result = |
| 10015 NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_BOTH); |
10113 return ast_context()->ReturnInstruction(result, call->id()); | 10016 return ast_context()->ReturnInstruction(result, call->id()); |
10114 } | 10017 } |
10115 | 10018 |
10116 | 10019 |
10117 // Fast support for SubString. | 10020 // Fast support for SubString. |
10118 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) { | 10021 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) { |
10119 ASSERT_EQ(3, call->arguments()->length()); | 10022 ASSERT_EQ(3, call->arguments()->length()); |
10120 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 10023 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
10121 HCallStub* result = New<HCallStub>(CodeStub::SubString, 3); | 10024 HCallStub* result = New<HCallStub>(CodeStub::SubString, 3); |
10122 Drop(3); | 10025 Drop(3); |
(...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10891 if (ShouldProduceTraceOutput()) { | 10794 if (ShouldProduceTraceOutput()) { |
10892 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10795 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
10893 } | 10796 } |
10894 | 10797 |
10895 #ifdef DEBUG | 10798 #ifdef DEBUG |
10896 graph_->Verify(false); // No full verify. | 10799 graph_->Verify(false); // No full verify. |
10897 #endif | 10800 #endif |
10898 } | 10801 } |
10899 | 10802 |
10900 } } // namespace v8::internal | 10803 } } // namespace v8::internal |
OLD | NEW |