| 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 1280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1291 if (object->type().IsJSObject()) return object; | 1291 if (object->type().IsJSObject()) return object; |
| 1292 return Add<HWrapReceiver>(object, function); | 1292 return Add<HWrapReceiver>(object, function); |
| 1293 } | 1293 } |
| 1294 | 1294 |
| 1295 | 1295 |
| 1296 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, | 1296 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, |
| 1297 HValue* elements, | 1297 HValue* elements, |
| 1298 ElementsKind kind, | 1298 ElementsKind kind, |
| 1299 HValue* length, | 1299 HValue* length, |
| 1300 HValue* key, | 1300 HValue* key, |
| 1301 bool is_js_array) { | 1301 bool is_js_array, |
| 1302 bool is_store) { |
| 1302 IfBuilder length_checker(this); | 1303 IfBuilder length_checker(this); |
| 1303 | 1304 |
| 1304 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; | 1305 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; |
| 1305 length_checker.If<HCompareNumericAndBranch>(key, length, token); | 1306 length_checker.If<HCompareNumericAndBranch>(key, length, token); |
| 1306 | 1307 |
| 1307 length_checker.Then(); | 1308 length_checker.Then(); |
| 1308 | 1309 |
| 1309 HValue* current_capacity = AddLoadFixedArrayLength(elements); | 1310 HValue* current_capacity = AddLoadFixedArrayLength(elements); |
| 1310 | 1311 |
| 1311 IfBuilder capacity_checker(this); | 1312 IfBuilder capacity_checker(this); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1334 capacity_checker.End(); | 1335 capacity_checker.End(); |
| 1335 | 1336 |
| 1336 if (is_js_array) { | 1337 if (is_js_array) { |
| 1337 HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1()); | 1338 HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1()); |
| 1338 new_length->ClearFlag(HValue::kCanOverflow); | 1339 new_length->ClearFlag(HValue::kCanOverflow); |
| 1339 | 1340 |
| 1340 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind), | 1341 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind), |
| 1341 new_length); | 1342 new_length); |
| 1342 } | 1343 } |
| 1343 | 1344 |
| 1345 if (is_store && kind == FAST_SMI_ELEMENTS) { |
| 1346 HValue* checked_elements = environment()->Top(); |
| 1347 |
| 1348 // Write zero to ensure that the new element is initialized with some smi. |
| 1349 Add<HStoreKeyed>(checked_elements, key, graph()->GetConstant0(), kind); |
| 1350 } |
| 1351 |
| 1344 length_checker.Else(); | 1352 length_checker.Else(); |
| 1345 Add<HBoundsCheck>(key, length); | 1353 Add<HBoundsCheck>(key, length); |
| 1346 | 1354 |
| 1347 environment()->Push(elements); | 1355 environment()->Push(elements); |
| 1348 length_checker.End(); | 1356 length_checker.End(); |
| 1349 | 1357 |
| 1350 return environment()->Pop(); | 1358 return environment()->Pop(); |
| 1351 } | 1359 } |
| 1352 | 1360 |
| 1353 | 1361 |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1680 isolate()->factory()->empty_string(), | 1688 isolate()->factory()->empty_string(), |
| 1681 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), | 1689 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), |
| 1682 1)); | 1690 1)); |
| 1683 } | 1691 } |
| 1684 if_found.End(); | 1692 if_found.End(); |
| 1685 | 1693 |
| 1686 return Pop(); | 1694 return Pop(); |
| 1687 } | 1695 } |
| 1688 | 1696 |
| 1689 | 1697 |
| 1690 HValue* HGraphBuilder::BuildSeqStringSizeFor(HValue* length, | 1698 HAllocate* HGraphBuilder::BuildAllocate( |
| 1691 String::Encoding encoding) { | 1699 HValue* object_size, |
| 1692 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0); | 1700 HType type, |
| 1693 HValue* size = length; | 1701 InstanceType instance_type, |
| 1694 if (encoding == String::TWO_BYTE_ENCODING) { | 1702 HAllocationMode allocation_mode) { |
| 1695 size = AddUncasted<HShl>(length, graph()->GetConstant1()); | 1703 // Compute the effective allocation size. |
| 1704 HValue* size = object_size; |
| 1705 if (allocation_mode.CreateAllocationMementos()) { |
| 1706 size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize)); |
| 1696 size->ClearFlag(HValue::kCanOverflow); | 1707 size->ClearFlag(HValue::kCanOverflow); |
| 1697 size->SetFlag(HValue::kUint32); | |
| 1698 } | 1708 } |
| 1699 size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>( | 1709 |
| 1700 SeqString::kHeaderSize + kObjectAlignmentMask))); | 1710 // Perform the actual allocation. |
| 1701 size->ClearFlag(HValue::kCanOverflow); | 1711 HAllocate* object = Add<HAllocate>( |
| 1702 size = AddUncasted<HBitwise>( | 1712 size, type, allocation_mode.GetPretenureMode(), |
| 1703 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( | 1713 instance_type, allocation_mode.feedback_site()); |
| 1704 ~kObjectAlignmentMask))); | 1714 |
| 1705 return size; | 1715 // Setup the allocation memento. |
| 1716 if (allocation_mode.CreateAllocationMementos()) { |
| 1717 BuildCreateAllocationMemento( |
| 1718 object, object_size, allocation_mode.current_site()); |
| 1719 } |
| 1720 |
| 1721 return object; |
| 1706 } | 1722 } |
| 1707 | 1723 |
| 1708 | 1724 |
| 1725 HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length, |
| 1726 HValue* right_length) { |
| 1727 // Compute the combined string length. If the result is larger than the max |
| 1728 // supported string length, we bailout to the runtime. This is done implicitly |
| 1729 // when converting the result back to a smi in case the max string length |
| 1730 // equals the max smi value. Otherwise, for platforms with 32-bit smis, we do |
| 1731 HValue* length = AddUncasted<HAdd>(left_length, right_length); |
| 1732 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); |
| 1733 if (String::kMaxLength != Smi::kMaxValue) { |
| 1734 IfBuilder if_nooverflow(this); |
| 1735 if_nooverflow.If<HCompareNumericAndBranch>( |
| 1736 length, Add<HConstant>(String::kMaxLength), Token::LTE); |
| 1737 if_nooverflow.Then(); |
| 1738 if_nooverflow.ElseDeopt("String length exceeds limit"); |
| 1739 } |
| 1740 return length; |
| 1741 } |
| 1742 |
| 1743 |
| 1744 HValue* HGraphBuilder::BuildCreateConsString( |
| 1745 HValue* length, |
| 1746 HValue* left, |
| 1747 HValue* right, |
| 1748 HAllocationMode allocation_mode) { |
| 1749 // Determine the string instance types. |
| 1750 HInstruction* left_instance_type = AddLoadStringInstanceType(left); |
| 1751 HInstruction* right_instance_type = AddLoadStringInstanceType(right); |
| 1752 |
| 1753 // Allocate the cons string object. HAllocate does not care whether we |
| 1754 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use |
| 1755 // CONS_STRING_TYPE here. Below we decide whether the cons string is |
| 1756 // one-byte or two-byte and set the appropriate map. |
| 1757 ASSERT(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE, |
| 1758 CONS_ASCII_STRING_TYPE)); |
| 1759 HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize), |
| 1760 HType::String(), CONS_STRING_TYPE, |
| 1761 allocation_mode); |
| 1762 |
| 1763 // Compute intersection and difference of instance types. |
| 1764 HValue* anded_instance_types = AddUncasted<HBitwise>( |
| 1765 Token::BIT_AND, left_instance_type, right_instance_type); |
| 1766 HValue* xored_instance_types = AddUncasted<HBitwise>( |
| 1767 Token::BIT_XOR, left_instance_type, right_instance_type); |
| 1768 |
| 1769 // We create a one-byte cons string if |
| 1770 // 1. both strings are one-byte, or |
| 1771 // 2. at least one of the strings is two-byte, but happens to contain only |
| 1772 // one-byte characters. |
| 1773 // To do this, we check |
| 1774 // 1. if both strings are one-byte, or if the one-byte data hint is set in |
| 1775 // both strings, or |
| 1776 // 2. if one of the strings has the one-byte data hint set and the other |
| 1777 // string is one-byte. |
| 1778 IfBuilder if_onebyte(this); |
| 1779 STATIC_ASSERT(kOneByteStringTag != 0); |
| 1780 STATIC_ASSERT(kOneByteDataHintMask != 0); |
| 1781 if_onebyte.If<HCompareNumericAndBranch>( |
| 1782 AddUncasted<HBitwise>( |
| 1783 Token::BIT_AND, anded_instance_types, |
| 1784 Add<HConstant>(static_cast<int32_t>( |
| 1785 kStringEncodingMask | kOneByteDataHintMask))), |
| 1786 graph()->GetConstant0(), Token::NE); |
| 1787 if_onebyte.Or(); |
| 1788 STATIC_ASSERT(kOneByteStringTag != 0 && |
| 1789 kOneByteDataHintTag != 0 && |
| 1790 kOneByteDataHintTag != kOneByteStringTag); |
| 1791 if_onebyte.If<HCompareNumericAndBranch>( |
| 1792 AddUncasted<HBitwise>( |
| 1793 Token::BIT_AND, xored_instance_types, |
| 1794 Add<HConstant>(static_cast<int32_t>( |
| 1795 kOneByteStringTag | kOneByteDataHintTag))), |
| 1796 Add<HConstant>(static_cast<int32_t>( |
| 1797 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); |
| 1798 if_onebyte.Then(); |
| 1799 { |
| 1800 // We can safely skip the write barrier for storing the map here. |
| 1801 Handle<Map> map = isolate()->factory()->cons_ascii_string_map(); |
| 1802 AddStoreMapConstantNoWriteBarrier(result, map); |
| 1803 } |
| 1804 if_onebyte.Else(); |
| 1805 { |
| 1806 // We can safely skip the write barrier for storing the map here. |
| 1807 Handle<Map> map = isolate()->factory()->cons_string_map(); |
| 1808 AddStoreMapConstantNoWriteBarrier(result, map); |
| 1809 } |
| 1810 if_onebyte.End(); |
| 1811 |
| 1812 // Initialize the cons string fields. |
| 1813 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(), |
| 1814 Add<HConstant>(String::kEmptyHashField)); |
| 1815 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length); |
| 1816 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left); |
| 1817 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right); |
| 1818 |
| 1819 // Count the native string addition. |
| 1820 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1821 |
| 1822 return result; |
| 1823 } |
| 1824 |
| 1825 |
| 1709 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, | 1826 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, |
| 1710 HValue* src_offset, | 1827 HValue* src_offset, |
| 1711 String::Encoding src_encoding, | 1828 String::Encoding src_encoding, |
| 1712 HValue* dst, | 1829 HValue* dst, |
| 1713 HValue* dst_offset, | 1830 HValue* dst_offset, |
| 1714 String::Encoding dst_encoding, | 1831 String::Encoding dst_encoding, |
| 1715 HValue* length) { | 1832 HValue* length) { |
| 1716 ASSERT(dst_encoding != String::ONE_BYTE_ENCODING || | 1833 ASSERT(dst_encoding != String::ONE_BYTE_ENCODING || |
| 1717 src_encoding == String::ONE_BYTE_ENCODING); | 1834 src_encoding == String::ONE_BYTE_ENCODING); |
| 1718 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); | 1835 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); |
| 1719 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); | 1836 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); |
| 1720 { | 1837 { |
| 1721 HValue* src_index = AddUncasted<HAdd>(src_offset, index); | 1838 HValue* src_index = AddUncasted<HAdd>(src_offset, index); |
| 1722 HValue* value = | 1839 HValue* value = |
| 1723 AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index); | 1840 AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index); |
| 1724 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index); | 1841 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index); |
| 1725 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); | 1842 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); |
| 1726 } | 1843 } |
| 1727 loop.EndBody(); | 1844 loop.EndBody(); |
| 1728 } | 1845 } |
| 1729 | 1846 |
| 1730 | 1847 |
| 1731 HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left, | 1848 HValue* HGraphBuilder::BuildUncheckedStringAdd( |
| 1732 HValue* right, | 1849 HValue* left, |
| 1733 PretenureFlag pretenure_flag) { | 1850 HValue* right, |
| 1851 HAllocationMode allocation_mode) { |
| 1734 // Determine the string lengths. | 1852 // Determine the string lengths. |
| 1735 HValue* left_length = Add<HLoadNamedField>( | 1853 HValue* left_length = AddLoadStringLength(left); |
| 1736 left, HObjectAccess::ForStringLength()); | 1854 HValue* right_length = AddLoadStringLength(right); |
| 1737 HValue* right_length = Add<HLoadNamedField>( | |
| 1738 right, HObjectAccess::ForStringLength()); | |
| 1739 | 1855 |
| 1740 // Compute the combined string length. If the result is larger than the max | 1856 // Compute the combined string length. |
| 1741 // supported string length, we bailout to the runtime. This is done implicitly | 1857 HValue* length = BuildAddStringLengths(left_length, right_length); |
| 1742 // when converting the result back to a smi in case the max string length | 1858 |
| 1743 // equals the max smi valie. Otherwise, for platforms with 32-bit smis, we do | 1859 // Do some manual constant folding here. |
| 1744 HValue* length = AddUncasted<HAdd>(left_length, right_length); | 1860 if (left_length->IsConstant()) { |
| 1745 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); | 1861 HConstant* c_left_length = HConstant::cast(left_length); |
| 1746 if (String::kMaxLength != Smi::kMaxValue) { | 1862 ASSERT_NE(0, c_left_length->Integer32Value()); |
| 1747 IfBuilder if_nooverflow(this); | 1863 if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) { |
| 1748 if_nooverflow.If<HCompareNumericAndBranch>( | 1864 // The right string contains at least one character. |
| 1749 length, Add<HConstant>(String::kMaxLength), Token::LTE); | 1865 return BuildCreateConsString(length, left, right, allocation_mode); |
| 1750 if_nooverflow.Then(); | 1866 } |
| 1751 if_nooverflow.ElseDeopt("String length exceeds limit"); | 1867 } else if (right_length->IsConstant()) { |
| 1868 HConstant* c_right_length = HConstant::cast(right_length); |
| 1869 ASSERT_NE(0, c_right_length->Integer32Value()); |
| 1870 if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) { |
| 1871 // The left string contains at least one character. |
| 1872 return BuildCreateConsString(length, left, right, allocation_mode); |
| 1873 } |
| 1752 } | 1874 } |
| 1753 | 1875 |
| 1754 // Determine the string instance types. | |
| 1755 HLoadNamedField* left_instance_type = Add<HLoadNamedField>( | |
| 1756 Add<HLoadNamedField>(left, HObjectAccess::ForMap()), | |
| 1757 HObjectAccess::ForMapInstanceType()); | |
| 1758 HLoadNamedField* right_instance_type = Add<HLoadNamedField>( | |
| 1759 Add<HLoadNamedField>(right, HObjectAccess::ForMap()), | |
| 1760 HObjectAccess::ForMapInstanceType()); | |
| 1761 | |
| 1762 // Compute difference of instance types. | |
| 1763 HValue* xored_instance_types = AddUncasted<HBitwise>( | |
| 1764 Token::BIT_XOR, left_instance_type, right_instance_type); | |
| 1765 | |
| 1766 // Check if we should create a cons string. | 1876 // Check if we should create a cons string. |
| 1767 IfBuilder if_createcons(this); | 1877 IfBuilder if_createcons(this); |
| 1768 if_createcons.If<HCompareNumericAndBranch>( | 1878 if_createcons.If<HCompareNumericAndBranch>( |
| 1769 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); | 1879 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); |
| 1770 if_createcons.Then(); | 1880 if_createcons.Then(); |
| 1771 { | 1881 { |
| 1772 // Allocate the cons string object. HAllocate does not care whether we | 1882 // Create a cons string. |
| 1773 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use | 1883 Push(BuildCreateConsString(length, left, right, allocation_mode)); |
| 1774 // CONS_STRING_TYPE here. Below we decide whether the cons string is | |
| 1775 // one-byte or two-byte and set the appropriate map. | |
| 1776 HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize), | |
| 1777 HType::String(), pretenure_flag, | |
| 1778 CONS_STRING_TYPE); | |
| 1779 | |
| 1780 // Compute the intersection of instance types. | |
| 1781 HValue* anded_instance_types = AddUncasted<HBitwise>( | |
| 1782 Token::BIT_AND, left_instance_type, right_instance_type); | |
| 1783 | |
| 1784 // We create a one-byte cons string if | |
| 1785 // 1. both strings are one-byte, or | |
| 1786 // 2. at least one of the strings is two-byte, but happens to contain only | |
| 1787 // one-byte characters. | |
| 1788 // To do this, we check | |
| 1789 // 1. if both strings are one-byte, or if the one-byte data hint is set in | |
| 1790 // both strings, or | |
| 1791 // 2. if one of the strings has the one-byte data hint set and the other | |
| 1792 // string is one-byte. | |
| 1793 IfBuilder if_onebyte(this); | |
| 1794 STATIC_ASSERT(kOneByteStringTag != 0); | |
| 1795 STATIC_ASSERT(kOneByteDataHintMask != 0); | |
| 1796 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1797 AddUncasted<HBitwise>( | |
| 1798 Token::BIT_AND, anded_instance_types, | |
| 1799 Add<HConstant>(static_cast<int32_t>( | |
| 1800 kStringEncodingMask | kOneByteDataHintMask))), | |
| 1801 graph()->GetConstant0(), Token::NE); | |
| 1802 if_onebyte.Or(); | |
| 1803 STATIC_ASSERT(kOneByteStringTag != 0 && | |
| 1804 kOneByteDataHintTag != 0 && | |
| 1805 kOneByteDataHintTag != kOneByteStringTag); | |
| 1806 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1807 AddUncasted<HBitwise>( | |
| 1808 Token::BIT_AND, xored_instance_types, | |
| 1809 Add<HConstant>(static_cast<int32_t>( | |
| 1810 kOneByteStringTag | kOneByteDataHintTag))), | |
| 1811 Add<HConstant>(static_cast<int32_t>( | |
| 1812 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); | |
| 1813 if_onebyte.Then(); | |
| 1814 { | |
| 1815 // We can safely skip the write barrier for storing the map here. | |
| 1816 Handle<Map> map = isolate()->factory()->cons_ascii_string_map(); | |
| 1817 AddStoreMapConstantNoWriteBarrier(string, map); | |
| 1818 } | |
| 1819 if_onebyte.Else(); | |
| 1820 { | |
| 1821 // We can safely skip the write barrier for storing the map here. | |
| 1822 Handle<Map> map = isolate()->factory()->cons_string_map(); | |
| 1823 AddStoreMapConstantNoWriteBarrier(string, map); | |
| 1824 } | |
| 1825 if_onebyte.End(); | |
| 1826 | |
| 1827 // Initialize the cons string fields. | |
| 1828 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), | |
| 1829 Add<HConstant>(String::kEmptyHashField)); | |
| 1830 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length); | |
| 1831 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left); | |
| 1832 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(), | |
| 1833 right); | |
| 1834 | |
| 1835 // Count the native string addition. | |
| 1836 AddIncrementCounter(isolate()->counters()->string_add_native()); | |
| 1837 | |
| 1838 // Cons string is result. | |
| 1839 Push(string); | |
| 1840 } | 1884 } |
| 1841 if_createcons.Else(); | 1885 if_createcons.Else(); |
| 1842 { | 1886 { |
| 1843 // Compute union of instance types. | 1887 // Determine the string instance types. |
| 1888 HValue* left_instance_type = AddLoadStringInstanceType(left); |
| 1889 HValue* right_instance_type = AddLoadStringInstanceType(right); |
| 1890 |
| 1891 // Compute union and difference of instance types. |
| 1844 HValue* ored_instance_types = AddUncasted<HBitwise>( | 1892 HValue* ored_instance_types = AddUncasted<HBitwise>( |
| 1845 Token::BIT_OR, left_instance_type, right_instance_type); | 1893 Token::BIT_OR, left_instance_type, right_instance_type); |
| 1894 HValue* xored_instance_types = AddUncasted<HBitwise>( |
| 1895 Token::BIT_XOR, left_instance_type, right_instance_type); |
| 1846 | 1896 |
| 1847 // Check if both strings have the same encoding and both are | 1897 // Check if both strings have the same encoding and both are |
| 1848 // sequential. | 1898 // sequential. |
| 1849 IfBuilder if_sameencodingandsequential(this); | 1899 IfBuilder if_sameencodingandsequential(this); |
| 1850 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | 1900 if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
| 1851 AddUncasted<HBitwise>( | 1901 AddUncasted<HBitwise>( |
| 1852 Token::BIT_AND, xored_instance_types, | 1902 Token::BIT_AND, xored_instance_types, |
| 1853 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | 1903 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
| 1854 graph()->GetConstant0(), Token::EQ); | 1904 graph()->GetConstant0(), Token::EQ); |
| 1855 if_sameencodingandsequential.And(); | 1905 if_sameencodingandsequential.And(); |
| 1856 STATIC_ASSERT(kSeqStringTag == 0); | 1906 STATIC_ASSERT(kSeqStringTag == 0); |
| 1857 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | 1907 if_sameencodingandsequential.If<HCompareNumericAndBranch>( |
| 1858 AddUncasted<HBitwise>( | 1908 AddUncasted<HBitwise>( |
| 1859 Token::BIT_AND, ored_instance_types, | 1909 Token::BIT_AND, ored_instance_types, |
| 1860 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), | 1910 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), |
| 1861 graph()->GetConstant0(), Token::EQ); | 1911 graph()->GetConstant0(), Token::EQ); |
| 1862 if_sameencodingandsequential.Then(); | 1912 if_sameencodingandsequential.Then(); |
| 1863 { | 1913 { |
| 1864 // Check if the result is a one-byte string. | 1914 HConstant* string_map = |
| 1915 Add<HConstant>(isolate()->factory()->string_map()); |
| 1916 HConstant* ascii_string_map = |
| 1917 Add<HConstant>(isolate()->factory()->ascii_string_map()); |
| 1918 |
| 1919 // Determine map and size depending on whether result is one-byte string. |
| 1865 IfBuilder if_onebyte(this); | 1920 IfBuilder if_onebyte(this); |
| 1866 STATIC_ASSERT(kOneByteStringTag != 0); | 1921 STATIC_ASSERT(kOneByteStringTag != 0); |
| 1867 if_onebyte.If<HCompareNumericAndBranch>( | 1922 if_onebyte.If<HCompareNumericAndBranch>( |
| 1868 AddUncasted<HBitwise>( | 1923 AddUncasted<HBitwise>( |
| 1869 Token::BIT_AND, ored_instance_types, | 1924 Token::BIT_AND, ored_instance_types, |
| 1870 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | 1925 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), |
| 1871 graph()->GetConstant0(), Token::NE); | 1926 graph()->GetConstant0(), Token::NE); |
| 1872 if_onebyte.Then(); | 1927 if_onebyte.Then(); |
| 1873 { | 1928 { |
| 1874 // Calculate the number of bytes needed for the characters in the | 1929 // Allocate sequential one-byte string object. |
| 1875 // string while observing object alignment. | 1930 Push(length); |
| 1876 HValue* size = BuildSeqStringSizeFor( | 1931 Push(ascii_string_map); |
| 1877 length, String::ONE_BYTE_ENCODING); | |
| 1878 | |
| 1879 // Allocate the ASCII string object. | |
| 1880 Handle<Map> map = isolate()->factory()->ascii_string_map(); | |
| 1881 HAllocate* string = Add<HAllocate>(size, HType::String(), | |
| 1882 pretenure_flag, ASCII_STRING_TYPE); | |
| 1883 string->set_known_initial_map(map); | |
| 1884 | |
| 1885 // We can safely skip the write barrier for storing map here. | |
| 1886 AddStoreMapConstantNoWriteBarrier(string, map); | |
| 1887 | |
| 1888 // Length must be stored into the string before we copy characters to | |
| 1889 // make debug verification code happy. | |
| 1890 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), | |
| 1891 length); | |
| 1892 | |
| 1893 // Copy bytes from the left string. | |
| 1894 BuildCopySeqStringChars( | |
| 1895 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1896 string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1897 left_length); | |
| 1898 | |
| 1899 // Copy bytes from the right string. | |
| 1900 BuildCopySeqStringChars( | |
| 1901 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1902 string, left_length, String::ONE_BYTE_ENCODING, | |
| 1903 right_length); | |
| 1904 | |
| 1905 // Count the native string addition. | |
| 1906 AddIncrementCounter(isolate()->counters()->string_add_native()); | |
| 1907 | |
| 1908 // Return the string. | |
| 1909 Push(string); | |
| 1910 } | 1932 } |
| 1911 if_onebyte.Else(); | 1933 if_onebyte.Else(); |
| 1912 { | 1934 { |
| 1913 // Calculate the number of bytes needed for the characters in the | 1935 // Allocate sequential two-byte string object. |
| 1914 // string while observing object alignment. | 1936 HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1()); |
| 1915 HValue* size = BuildSeqStringSizeFor( | 1937 size->ClearFlag(HValue::kCanOverflow); |
| 1916 length, String::TWO_BYTE_ENCODING); | 1938 size->SetFlag(HValue::kUint32); |
| 1939 Push(size); |
| 1940 Push(string_map); |
| 1941 } |
| 1942 if_onebyte.End(); |
| 1943 HValue* map = Pop(); |
| 1917 | 1944 |
| 1918 // Allocate the two-byte string object. | 1945 // Calculate the number of bytes needed for the characters in the |
| 1919 Handle<Map> map = isolate()->factory()->string_map(); | 1946 // string while observing object alignment. |
| 1920 HAllocate* string = Add<HAllocate>(size, HType::String(), | 1947 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 1921 pretenure_flag, STRING_TYPE); | 1948 HValue* size = Pop(); |
| 1922 string->set_known_initial_map(map); | 1949 size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>( |
| 1950 SeqString::kHeaderSize + kObjectAlignmentMask))); |
| 1951 size->ClearFlag(HValue::kCanOverflow); |
| 1952 size = AddUncasted<HBitwise>( |
| 1953 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( |
| 1954 ~kObjectAlignmentMask))); |
| 1923 | 1955 |
| 1924 // We can safely skip the write barrier for storing map here. | 1956 // Allocate the string object. HAllocate does not care whether we pass |
| 1925 AddStoreMapConstantNoWriteBarrier(string, map); | 1957 // STRING_TYPE or ASCII_STRING_TYPE here, so we just use STRING_TYPE here. |
| 1958 HAllocate* result = BuildAllocate( |
| 1959 size, HType::String(), STRING_TYPE, allocation_mode); |
| 1926 | 1960 |
| 1927 // Length must be stored into the string before we copy characters to | 1961 // We can safely skip the write barrier for storing map here. |
| 1928 // make debug verification code happy. | 1962 AddStoreMapNoWriteBarrier(result, map); |
| 1929 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), | |
| 1930 length); | |
| 1931 | 1963 |
| 1932 // Copy bytes from the left string. | 1964 // Initialize the string fields. |
| 1965 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(), |
| 1966 Add<HConstant>(String::kEmptyHashField)); |
| 1967 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length); |
| 1968 |
| 1969 // Copy characters to the result string. |
| 1970 IfBuilder if_twobyte(this); |
| 1971 if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map); |
| 1972 if_twobyte.Then(); |
| 1973 { |
| 1974 // Copy characters from the left string. |
| 1933 BuildCopySeqStringChars( | 1975 BuildCopySeqStringChars( |
| 1934 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | 1976 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1935 string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | 1977 result, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1936 left_length); | 1978 left_length); |
| 1937 | 1979 |
| 1938 // Copy bytes from the right string. | 1980 // Copy characters from the right string. |
| 1939 BuildCopySeqStringChars( | 1981 BuildCopySeqStringChars( |
| 1940 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | 1982 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, |
| 1941 string, left_length, String::TWO_BYTE_ENCODING, | 1983 result, left_length, String::TWO_BYTE_ENCODING, |
| 1942 right_length); | 1984 right_length); |
| 1985 } |
| 1986 if_twobyte.Else(); |
| 1987 { |
| 1988 // Copy characters from the left string. |
| 1989 BuildCopySeqStringChars( |
| 1990 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1991 result, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1992 left_length); |
| 1943 | 1993 |
| 1944 // Return the string. | 1994 // Copy characters from the right string. |
| 1945 Push(string); | 1995 BuildCopySeqStringChars( |
| 1996 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, |
| 1997 result, left_length, String::ONE_BYTE_ENCODING, |
| 1998 right_length); |
| 1946 } | 1999 } |
| 1947 if_onebyte.End(); | 2000 if_twobyte.End(); |
| 1948 | |
| 1949 // Initialize the (common) string fields. | |
| 1950 HValue* string = Pop(); | |
| 1951 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), | |
| 1952 Add<HConstant>(String::kEmptyHashField)); | |
| 1953 | 2001 |
| 1954 // Count the native string addition. | 2002 // Count the native string addition. |
| 1955 AddIncrementCounter(isolate()->counters()->string_add_native()); | 2003 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1956 | 2004 |
| 1957 Push(string); | 2005 // Return the sequential string. |
| 2006 Push(result); |
| 1958 } | 2007 } |
| 1959 if_sameencodingandsequential.Else(); | 2008 if_sameencodingandsequential.Else(); |
| 1960 { | 2009 { |
| 1961 // Fallback to the runtime to add the two strings. | 2010 // Fallback to the runtime to add the two strings. |
| 1962 Add<HPushArgument>(left); | 2011 Add<HPushArgument>(left); |
| 1963 Add<HPushArgument>(right); | 2012 Add<HPushArgument>(right); |
| 1964 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), | 2013 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), |
| 1965 Runtime::FunctionForId(Runtime::kStringAdd), | 2014 Runtime::FunctionForId(Runtime::kStringAdd), |
| 1966 2)); | 2015 2)); |
| 1967 } | 2016 } |
| 1968 if_sameencodingandsequential.End(); | 2017 if_sameencodingandsequential.End(); |
| 1969 } | 2018 } |
| 1970 if_createcons.End(); | 2019 if_createcons.End(); |
| 1971 | 2020 |
| 1972 return Pop(); | 2021 return Pop(); |
| 1973 } | 2022 } |
| 1974 | 2023 |
| 1975 | 2024 |
| 1976 HValue* HGraphBuilder::BuildStringAdd(HValue* left, | 2025 HValue* HGraphBuilder::BuildStringAdd( |
| 1977 HValue* right, | 2026 HValue* left, |
| 1978 PretenureFlag pretenure_flag) { | 2027 HValue* right, |
| 1979 // Determine the string lengths. | 2028 HAllocationMode allocation_mode) { |
| 1980 HValue* left_length = Add<HLoadNamedField>( | 2029 NoObservableSideEffectsScope no_effects(this); |
| 1981 left, HObjectAccess::ForStringLength()); | 2030 |
| 1982 HValue* right_length = Add<HLoadNamedField>( | 2031 // Determine string lengths. |
| 1983 right, HObjectAccess::ForStringLength()); | 2032 HValue* left_length = AddLoadStringLength(left); |
| 2033 HValue* right_length = AddLoadStringLength(right); |
| 1984 | 2034 |
| 1985 // Check if left string is empty. | 2035 // Check if left string is empty. |
| 1986 IfBuilder if_leftisempty(this); | 2036 IfBuilder if_leftempty(this); |
| 1987 if_leftisempty.If<HCompareNumericAndBranch>( | 2037 if_leftempty.If<HCompareNumericAndBranch>( |
| 1988 left_length, graph()->GetConstant0(), Token::EQ); | 2038 left_length, graph()->GetConstant0(), Token::EQ); |
| 1989 if_leftisempty.Then(); | 2039 if_leftempty.Then(); |
| 1990 { | 2040 { |
| 1991 // Count the native string addition. | 2041 // Count the native string addition. |
| 1992 AddIncrementCounter(isolate()->counters()->string_add_native()); | 2042 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 1993 | 2043 |
| 1994 // Just return the right string. | 2044 // Just return the right string. |
| 1995 Push(right); | 2045 Push(right); |
| 1996 } | 2046 } |
| 1997 if_leftisempty.Else(); | 2047 if_leftempty.Else(); |
| 1998 { | 2048 { |
| 1999 // Check if right string is empty. | 2049 // Check if right string is empty. |
| 2000 IfBuilder if_rightisempty(this); | 2050 IfBuilder if_rightempty(this); |
| 2001 if_rightisempty.If<HCompareNumericAndBranch>( | 2051 if_rightempty.If<HCompareNumericAndBranch>( |
| 2002 right_length, graph()->GetConstant0(), Token::EQ); | 2052 right_length, graph()->GetConstant0(), Token::EQ); |
| 2003 if_rightisempty.Then(); | 2053 if_rightempty.Then(); |
| 2004 { | 2054 { |
| 2005 // Count the native string addition. | 2055 // Count the native string addition. |
| 2006 AddIncrementCounter(isolate()->counters()->string_add_native()); | 2056 AddIncrementCounter(isolate()->counters()->string_add_native()); |
| 2007 | 2057 |
| 2008 // Just return the left string. | 2058 // Just return the left string. |
| 2009 Push(left); | 2059 Push(left); |
| 2010 } | 2060 } |
| 2011 if_rightisempty.Else(); | 2061 if_rightempty.Else(); |
| 2012 { | 2062 { |
| 2013 // Concatenate the two non-empty strings. | 2063 // Add the two non-empty strings. |
| 2014 Push(BuildUncheckedStringAdd(left, right, pretenure_flag)); | 2064 Push(BuildUncheckedStringAdd(left, right, allocation_mode)); |
| 2015 } | 2065 } |
| 2016 if_rightisempty.End(); | 2066 if_rightempty.End(); |
| 2017 } | 2067 } |
| 2018 if_leftisempty.End(); | 2068 if_leftempty.End(); |
| 2019 | 2069 |
| 2020 return Pop(); | 2070 return Pop(); |
| 2021 } | 2071 } |
| 2022 | 2072 |
| 2023 | 2073 |
| 2024 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 2074 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 2025 HValue* checked_object, | 2075 HValue* checked_object, |
| 2026 HValue* key, | 2076 HValue* key, |
| 2027 HValue* val, | 2077 HValue* val, |
| 2028 bool is_js_array, | 2078 bool is_js_array, |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2097 // deopt, leaving the backing store in an invalid state. | 2147 // deopt, leaving the backing store in an invalid state. |
| 2098 if (is_store && IsFastSmiElementsKind(elements_kind) && | 2148 if (is_store && IsFastSmiElementsKind(elements_kind) && |
| 2099 !val->type().IsSmi()) { | 2149 !val->type().IsSmi()) { |
| 2100 val = AddUncasted<HForceRepresentation>(val, Representation::Smi()); | 2150 val = AddUncasted<HForceRepresentation>(val, Representation::Smi()); |
| 2101 } | 2151 } |
| 2102 | 2152 |
| 2103 if (IsGrowStoreMode(store_mode)) { | 2153 if (IsGrowStoreMode(store_mode)) { |
| 2104 NoObservableSideEffectsScope no_effects(this); | 2154 NoObservableSideEffectsScope no_effects(this); |
| 2105 elements = BuildCheckForCapacityGrow(checked_object, elements, | 2155 elements = BuildCheckForCapacityGrow(checked_object, elements, |
| 2106 elements_kind, length, key, | 2156 elements_kind, length, key, |
| 2107 is_js_array); | 2157 is_js_array, is_store); |
| 2108 checked_key = key; | 2158 checked_key = key; |
| 2109 } else { | 2159 } else { |
| 2110 checked_key = Add<HBoundsCheck>(key, length); | 2160 checked_key = Add<HBoundsCheck>(key, length); |
| 2111 | 2161 |
| 2112 if (is_store && (fast_elements || fast_smi_only_elements)) { | 2162 if (is_store && (fast_elements || fast_smi_only_elements)) { |
| 2113 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { | 2163 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { |
| 2114 NoObservableSideEffectsScope no_effects(this); | 2164 NoObservableSideEffectsScope no_effects(this); |
| 2115 elements = BuildCopyElementsOnWrite(checked_object, elements, | 2165 elements = BuildCopyElementsOnWrite(checked_object, elements, |
| 2116 elements_kind, length); | 2166 elements_kind, length); |
| 2117 } else { | 2167 } else { |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2261 HValue* val, | 2311 HValue* val, |
| 2262 HValue* dependency, | 2312 HValue* dependency, |
| 2263 ElementsKind elements_kind, | 2313 ElementsKind elements_kind, |
| 2264 bool is_store, | 2314 bool is_store, |
| 2265 LoadKeyedHoleMode load_mode) { | 2315 LoadKeyedHoleMode load_mode) { |
| 2266 if (is_store) { | 2316 if (is_store) { |
| 2267 ASSERT(val != NULL); | 2317 ASSERT(val != NULL); |
| 2268 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) { | 2318 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) { |
| 2269 val = Add<HClampToUint8>(val); | 2319 val = Add<HClampToUint8>(val); |
| 2270 } | 2320 } |
| 2271 return Add<HStoreKeyed>(elements, checked_key, val, elements_kind); | 2321 return Add<HStoreKeyed>(elements, checked_key, val, elements_kind, |
| 2322 elements_kind == FAST_SMI_ELEMENTS |
| 2323 ? STORE_TO_INITIALIZED_ENTRY |
| 2324 : INITIALIZING_STORE); |
| 2272 } | 2325 } |
| 2273 | 2326 |
| 2274 ASSERT(!is_store); | 2327 ASSERT(!is_store); |
| 2275 ASSERT(val == NULL); | 2328 ASSERT(val == NULL); |
| 2276 HLoadKeyed* load = Add<HLoadKeyed>( | 2329 HLoadKeyed* load = Add<HLoadKeyed>( |
| 2277 elements, checked_key, dependency, elements_kind, load_mode); | 2330 elements, checked_key, dependency, elements_kind, load_mode); |
| 2278 if (FLAG_opt_safe_uint32_operations && | 2331 if (FLAG_opt_safe_uint32_operations && |
| 2279 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { | 2332 elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) { |
| 2280 graph()->RecordUint32Instruction(load); | 2333 graph()->RecordUint32Instruction(load); |
| 2281 } | 2334 } |
| (...skipping 1849 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4131 ASSERT(current_block()->HasPredecessor()); | 4184 ASSERT(current_block()->HasPredecessor()); |
| 4132 return Bailout(kWithStatement); | 4185 return Bailout(kWithStatement); |
| 4133 } | 4186 } |
| 4134 | 4187 |
| 4135 | 4188 |
| 4136 void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { | 4189 void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
| 4137 ASSERT(!HasStackOverflow()); | 4190 ASSERT(!HasStackOverflow()); |
| 4138 ASSERT(current_block() != NULL); | 4191 ASSERT(current_block() != NULL); |
| 4139 ASSERT(current_block()->HasPredecessor()); | 4192 ASSERT(current_block()->HasPredecessor()); |
| 4140 | 4193 |
| 4141 // We only optimize switch statements with smi-literal smi comparisons, | 4194 // We only optimize switch statements with a bounded number of clauses. |
| 4142 // with a bounded number of clauses. | |
| 4143 const int kCaseClauseLimit = 128; | 4195 const int kCaseClauseLimit = 128; |
| 4144 ZoneList<CaseClause*>* clauses = stmt->cases(); | 4196 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 4145 int clause_count = clauses->length(); | 4197 int clause_count = clauses->length(); |
| 4198 ZoneList<HBasicBlock*> body_blocks(clause_count, zone()); |
| 4146 if (clause_count > kCaseClauseLimit) { | 4199 if (clause_count > kCaseClauseLimit) { |
| 4147 return Bailout(kSwitchStatementTooManyClauses); | 4200 return Bailout(kSwitchStatementTooManyClauses); |
| 4148 } | 4201 } |
| 4149 | 4202 |
| 4150 ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH); | |
| 4151 if (stmt->switch_type() == SwitchStatement::GENERIC_SWITCH) { | |
| 4152 return Bailout(kSwitchStatementMixedOrNonLiteralSwitchLabels); | |
| 4153 } | |
| 4154 | |
| 4155 CHECK_ALIVE(VisitForValue(stmt->tag())); | 4203 CHECK_ALIVE(VisitForValue(stmt->tag())); |
| 4156 Add<HSimulate>(stmt->EntryId()); | 4204 Add<HSimulate>(stmt->EntryId()); |
| 4157 HValue* tag_value = Pop(); | 4205 HValue* tag_value = Top(); |
| 4158 HBasicBlock* first_test_block = current_block(); | 4206 Handle<Type> tag_type = stmt->tag()->bounds().lower; |
| 4159 | |
| 4160 HUnaryControlInstruction* string_check = NULL; | |
| 4161 HBasicBlock* not_string_block = NULL; | |
| 4162 | |
| 4163 // Test switch's tag value if all clauses are string literals | |
| 4164 if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) { | |
| 4165 first_test_block = graph()->CreateBasicBlock(); | |
| 4166 not_string_block = graph()->CreateBasicBlock(); | |
| 4167 string_check = New<HIsStringAndBranch>( | |
| 4168 tag_value, first_test_block, not_string_block); | |
| 4169 FinishCurrentBlock(string_check); | |
| 4170 | |
| 4171 set_current_block(first_test_block); | |
| 4172 } | |
| 4173 | 4207 |
| 4174 // 1. Build all the tests, with dangling true branches | 4208 // 1. Build all the tests, with dangling true branches |
| 4175 BailoutId default_id = BailoutId::None(); | 4209 BailoutId default_id = BailoutId::None(); |
| 4176 for (int i = 0; i < clause_count; ++i) { | 4210 for (int i = 0; i < clause_count; ++i) { |
| 4177 CaseClause* clause = clauses->at(i); | 4211 CaseClause* clause = clauses->at(i); |
| 4178 if (clause->is_default()) { | 4212 if (clause->is_default()) { |
| 4179 default_id = clause->EntryId(); | 4213 body_blocks.Add(NULL, zone()); |
| 4214 if (default_id.IsNone()) default_id = clause->EntryId(); |
| 4180 continue; | 4215 continue; |
| 4181 } | 4216 } |
| 4182 | 4217 |
| 4183 // Generate a compare and branch. | 4218 // Generate a compare and branch. |
| 4184 CHECK_ALIVE(VisitForValue(clause->label())); | 4219 CHECK_ALIVE(VisitForValue(clause->label())); |
| 4185 HValue* label_value = Pop(); | 4220 HValue* label_value = Pop(); |
| 4186 | 4221 |
| 4222 Handle<Type> label_type = clause->label()->bounds().lower; |
| 4223 Handle<Type> combined_type = clause->compare_type(); |
| 4224 HControlInstruction* compare = BuildCompareInstruction( |
| 4225 Token::EQ_STRICT, tag_value, label_value, tag_type, label_type, |
| 4226 combined_type, stmt->tag()->position(), clause->label()->position(), |
| 4227 clause->id()); |
| 4228 |
| 4187 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); | 4229 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
| 4188 HBasicBlock* body_block = graph()->CreateBasicBlock(); | 4230 HBasicBlock* body_block = graph()->CreateBasicBlock(); |
| 4189 | 4231 body_blocks.Add(body_block, zone()); |
| 4190 HControlInstruction* compare; | |
| 4191 | |
| 4192 if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { | |
| 4193 if (!clause->compare_type()->Is(Type::Smi())) { | |
| 4194 Add<HDeoptimize>("Non-smi switch type", Deoptimizer::SOFT); | |
| 4195 } | |
| 4196 | |
| 4197 HCompareNumericAndBranch* compare_ = | |
| 4198 New<HCompareNumericAndBranch>(tag_value, | |
| 4199 label_value, | |
| 4200 Token::EQ_STRICT); | |
| 4201 compare_->set_observed_input_representation( | |
| 4202 Representation::Smi(), Representation::Smi()); | |
| 4203 compare = compare_; | |
| 4204 } else { | |
| 4205 compare = New<HStringCompareAndBranch>(tag_value, | |
| 4206 label_value, | |
| 4207 Token::EQ_STRICT); | |
| 4208 } | |
| 4209 | |
| 4210 compare->SetSuccessorAt(0, body_block); | 4232 compare->SetSuccessorAt(0, body_block); |
| 4211 compare->SetSuccessorAt(1, next_test_block); | 4233 compare->SetSuccessorAt(1, next_test_block); |
| 4212 FinishCurrentBlock(compare); | 4234 FinishCurrentBlock(compare); |
| 4213 | 4235 |
| 4236 set_current_block(body_block); |
| 4237 Drop(1); // tag_value |
| 4238 |
| 4214 set_current_block(next_test_block); | 4239 set_current_block(next_test_block); |
| 4215 } | 4240 } |
| 4216 | 4241 |
| 4217 // Save the current block to use for the default or to join with the | 4242 // Save the current block to use for the default or to join with the |
| 4218 // exit. | 4243 // exit. |
| 4219 HBasicBlock* last_block = current_block(); | 4244 HBasicBlock* last_block = current_block(); |
| 4220 | 4245 Drop(1); // tag_value |
| 4221 if (not_string_block != NULL) { | |
| 4222 BailoutId join_id = !default_id.IsNone() ? default_id : stmt->ExitId(); | |
| 4223 last_block = CreateJoin(last_block, not_string_block, join_id); | |
| 4224 } | |
| 4225 | 4246 |
| 4226 // 2. Loop over the clauses and the linked list of tests in lockstep, | 4247 // 2. Loop over the clauses and the linked list of tests in lockstep, |
| 4227 // translating the clause bodies. | 4248 // translating the clause bodies. |
| 4228 HBasicBlock* curr_test_block = first_test_block; | |
| 4229 HBasicBlock* fall_through_block = NULL; | 4249 HBasicBlock* fall_through_block = NULL; |
| 4230 | 4250 |
| 4231 BreakAndContinueInfo break_info(stmt); | 4251 BreakAndContinueInfo break_info(stmt); |
| 4232 { BreakAndContinueScope push(&break_info, this); | 4252 { BreakAndContinueScope push(&break_info, this); |
| 4233 for (int i = 0; i < clause_count; ++i) { | 4253 for (int i = 0; i < clause_count; ++i) { |
| 4234 CaseClause* clause = clauses->at(i); | 4254 CaseClause* clause = clauses->at(i); |
| 4235 | 4255 |
| 4236 // Identify the block where normal (non-fall-through) control flow | 4256 // Identify the block where normal (non-fall-through) control flow |
| 4237 // goes to. | 4257 // goes to. |
| 4238 HBasicBlock* normal_block = NULL; | 4258 HBasicBlock* normal_block = NULL; |
| 4239 if (clause->is_default()) { | 4259 if (clause->is_default()) { |
| 4240 if (last_block != NULL) { | 4260 if (last_block == NULL) continue; |
| 4241 normal_block = last_block; | 4261 normal_block = last_block; |
| 4242 last_block = NULL; // Cleared to indicate we've handled it. | 4262 last_block = NULL; // Cleared to indicate we've handled it. |
| 4243 } | |
| 4244 } else { | 4263 } else { |
| 4245 // If the current test block is deoptimizing due to an unhandled clause | 4264 normal_block = body_blocks[i]; |
| 4246 // of the switch, the test instruction is in the next block since the | |
| 4247 // deopt must end the current block. | |
| 4248 if (curr_test_block->IsDeoptimizing()) { | |
| 4249 ASSERT(curr_test_block->end()->SecondSuccessor() == NULL); | |
| 4250 curr_test_block = curr_test_block->end()->FirstSuccessor(); | |
| 4251 } | |
| 4252 normal_block = curr_test_block->end()->FirstSuccessor(); | |
| 4253 curr_test_block = curr_test_block->end()->SecondSuccessor(); | |
| 4254 } | 4265 } |
| 4255 | 4266 |
| 4256 // Identify a block to emit the body into. | 4267 if (fall_through_block == NULL) { |
| 4257 if (normal_block == NULL) { | |
| 4258 if (fall_through_block == NULL) { | |
| 4259 // (a) Unreachable. | |
| 4260 if (clause->is_default()) { | |
| 4261 continue; // Might still be reachable clause bodies. | |
| 4262 } else { | |
| 4263 break; | |
| 4264 } | |
| 4265 } else { | |
| 4266 // (b) Reachable only as fall through. | |
| 4267 set_current_block(fall_through_block); | |
| 4268 } | |
| 4269 } else if (fall_through_block == NULL) { | |
| 4270 // (c) Reachable only normally. | |
| 4271 set_current_block(normal_block); | 4268 set_current_block(normal_block); |
| 4272 } else { | 4269 } else { |
| 4273 // (d) Reachable both ways. | |
| 4274 HBasicBlock* join = CreateJoin(fall_through_block, | 4270 HBasicBlock* join = CreateJoin(fall_through_block, |
| 4275 normal_block, | 4271 normal_block, |
| 4276 clause->EntryId()); | 4272 clause->EntryId()); |
| 4277 set_current_block(join); | 4273 set_current_block(join); |
| 4278 } | 4274 } |
| 4279 | 4275 |
| 4280 CHECK_BAILOUT(VisitStatements(clause->statements())); | 4276 CHECK_BAILOUT(VisitStatements(clause->statements())); |
| 4281 fall_through_block = current_block(); | 4277 fall_through_block = current_block(); |
| 4282 } | 4278 } |
| 4283 } | 4279 } |
| (...skipping 974 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5258 // Already holds a HeapNumber; load the box and write its value field. | 5254 // Already holds a HeapNumber; load the box and write its value field. |
| 5259 HInstruction* heap_number = Add<HLoadNamedField>(checked_object, | 5255 HInstruction* heap_number = Add<HLoadNamedField>(checked_object, |
| 5260 heap_number_access); | 5256 heap_number_access); |
| 5261 heap_number->set_type(HType::HeapNumber()); | 5257 heap_number->set_type(HType::HeapNumber()); |
| 5262 instr = New<HStoreNamedField>(heap_number, | 5258 instr = New<HStoreNamedField>(heap_number, |
| 5263 HObjectAccess::ForHeapNumberValue(), | 5259 HObjectAccess::ForHeapNumberValue(), |
| 5264 value); | 5260 value); |
| 5265 } | 5261 } |
| 5266 } else { | 5262 } else { |
| 5267 // This is a normal store. | 5263 // This is a normal store. |
| 5268 instr = New<HStoreNamedField>(checked_object->ActualValue(), | 5264 instr = New<HStoreNamedField>( |
| 5269 field_access, | 5265 checked_object->ActualValue(), field_access, value, |
| 5270 value); | 5266 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); |
| 5271 } | 5267 } |
| 5272 | 5268 |
| 5273 if (transition_to_field) { | 5269 if (transition_to_field) { |
| 5274 Handle<Map> transition(lookup->GetTransitionMapFromMap(*map)); | 5270 Handle<Map> transition(lookup->GetTransitionMapFromMap(*map)); |
| 5275 HConstant* transition_constant = Add<HConstant>(transition); | 5271 HConstant* transition_constant = Add<HConstant>(transition); |
| 5276 instr->SetTransition(transition_constant, top_info()); | 5272 instr->SetTransition(transition_constant, top_info()); |
| 5277 // TODO(fschneider): Record the new map type of the object in the IR to | 5273 // TODO(fschneider): Record the new map type of the object in the IR to |
| 5278 // enable elimination of redundant checks after the transition store. | 5274 // enable elimination of redundant checks after the transition store. |
| 5279 instr->SetGVNFlag(kChangesMaps); | 5275 instr->SetGVNFlag(kChangesMaps); |
| 5280 } | 5276 } |
| (...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6139 return New<HLoadNamedField>(object, access); | 6135 return New<HLoadNamedField>(object, access); |
| 6140 } | 6136 } |
| 6141 | 6137 |
| 6142 | 6138 |
| 6143 HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object, | 6139 HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object, |
| 6144 HObjectAccess access) { | 6140 HObjectAccess access) { |
| 6145 return AddInstruction(BuildLoadNamedField(object, access)); | 6141 return AddInstruction(BuildLoadNamedField(object, access)); |
| 6146 } | 6142 } |
| 6147 | 6143 |
| 6148 | 6144 |
| 6149 HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* object, | 6145 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) { |
| 6150 HValue* checked_string) { | 6146 if (string->IsConstant()) { |
| 6151 if (FLAG_fold_constants && object->IsConstant()) { | 6147 HConstant* c_string = HConstant::cast(string); |
| 6152 HConstant* constant = HConstant::cast(object); | 6148 if (c_string->HasStringValue()) { |
| 6153 if (constant->HasStringValue()) { | 6149 return Add<HConstant>(c_string->StringValue()->map()->instance_type()); |
| 6154 return New<HConstant>(constant->StringValue()->length()); | |
| 6155 } | 6150 } |
| 6156 } | 6151 } |
| 6157 return BuildLoadNamedField(checked_string, HObjectAccess::ForStringLength()); | 6152 return AddLoadNamedField( |
| 6153 AddLoadNamedField(string, HObjectAccess::ForMap()), |
| 6154 HObjectAccess::ForMapInstanceType()); |
| 6158 } | 6155 } |
| 6159 | 6156 |
| 6160 | 6157 |
| 6158 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) { |
| 6159 if (string->IsConstant()) { |
| 6160 HConstant* c_string = HConstant::cast(string); |
| 6161 if (c_string->HasStringValue()) { |
| 6162 return Add<HConstant>(c_string->StringValue()->length()); |
| 6163 } |
| 6164 } |
| 6165 return AddLoadNamedField(string, HObjectAccess::ForStringLength()); |
| 6166 } |
| 6167 |
| 6168 |
| 6161 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( | 6169 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( |
| 6162 HValue* object, | 6170 HValue* object, |
| 6163 Handle<String> name, | 6171 Handle<String> name, |
| 6164 Property* expr) { | 6172 Property* expr) { |
| 6165 if (expr->IsUninitialized()) { | 6173 if (expr->IsUninitialized()) { |
| 6166 Add<HDeoptimize>("Insufficient type feedback for generic named load", | 6174 Add<HDeoptimize>("Insufficient type feedback for generic named load", |
| 6167 Deoptimizer::SOFT); | 6175 Deoptimizer::SOFT); |
| 6168 } | 6176 } |
| 6169 return New<HLoadNamedGeneric>(object, name); | 6177 return New<HLoadNamedGeneric>(object, name); |
| 6170 } | 6178 } |
| (...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6777 if (!expr->ComputeTarget(info.map(), name)) return false; | 6785 if (!expr->ComputeTarget(info.map(), name)) return false; |
| 6778 | 6786 |
| 6779 BuildCheckHeapObject(receiver); | 6787 BuildCheckHeapObject(receiver); |
| 6780 Add<HCheckMaps>(receiver, types); | 6788 Add<HCheckMaps>(receiver, types); |
| 6781 AddCheckPrototypeMaps(expr->holder(), info.map()); | 6789 AddCheckPrototypeMaps(expr->holder(), info.map()); |
| 6782 if (FLAG_trace_inlining) { | 6790 if (FLAG_trace_inlining) { |
| 6783 Handle<JSFunction> caller = current_info()->closure(); | 6791 Handle<JSFunction> caller = current_info()->closure(); |
| 6784 SmartArrayPointer<char> caller_name = | 6792 SmartArrayPointer<char> caller_name = |
| 6785 caller->shared()->DebugName()->ToCString(); | 6793 caller->shared()->DebugName()->ToCString(); |
| 6786 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 6794 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
| 6787 *name->ToCString(), *caller_name); | 6795 name->ToCString().get(), caller_name.get()); |
| 6788 } | 6796 } |
| 6789 | 6797 |
| 6790 if (!TryInlineCall(expr)) { | 6798 if (!TryInlineCall(expr)) { |
| 6791 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 6799 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
| 6792 HCallConstantFunction* call = | 6800 HCallConstantFunction* call = |
| 6793 New<HCallConstantFunction>(expr->target(), argument_count); | 6801 New<HCallConstantFunction>(expr->target(), argument_count); |
| 6794 PreProcessCall(call); | 6802 PreProcessCall(call); |
| 6795 AddInstruction(call); | 6803 AddInstruction(call); |
| 6796 if (!ast_context()->IsEffect()) Push(call); | 6804 if (!ast_context()->IsEffect()) Push(call); |
| 6797 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 6805 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6890 } | 6898 } |
| 6891 set_current_block(if_true); | 6899 set_current_block(if_true); |
| 6892 | 6900 |
| 6893 expr->ComputeTarget(map, name); | 6901 expr->ComputeTarget(map, name); |
| 6894 AddCheckPrototypeMaps(expr->holder(), map); | 6902 AddCheckPrototypeMaps(expr->holder(), map); |
| 6895 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 6903 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 6896 Handle<JSFunction> caller = current_info()->closure(); | 6904 Handle<JSFunction> caller = current_info()->closure(); |
| 6897 SmartArrayPointer<char> caller_name = | 6905 SmartArrayPointer<char> caller_name = |
| 6898 caller->shared()->DebugName()->ToCString(); | 6906 caller->shared()->DebugName()->ToCString(); |
| 6899 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 6907 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
| 6900 *name->ToCString(), | 6908 name->ToCString().get(), |
| 6901 *caller_name); | 6909 caller_name.get()); |
| 6902 } | 6910 } |
| 6903 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { | 6911 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { |
| 6904 // Trying to inline will signal that we should bailout from the | 6912 // Trying to inline will signal that we should bailout from the |
| 6905 // entire compilation by setting stack overflow on the visitor. | 6913 // entire compilation by setting stack overflow on the visitor. |
| 6906 if (HasStackOverflow()) return; | 6914 if (HasStackOverflow()) return; |
| 6907 } else { | 6915 } else { |
| 6908 HCallConstantFunction* call = | 6916 HCallConstantFunction* call = |
| 6909 New<HCallConstantFunction>(expr->target(), argument_count); | 6917 New<HCallConstantFunction>(expr->target(), argument_count); |
| 6910 PreProcessCall(call); | 6918 PreProcessCall(call); |
| 6911 AddInstruction(call); | 6919 AddInstruction(call); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6955 | 6963 |
| 6956 void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target, | 6964 void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target, |
| 6957 Handle<JSFunction> caller, | 6965 Handle<JSFunction> caller, |
| 6958 const char* reason) { | 6966 const char* reason) { |
| 6959 if (FLAG_trace_inlining) { | 6967 if (FLAG_trace_inlining) { |
| 6960 SmartArrayPointer<char> target_name = | 6968 SmartArrayPointer<char> target_name = |
| 6961 target->shared()->DebugName()->ToCString(); | 6969 target->shared()->DebugName()->ToCString(); |
| 6962 SmartArrayPointer<char> caller_name = | 6970 SmartArrayPointer<char> caller_name = |
| 6963 caller->shared()->DebugName()->ToCString(); | 6971 caller->shared()->DebugName()->ToCString(); |
| 6964 if (reason == NULL) { | 6972 if (reason == NULL) { |
| 6965 PrintF("Inlined %s called from %s.\n", *target_name, *caller_name); | 6973 PrintF("Inlined %s called from %s.\n", target_name.get(), |
| 6974 caller_name.get()); |
| 6966 } else { | 6975 } else { |
| 6967 PrintF("Did not inline %s called from %s (%s).\n", | 6976 PrintF("Did not inline %s called from %s (%s).\n", |
| 6968 *target_name, *caller_name, reason); | 6977 target_name.get(), caller_name.get(), reason); |
| 6969 } | 6978 } |
| 6970 } | 6979 } |
| 6971 } | 6980 } |
| 6972 | 6981 |
| 6973 | 6982 |
| 6974 static const int kNotInlinable = 1000000000; | 6983 static const int kNotInlinable = 1000000000; |
| 6975 | 6984 |
| 6976 | 6985 |
| 6977 int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { | 6986 int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { |
| 6978 if (!FLAG_use_inlining) return kNotInlinable; | 6987 if (!FLAG_use_inlining) return kNotInlinable; |
| (...skipping 1632 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8611 HConstant* c_index = HConstant::cast(index); | 8620 HConstant* c_index = HConstant::cast(index); |
| 8612 if (c_string->HasStringValue() && c_index->HasNumberValue()) { | 8621 if (c_string->HasStringValue() && c_index->HasNumberValue()) { |
| 8613 int32_t i = c_index->NumberValueAsInteger32(); | 8622 int32_t i = c_index->NumberValueAsInteger32(); |
| 8614 Handle<String> s = c_string->StringValue(); | 8623 Handle<String> s = c_string->StringValue(); |
| 8615 if (i < 0 || i >= s->length()) { | 8624 if (i < 0 || i >= s->length()) { |
| 8616 return New<HConstant>(OS::nan_value()); | 8625 return New<HConstant>(OS::nan_value()); |
| 8617 } | 8626 } |
| 8618 return New<HConstant>(s->Get(i)); | 8627 return New<HConstant>(s->Get(i)); |
| 8619 } | 8628 } |
| 8620 } | 8629 } |
| 8621 BuildCheckHeapObject(string); | 8630 string = BuildCheckString(string); |
| 8622 HValue* checkstring = | 8631 index = Add<HBoundsCheck>(index, AddLoadStringLength(string)); |
| 8623 Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); | 8632 return New<HStringCharCodeAt>(string, index); |
| 8624 HInstruction* length = BuildLoadStringLength(string, checkstring); | |
| 8625 AddInstruction(length); | |
| 8626 HInstruction* checked_index = Add<HBoundsCheck>(index, length); | |
| 8627 return New<HStringCharCodeAt>(string, checked_index); | |
| 8628 } | 8633 } |
| 8629 | 8634 |
| 8630 | 8635 |
| 8631 // Checks if the given shift amounts have following forms: | 8636 // Checks if the given shift amounts have following forms: |
| 8632 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa). | 8637 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa). |
| 8633 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, | 8638 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, |
| 8634 HValue* const32_minus_sa) { | 8639 HValue* const32_minus_sa) { |
| 8635 if (sa->IsConstant() && const32_minus_sa->IsConstant()) { | 8640 if (sa->IsConstant() && const32_minus_sa->IsConstant()) { |
| 8636 const HConstant* c1 = HConstant::cast(sa); | 8641 const HConstant* c1 = HConstant::cast(sa); |
| 8637 const HConstant* c2 = HConstant::cast(const32_minus_sa); | 8642 const HConstant* c2 = HConstant::cast(const32_minus_sa); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8748 | 8753 |
| 8749 | 8754 |
| 8750 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( | 8755 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( |
| 8751 BinaryOperation* expr, | 8756 BinaryOperation* expr, |
| 8752 HValue* left, | 8757 HValue* left, |
| 8753 HValue* right) { | 8758 HValue* right) { |
| 8754 Handle<Type> left_type = expr->left()->bounds().lower; | 8759 Handle<Type> left_type = expr->left()->bounds().lower; |
| 8755 Handle<Type> right_type = expr->right()->bounds().lower; | 8760 Handle<Type> right_type = expr->right()->bounds().lower; |
| 8756 Handle<Type> result_type = expr->bounds().lower; | 8761 Handle<Type> result_type = expr->bounds().lower; |
| 8757 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); | 8762 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); |
| 8763 Handle<AllocationSite> allocation_site = expr->allocation_site(); |
| 8764 |
| 8765 HAllocationMode allocation_mode = |
| 8766 FLAG_allocation_site_pretenuring |
| 8767 ? (allocation_site.is_null() |
| 8768 ? HAllocationMode(NOT_TENURED) |
| 8769 : HAllocationMode(allocation_site)) |
| 8770 : HAllocationMode(isolate()->heap()->GetPretenureMode()); |
| 8758 | 8771 |
| 8759 HValue* result = HGraphBuilder::BuildBinaryOperation( | 8772 HValue* result = HGraphBuilder::BuildBinaryOperation( |
| 8760 expr->op(), left, right, left_type, right_type, | 8773 expr->op(), left, right, left_type, right_type, result_type, |
| 8761 result_type, fixed_right_arg); | 8774 fixed_right_arg, allocation_mode); |
| 8762 // Add a simulate after instructions with observable side effects, and | 8775 // Add a simulate after instructions with observable side effects, and |
| 8763 // after phis, which are the result of BuildBinaryOperation when we | 8776 // after phis, which are the result of BuildBinaryOperation when we |
| 8764 // inlined some complex subgraph. | 8777 // inlined some complex subgraph. |
| 8765 if (result->HasObservableSideEffects() || result->IsPhi()) { | 8778 if (result->HasObservableSideEffects() || result->IsPhi()) { |
| 8766 Push(result); | 8779 Push(result); |
| 8767 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 8780 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 8768 Drop(1); | 8781 Drop(1); |
| 8769 } | 8782 } |
| 8770 return result; | 8783 return result; |
| 8771 } | 8784 } |
| 8772 | 8785 |
| 8773 | 8786 |
| 8774 HValue* HGraphBuilder::BuildBinaryOperation( | 8787 HValue* HGraphBuilder::BuildBinaryOperation( |
| 8775 Token::Value op, | 8788 Token::Value op, |
| 8776 HValue* left, | 8789 HValue* left, |
| 8777 HValue* right, | 8790 HValue* right, |
| 8778 Handle<Type> left_type, | 8791 Handle<Type> left_type, |
| 8779 Handle<Type> right_type, | 8792 Handle<Type> right_type, |
| 8780 Handle<Type> result_type, | 8793 Handle<Type> result_type, |
| 8781 Maybe<int> fixed_right_arg) { | 8794 Maybe<int> fixed_right_arg, |
| 8795 HAllocationMode allocation_mode) { |
| 8782 | 8796 |
| 8783 Representation left_rep = Representation::FromType(left_type); | 8797 Representation left_rep = Representation::FromType(left_type); |
| 8784 Representation right_rep = Representation::FromType(right_type); | 8798 Representation right_rep = Representation::FromType(right_type); |
| 8785 | 8799 |
| 8786 bool maybe_string_add = op == Token::ADD && | 8800 bool maybe_string_add = op == Token::ADD && |
| 8787 (left_type->Maybe(Type::String()) || | 8801 (left_type->Maybe(Type::String()) || |
| 8788 right_type->Maybe(Type::String())); | 8802 right_type->Maybe(Type::String())); |
| 8789 | 8803 |
| 8790 if (left_type->Is(Type::None())) { | 8804 if (left_type->Is(Type::None())) { |
| 8791 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", | 8805 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8837 ASSERT(left_type->Is(Type::String())); | 8851 ASSERT(left_type->Is(Type::String())); |
| 8838 right = BuildNumberToString(right, right_type); | 8852 right = BuildNumberToString(right, right_type); |
| 8839 } else if (!right_type->Is(Type::String())) { | 8853 } else if (!right_type->Is(Type::String())) { |
| 8840 ASSERT(left_type->Is(Type::String())); | 8854 ASSERT(left_type->Is(Type::String())); |
| 8841 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); | 8855 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); |
| 8842 Add<HPushArgument>(left); | 8856 Add<HPushArgument>(left); |
| 8843 Add<HPushArgument>(right); | 8857 Add<HPushArgument>(right); |
| 8844 return AddUncasted<HInvokeFunction>(function, 2); | 8858 return AddUncasted<HInvokeFunction>(function, 2); |
| 8845 } | 8859 } |
| 8846 | 8860 |
| 8847 return AddUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE); | 8861 // Inline the string addition into the stub when creating allocation |
| 8862 // mementos to gather allocation site feedback. |
| 8863 if (graph()->info()->IsStub() && |
| 8864 allocation_mode.CreateAllocationMementos()) { |
| 8865 return BuildStringAdd(left, right, allocation_mode); |
| 8866 } |
| 8867 |
| 8868 // Register the dependent code with the allocation site. |
| 8869 if (!allocation_mode.feedback_site().is_null()) { |
| 8870 ASSERT(!graph()->info()->IsStub()); |
| 8871 allocation_mode.feedback_site()->AddDependentCompilationInfo( |
| 8872 AllocationSite::TENURING, top_info()); |
| 8873 } |
| 8874 |
| 8875 // Inline string addition if we know that we'll create a cons string. |
| 8876 if (left->IsConstant()) { |
| 8877 HConstant* c_left = HConstant::cast(left); |
| 8878 if (c_left->HasStringValue()) { |
| 8879 int c_left_length = c_left->StringValue()->length(); |
| 8880 if (c_left_length == 0) { |
| 8881 return right; |
| 8882 } else if (c_left_length + 1 >= ConsString::kMinLength) { |
| 8883 return BuildStringAdd(left, right, allocation_mode); |
| 8884 } |
| 8885 } |
| 8886 } |
| 8887 if (right->IsConstant()) { |
| 8888 HConstant* c_right = HConstant::cast(right); |
| 8889 if (c_right->HasStringValue()) { |
| 8890 int c_right_length = c_right->StringValue()->length(); |
| 8891 if (c_right_length == 0) { |
| 8892 return left; |
| 8893 } else if (c_right_length + 1 >= ConsString::kMinLength) { |
| 8894 return BuildStringAdd(left, right, allocation_mode); |
| 8895 } |
| 8896 } |
| 8897 } |
| 8898 |
| 8899 // Fallback to using the string add stub. |
| 8900 return AddUncasted<HStringAdd>( |
| 8901 left, right, allocation_mode.GetPretenureMode(), |
| 8902 STRING_ADD_CHECK_NONE, allocation_mode.feedback_site()); |
| 8848 } | 8903 } |
| 8849 | 8904 |
| 8850 if (graph()->info()->IsStub()) { | 8905 if (graph()->info()->IsStub()) { |
| 8851 left = EnforceNumberType(left, left_type); | 8906 left = EnforceNumberType(left, left_type); |
| 8852 right = EnforceNumberType(right, right_type); | 8907 right = EnforceNumberType(right, right_type); |
| 8853 } | 8908 } |
| 8854 | 8909 |
| 8855 Representation result_rep = Representation::FromType(result_type); | 8910 Representation result_rep = Representation::FromType(result_type); |
| 8856 | 8911 |
| 8857 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || | 8912 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9163 HValue* value = Pop(); | 9218 HValue* value = Pop(); |
| 9164 Literal* literal = expr->right()->AsLiteral(); | 9219 Literal* literal = expr->right()->AsLiteral(); |
| 9165 Handle<String> rhs = Handle<String>::cast(literal->value()); | 9220 Handle<String> rhs = Handle<String>::cast(literal->value()); |
| 9166 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs); | 9221 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs); |
| 9167 return ast_context()->ReturnControl(instr, expr->id()); | 9222 return ast_context()->ReturnControl(instr, expr->id()); |
| 9168 } | 9223 } |
| 9169 | 9224 |
| 9170 Handle<Type> left_type = expr->left()->bounds().lower; | 9225 Handle<Type> left_type = expr->left()->bounds().lower; |
| 9171 Handle<Type> right_type = expr->right()->bounds().lower; | 9226 Handle<Type> right_type = expr->right()->bounds().lower; |
| 9172 Handle<Type> combined_type = expr->combined_type(); | 9227 Handle<Type> combined_type = expr->combined_type(); |
| 9173 Representation combined_rep = Representation::FromType(combined_type); | |
| 9174 Representation left_rep = Representation::FromType(left_type); | |
| 9175 Representation right_rep = Representation::FromType(right_type); | |
| 9176 | 9228 |
| 9177 CHECK_ALIVE(VisitForValue(expr->left())); | 9229 CHECK_ALIVE(VisitForValue(expr->left())); |
| 9178 CHECK_ALIVE(VisitForValue(expr->right())); | 9230 CHECK_ALIVE(VisitForValue(expr->right())); |
| 9179 | 9231 |
| 9180 if (FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 9232 if (FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 9181 | 9233 |
| 9182 HValue* right = Pop(); | 9234 HValue* right = Pop(); |
| 9183 HValue* left = Pop(); | 9235 HValue* left = Pop(); |
| 9184 Token::Value op = expr->op(); | 9236 Token::Value op = expr->op(); |
| 9185 | 9237 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9230 } else if (op == Token::IN) { | 9282 } else if (op == Token::IN) { |
| 9231 HValue* function = AddLoadJSBuiltin(Builtins::IN); | 9283 HValue* function = AddLoadJSBuiltin(Builtins::IN); |
| 9232 Add<HPushArgument>(left); | 9284 Add<HPushArgument>(left); |
| 9233 Add<HPushArgument>(right); | 9285 Add<HPushArgument>(right); |
| 9234 // TODO(olivf) InvokeFunction produces a check for the parameter count, | 9286 // TODO(olivf) InvokeFunction produces a check for the parameter count, |
| 9235 // even though we are certain to pass the correct number of arguments here. | 9287 // even though we are certain to pass the correct number of arguments here. |
| 9236 HInstruction* result = New<HInvokeFunction>(function, 2); | 9288 HInstruction* result = New<HInvokeFunction>(function, 2); |
| 9237 return ast_context()->ReturnInstruction(result, expr->id()); | 9289 return ast_context()->ReturnInstruction(result, expr->id()); |
| 9238 } | 9290 } |
| 9239 | 9291 |
| 9292 HControlInstruction* compare = BuildCompareInstruction( |
| 9293 op, left, right, left_type, right_type, combined_type, |
| 9294 expr->left()->position(), expr->right()->position(), expr->id()); |
| 9295 if (compare == NULL) return; // Bailed out. |
| 9296 return ast_context()->ReturnControl(compare, expr->id()); |
| 9297 } |
| 9298 |
| 9299 |
| 9300 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction( |
| 9301 Token::Value op, |
| 9302 HValue* left, |
| 9303 HValue* right, |
| 9304 Handle<Type> left_type, |
| 9305 Handle<Type> right_type, |
| 9306 Handle<Type> combined_type, |
| 9307 int left_position, |
| 9308 int right_position, |
| 9309 BailoutId bailout_id) { |
| 9240 // Cases handled below depend on collected type feedback. They should | 9310 // Cases handled below depend on collected type feedback. They should |
| 9241 // soft deoptimize when there is no type feedback. | 9311 // soft deoptimize when there is no type feedback. |
| 9242 if (combined_type->Is(Type::None())) { | 9312 if (combined_type->Is(Type::None())) { |
| 9243 Add<HDeoptimize>("Insufficient type feedback for combined type " | 9313 Add<HDeoptimize>("Insufficient type feedback for combined type " |
| 9244 "of binary operation", | 9314 "of binary operation", |
| 9245 Deoptimizer::SOFT); | 9315 Deoptimizer::SOFT); |
| 9246 combined_type = left_type = right_type = handle(Type::Any(), isolate()); | 9316 combined_type = left_type = right_type = handle(Type::Any(), isolate()); |
| 9247 } | 9317 } |
| 9248 | 9318 |
| 9319 Representation left_rep = Representation::FromType(left_type); |
| 9320 Representation right_rep = Representation::FromType(right_type); |
| 9321 Representation combined_rep = Representation::FromType(combined_type); |
| 9322 |
| 9249 if (combined_type->Is(Type::Receiver())) { | 9323 if (combined_type->Is(Type::Receiver())) { |
| 9250 switch (op) { | 9324 if (Token::IsEqualityOp(op)) { |
| 9251 case Token::EQ: | 9325 // Can we get away with map check and not instance type check? |
| 9252 case Token::EQ_STRICT: { | 9326 HValue* operand_to_check = |
| 9253 // Can we get away with map check and not instance type check? | 9327 left->block()->block_id() < right->block()->block_id() ? left : right; |
| 9254 if (combined_type->IsClass()) { | 9328 if (combined_type->IsClass()) { |
| 9255 Handle<Map> map = combined_type->AsClass(); | 9329 Handle<Map> map = combined_type->AsClass(); |
| 9256 AddCheckMap(left, map); | 9330 AddCheckMap(operand_to_check, map); |
| 9257 AddCheckMap(right, map); | 9331 HCompareObjectEqAndBranch* result = |
| 9258 HCompareObjectEqAndBranch* result = | 9332 New<HCompareObjectEqAndBranch>(left, right); |
| 9259 New<HCompareObjectEqAndBranch>(left, right); | 9333 if (FLAG_emit_opt_code_positions) { |
| 9260 if (FLAG_emit_opt_code_positions) { | 9334 result->set_operand_position(zone(), 0, left_position); |
| 9261 result->set_operand_position(zone(), 0, expr->left()->position()); | 9335 result->set_operand_position(zone(), 1, right_position); |
| 9262 result->set_operand_position(zone(), 1, expr->right()->position()); | |
| 9263 } | |
| 9264 return ast_context()->ReturnControl(result, expr->id()); | |
| 9265 } else { | |
| 9266 BuildCheckHeapObject(left); | |
| 9267 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT); | |
| 9268 BuildCheckHeapObject(right); | |
| 9269 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT); | |
| 9270 HCompareObjectEqAndBranch* result = | |
| 9271 New<HCompareObjectEqAndBranch>(left, right); | |
| 9272 return ast_context()->ReturnControl(result, expr->id()); | |
| 9273 } | 9336 } |
| 9337 return result; |
| 9338 } else { |
| 9339 BuildCheckHeapObject(operand_to_check); |
| 9340 Add<HCheckInstanceType>(operand_to_check, |
| 9341 HCheckInstanceType::IS_SPEC_OBJECT); |
| 9342 HCompareObjectEqAndBranch* result = |
| 9343 New<HCompareObjectEqAndBranch>(left, right); |
| 9344 return result; |
| 9274 } | 9345 } |
| 9275 default: | 9346 } else { |
| 9276 return Bailout(kUnsupportedNonPrimitiveCompare); | 9347 Bailout(kUnsupportedNonPrimitiveCompare); |
| 9348 return NULL; |
| 9277 } | 9349 } |
| 9278 } else if (combined_type->Is(Type::InternalizedString()) && | 9350 } else if (combined_type->Is(Type::InternalizedString()) && |
| 9279 Token::IsEqualityOp(op)) { | 9351 Token::IsEqualityOp(op)) { |
| 9280 BuildCheckHeapObject(left); | 9352 BuildCheckHeapObject(left); |
| 9281 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING); | 9353 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING); |
| 9282 BuildCheckHeapObject(right); | 9354 BuildCheckHeapObject(right); |
| 9283 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING); | 9355 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING); |
| 9284 HCompareObjectEqAndBranch* result = | 9356 HCompareObjectEqAndBranch* result = |
| 9285 New<HCompareObjectEqAndBranch>(left, right); | 9357 New<HCompareObjectEqAndBranch>(left, right); |
| 9286 return ast_context()->ReturnControl(result, expr->id()); | 9358 return result; |
| 9287 } else if (combined_type->Is(Type::String())) { | 9359 } else if (combined_type->Is(Type::String())) { |
| 9288 BuildCheckHeapObject(left); | 9360 BuildCheckHeapObject(left); |
| 9289 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING); | 9361 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING); |
| 9290 BuildCheckHeapObject(right); | 9362 BuildCheckHeapObject(right); |
| 9291 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); | 9363 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); |
| 9292 HStringCompareAndBranch* result = | 9364 HStringCompareAndBranch* result = |
| 9293 New<HStringCompareAndBranch>(left, right, op); | 9365 New<HStringCompareAndBranch>(left, right, op); |
| 9294 return ast_context()->ReturnControl(result, expr->id()); | 9366 return result; |
| 9295 } else { | 9367 } else { |
| 9296 if (combined_rep.IsTagged() || combined_rep.IsNone()) { | 9368 if (combined_rep.IsTagged() || combined_rep.IsNone()) { |
| 9297 HCompareGeneric* result = New<HCompareGeneric>(left, right, op); | 9369 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op); |
| 9298 result->set_observed_input_representation(1, left_rep); | 9370 result->set_observed_input_representation(1, left_rep); |
| 9299 result->set_observed_input_representation(2, right_rep); | 9371 result->set_observed_input_representation(2, right_rep); |
| 9300 return ast_context()->ReturnInstruction(result, expr->id()); | 9372 if (result->HasObservableSideEffects()) { |
| 9373 Push(result); |
| 9374 AddSimulate(bailout_id, REMOVABLE_SIMULATE); |
| 9375 Drop(1); |
| 9376 } |
| 9377 // TODO(jkummerow): Can we make this more efficient? |
| 9378 HBranch* branch = New<HBranch>(result); |
| 9379 return branch; |
| 9301 } else { | 9380 } else { |
| 9302 HCompareNumericAndBranch* result = | 9381 HCompareNumericAndBranch* result = |
| 9303 New<HCompareNumericAndBranch>(left, right, op); | 9382 New<HCompareNumericAndBranch>(left, right, op); |
| 9304 result->set_observed_input_representation(left_rep, right_rep); | 9383 result->set_observed_input_representation(left_rep, right_rep); |
| 9305 if (FLAG_emit_opt_code_positions) { | 9384 if (FLAG_emit_opt_code_positions) { |
| 9306 result->SetOperandPositions(zone(), | 9385 result->SetOperandPositions(zone(), left_position, right_position); |
| 9307 expr->left()->position(), | |
| 9308 expr->right()->position()); | |
| 9309 } | 9386 } |
| 9310 return ast_context()->ReturnControl(result, expr->id()); | 9387 return result; |
| 9311 } | 9388 } |
| 9312 } | 9389 } |
| 9313 } | 9390 } |
| 9314 | 9391 |
| 9315 | 9392 |
| 9316 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, | 9393 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, |
| 9317 Expression* sub_expr, | 9394 Expression* sub_expr, |
| 9318 NilValue nil) { | 9395 NilValue nil) { |
| 9319 ASSERT(!HasStackOverflow()); | 9396 ASSERT(!HasStackOverflow()); |
| 9320 ASSERT(current_block() != NULL); | 9397 ASSERT(current_block() != NULL); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9487 | 9564 |
| 9488 if (value->IsJSObject()) { | 9565 if (value->IsJSObject()) { |
| 9489 Handle<JSObject> value_object = Handle<JSObject>::cast(value); | 9566 Handle<JSObject> value_object = Handle<JSObject>::cast(value); |
| 9490 Handle<AllocationSite> current_site = site_context->EnterNewScope(); | 9567 Handle<AllocationSite> current_site = site_context->EnterNewScope(); |
| 9491 HInstruction* result = | 9568 HInstruction* result = |
| 9492 BuildFastLiteral(value_object, site_context); | 9569 BuildFastLiteral(value_object, site_context); |
| 9493 site_context->ExitScope(current_site, value_object); | 9570 site_context->ExitScope(current_site, value_object); |
| 9494 Add<HStoreNamedField>(object, access, result); | 9571 Add<HStoreNamedField>(object, access, result); |
| 9495 } else { | 9572 } else { |
| 9496 Representation representation = details.representation(); | 9573 Representation representation = details.representation(); |
| 9497 HInstruction* value_instruction = Add<HConstant>(value); | 9574 HInstruction* value_instruction; |
| 9498 | 9575 |
| 9499 if (representation.IsDouble()) { | 9576 if (representation.IsDouble()) { |
| 9500 // Allocate a HeapNumber box and store the value into it. | 9577 // Allocate a HeapNumber box and store the value into it. |
| 9501 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize); | 9578 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize); |
| 9502 // This heap number alloc does not have a corresponding | 9579 // This heap number alloc does not have a corresponding |
| 9503 // AllocationSite. That is okay because | 9580 // AllocationSite. That is okay because |
| 9504 // 1) it's a child object of another object with a valid allocation site | 9581 // 1) it's a child object of another object with a valid allocation site |
| 9505 // 2) we can just use the mode of the parent object for pretenuring | 9582 // 2) we can just use the mode of the parent object for pretenuring |
| 9506 HInstruction* double_box = | 9583 HInstruction* double_box = |
| 9507 Add<HAllocate>(heap_number_constant, HType::HeapNumber(), | 9584 Add<HAllocate>(heap_number_constant, HType::HeapNumber(), |
| 9508 pretenure_flag, HEAP_NUMBER_TYPE); | 9585 pretenure_flag, HEAP_NUMBER_TYPE); |
| 9509 AddStoreMapConstant(double_box, | 9586 AddStoreMapConstant(double_box, |
| 9510 isolate()->factory()->heap_number_map()); | 9587 isolate()->factory()->heap_number_map()); |
| 9511 Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(), | 9588 Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(), |
| 9512 value_instruction); | 9589 Add<HConstant>(value)); |
| 9513 value_instruction = double_box; | 9590 value_instruction = double_box; |
| 9591 } else if (representation.IsSmi() && value->IsUninitialized()) { |
| 9592 value_instruction = graph()->GetConstant0(); |
| 9593 } else { |
| 9594 value_instruction = Add<HConstant>(value); |
| 9514 } | 9595 } |
| 9515 | 9596 |
| 9516 Add<HStoreNamedField>(object, access, value_instruction); | 9597 Add<HStoreNamedField>(object, access, value_instruction); |
| 9517 } | 9598 } |
| 9518 } | 9599 } |
| 9519 | 9600 |
| 9520 int inobject_properties = boilerplate_object->map()->inobject_properties(); | 9601 int inobject_properties = boilerplate_object->map()->inobject_properties(); |
| 9521 HInstruction* value_instruction = | 9602 HInstruction* value_instruction = |
| 9522 Add<HConstant>(isolate()->factory()->one_pointer_filler_map()); | 9603 Add<HConstant>(isolate()->factory()->one_pointer_filler_map()); |
| 9523 for (int i = copied_fields; i < inobject_properties; i++) { | 9604 for (int i = copied_fields; i < inobject_properties; i++) { |
| (...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10040 } | 10121 } |
| 10041 | 10122 |
| 10042 | 10123 |
| 10043 // Fast support for StringAdd. | 10124 // Fast support for StringAdd. |
| 10044 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) { | 10125 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) { |
| 10045 ASSERT_EQ(2, call->arguments()->length()); | 10126 ASSERT_EQ(2, call->arguments()->length()); |
| 10046 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10127 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10047 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10128 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10048 HValue* right = Pop(); | 10129 HValue* right = Pop(); |
| 10049 HValue* left = Pop(); | 10130 HValue* left = Pop(); |
| 10050 HInstruction* result = | 10131 HInstruction* result = NewUncasted<HStringAdd>(left, right); |
| 10051 NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_BOTH); | |
| 10052 return ast_context()->ReturnInstruction(result, call->id()); | 10132 return ast_context()->ReturnInstruction(result, call->id()); |
| 10053 } | 10133 } |
| 10054 | 10134 |
| 10055 | 10135 |
| 10056 // Fast support for SubString. | 10136 // Fast support for SubString. |
| 10057 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) { | 10137 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) { |
| 10058 ASSERT_EQ(3, call->arguments()->length()); | 10138 ASSERT_EQ(3, call->arguments()->length()); |
| 10059 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 10139 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 10060 HCallStub* result = New<HCallStub>(CodeStub::SubString, 3); | 10140 HCallStub* result = New<HCallStub>(CodeStub::SubString, 3); |
| 10061 Drop(3); | 10141 Drop(3); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10157 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10237 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10158 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10238 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10159 HValue* right = Pop(); | 10239 HValue* right = Pop(); |
| 10160 HValue* left = Pop(); | 10240 HValue* left = Pop(); |
| 10161 HInstruction* result = NewUncasted<HPower>(left, right); | 10241 HInstruction* result = NewUncasted<HPower>(left, right); |
| 10162 return ast_context()->ReturnInstruction(result, call->id()); | 10242 return ast_context()->ReturnInstruction(result, call->id()); |
| 10163 } | 10243 } |
| 10164 | 10244 |
| 10165 | 10245 |
| 10166 void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) { | 10246 void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) { |
| 10167 ASSERT_EQ(1, call->arguments()->length()); | 10247 ASSERT(call->arguments()->length() == 1); |
| 10168 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 10248 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10169 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); | 10249 HValue* value = Pop(); |
| 10170 result->set_transcendental_type(TranscendentalCache::LOG); | 10250 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathLog); |
| 10171 Drop(1); | |
| 10172 return ast_context()->ReturnInstruction(result, call->id()); | 10251 return ast_context()->ReturnInstruction(result, call->id()); |
| 10173 } | 10252 } |
| 10174 | 10253 |
| 10175 | 10254 |
| 10176 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) { | 10255 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) { |
| 10177 ASSERT(call->arguments()->length() == 1); | 10256 ASSERT(call->arguments()->length() == 1); |
| 10178 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10257 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10179 HValue* value = Pop(); | 10258 HValue* value = Pop(); |
| 10180 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); | 10259 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); |
| 10181 return ast_context()->ReturnInstruction(result, call->id()); | 10260 return ast_context()->ReturnInstruction(result, call->id()); |
| (...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10511 stream->Add("\n"); | 10590 stream->Add("\n"); |
| 10512 } | 10591 } |
| 10513 PrintF("\n"); | 10592 PrintF("\n"); |
| 10514 } | 10593 } |
| 10515 | 10594 |
| 10516 | 10595 |
| 10517 void HEnvironment::PrintToStd() { | 10596 void HEnvironment::PrintToStd() { |
| 10518 HeapStringAllocator string_allocator; | 10597 HeapStringAllocator string_allocator; |
| 10519 StringStream trace(&string_allocator); | 10598 StringStream trace(&string_allocator); |
| 10520 PrintTo(&trace); | 10599 PrintTo(&trace); |
| 10521 PrintF("%s", *trace.ToCString()); | 10600 PrintF("%s", trace.ToCString().get()); |
| 10522 } | 10601 } |
| 10523 | 10602 |
| 10524 | 10603 |
| 10525 void HTracer::TraceCompilation(CompilationInfo* info) { | 10604 void HTracer::TraceCompilation(CompilationInfo* info) { |
| 10526 Tag tag(this, "compilation"); | 10605 Tag tag(this, "compilation"); |
| 10527 if (info->IsOptimizing()) { | 10606 if (info->IsOptimizing()) { |
| 10528 Handle<String> name = info->function()->debug_name(); | 10607 Handle<String> name = info->function()->debug_name(); |
| 10529 PrintStringProperty("name", *name->ToCString()); | 10608 PrintStringProperty("name", name->ToCString().get()); |
| 10530 PrintStringProperty("method", *name->ToCString()); | 10609 PrintStringProperty("method", name->ToCString().get()); |
| 10531 } else { | 10610 } else { |
| 10532 CodeStub::Major major_key = info->code_stub()->MajorKey(); | 10611 CodeStub::Major major_key = info->code_stub()->MajorKey(); |
| 10533 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); | 10612 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); |
| 10534 PrintStringProperty("method", "stub"); | 10613 PrintStringProperty("method", "stub"); |
| 10535 } | 10614 } |
| 10536 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); | 10615 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); |
| 10537 } | 10616 } |
| 10538 | 10617 |
| 10539 | 10618 |
| 10540 void HTracer::TraceLithium(const char* name, LChunk* chunk) { | 10619 void HTracer::TraceLithium(const char* name, LChunk* chunk) { |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10740 } | 10819 } |
| 10741 current_pos = current_pos->next(); | 10820 current_pos = current_pos->next(); |
| 10742 } | 10821 } |
| 10743 | 10822 |
| 10744 trace_.Add(" \"\"\n"); | 10823 trace_.Add(" \"\"\n"); |
| 10745 } | 10824 } |
| 10746 } | 10825 } |
| 10747 | 10826 |
| 10748 | 10827 |
| 10749 void HTracer::FlushToFile() { | 10828 void HTracer::FlushToFile() { |
| 10750 AppendChars(filename_.start(), *trace_.ToCString(), trace_.length(), false); | 10829 AppendChars(filename_.start(), trace_.ToCString().get(), trace_.length(), |
| 10830 false); |
| 10751 trace_.Reset(); | 10831 trace_.Reset(); |
| 10752 } | 10832 } |
| 10753 | 10833 |
| 10754 | 10834 |
| 10755 void HStatistics::Initialize(CompilationInfo* info) { | 10835 void HStatistics::Initialize(CompilationInfo* info) { |
| 10756 if (info->shared_info().is_null()) return; | 10836 if (info->shared_info().is_null()) return; |
| 10757 source_size_ += info->shared_info()->SourceSize(); | 10837 source_size_ += info->shared_info()->SourceSize(); |
| 10758 } | 10838 } |
| 10759 | 10839 |
| 10760 | 10840 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10830 if (ShouldProduceTraceOutput()) { | 10910 if (ShouldProduceTraceOutput()) { |
| 10831 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10911 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 10832 } | 10912 } |
| 10833 | 10913 |
| 10834 #ifdef DEBUG | 10914 #ifdef DEBUG |
| 10835 graph_->Verify(false); // No full verify. | 10915 graph_->Verify(false); // No full verify. |
| 10836 #endif | 10916 #endif |
| 10837 } | 10917 } |
| 10838 | 10918 |
| 10839 } } // namespace v8::internal | 10919 } } // namespace v8::internal |
| OLD | NEW |