| OLD | NEW |
| 1 // Copyright 2017 the V8 project authors. All rights reserved. | 1 // Copyright 2017 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/builtins/builtins-utils-gen.h" | 5 #include "src/builtins/builtins-utils-gen.h" |
| 6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
| 7 #include "src/code-stub-assembler.h" | 7 #include "src/code-stub-assembler.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| (...skipping 1661 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1672 const int kSearchElementArg = 0; | 1672 const int kSearchElementArg = 0; |
| 1673 const int kFromIndexArg = 1; | 1673 const int kFromIndexArg = 1; |
| 1674 | 1674 |
| 1675 Node* argc = | 1675 Node* argc = |
| 1676 ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount)); | 1676 ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount)); |
| 1677 CodeStubArguments args(this, argc); | 1677 CodeStubArguments args(this, argc); |
| 1678 | 1678 |
| 1679 Node* array = args.GetReceiver(); | 1679 Node* array = args.GetReceiver(); |
| 1680 Node* search_element = | 1680 Node* search_element = |
| 1681 args.GetOptionalArgumentValue(kSearchElementArg, UndefinedConstant()); | 1681 args.GetOptionalArgumentValue(kSearchElementArg, UndefinedConstant()); |
| 1682 Node* start_from = | |
| 1683 args.GetOptionalArgumentValue(kFromIndexArg, UndefinedConstant()); | |
| 1684 Node* context = Parameter(BuiltinDescriptor::kContext); | 1682 Node* context = Parameter(BuiltinDescriptor::kContext); |
| 1685 | 1683 |
| 1686 Node* intptr_zero = IntPtrConstant(0); | 1684 Node* intptr_zero = IntPtrConstant(0); |
| 1687 Node* intptr_one = IntPtrConstant(1); | 1685 Node* intptr_one = IntPtrConstant(1); |
| 1688 | 1686 |
| 1689 VARIABLE(len_var, MachineType::PointerRepresentation()); | 1687 Label init_index(this), return_found(this), return_not_found(this), |
| 1690 VARIABLE(index_var, MachineType::PointerRepresentation()); | |
| 1691 VARIABLE(start_from_var, MachineType::PointerRepresentation()); | |
| 1692 | |
| 1693 Label init_k(this), return_found(this), return_not_found(this), | |
| 1694 call_runtime(this); | 1688 call_runtime(this); |
| 1695 | 1689 |
| 1696 Label init_len(this); | |
| 1697 | |
| 1698 index_var.Bind(intptr_zero); | |
| 1699 len_var.Bind(intptr_zero); | |
| 1700 | |
| 1701 // Take slow path if not a JSArray, if retrieving elements requires | 1690 // Take slow path if not a JSArray, if retrieving elements requires |
| 1702 // traversing prototype, or if access checks are required. | 1691 // traversing prototype, or if access checks are required. |
| 1703 BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ, | 1692 BranchIfFastJSArray(array, context, FastJSArrayAccessMode::INBOUNDS_READ, |
| 1704 &init_len, &call_runtime); | 1693 &init_index, &call_runtime); |
| 1705 | 1694 |
| 1706 BIND(&init_len); | 1695 BIND(&init_index); |
| 1707 { | 1696 VARIABLE(index_var, MachineType::PointerRepresentation(), intptr_zero); |
| 1708 // JSArray length is always an Smi for fast arrays. | |
| 1709 CSA_ASSERT(this, | |
| 1710 TaggedIsSmi(LoadObjectField(array, JSArray::kLengthOffset))); | |
| 1711 Node* len = LoadAndUntagObjectField(array, JSArray::kLengthOffset); | |
| 1712 | 1697 |
| 1713 len_var.Bind(len); | 1698 // JSArray length is always a positive Smi for fast arrays. |
| 1714 Branch(WordEqual(len_var.value(), intptr_zero), &return_not_found, &init_k); | 1699 CSA_ASSERT(this, TaggedIsPositiveSmi(LoadJSArrayLength(array))); |
| 1715 } | 1700 Node* array_length = SmiUntag(LoadJSArrayLength(array)); |
| 1716 | 1701 |
| 1717 BIND(&init_k); | |
| 1718 { | 1702 { |
| 1719 // For now only deal with undefined and Smis here; we must be really careful | 1703 // For now only deal with undefined and Smis here; we must be really careful |
| 1720 // with side-effects from the ToInteger conversion as the side-effects might | 1704 // with side-effects from the ToInteger conversion as the side-effects might |
| 1721 // render our assumptions about the receiver being a fast JSArray and the | 1705 // render our assumptions about the receiver being a fast JSArray and the |
| 1722 // length invalid. | 1706 // length invalid. |
| 1723 Label done(this), init_k_smi(this), init_k_other(this), init_k_zero(this), | 1707 Label done(this); |
| 1724 init_k_n(this); | |
| 1725 Branch(TaggedIsSmi(start_from), &init_k_smi, &init_k_other); | |
| 1726 | 1708 |
| 1727 BIND(&init_k_smi); | 1709 // If no fromIndex was passed, default to 0. |
| 1710 GotoIf(IntPtrLessThanOrEqual(argc, IntPtrConstant(kFromIndexArg)), &done); |
| 1711 |
| 1712 // Handle Smis here and everything else in runtime. |
| 1713 Node* start_from = args.AtIndex(kFromIndexArg); |
| 1714 GotoIfNot(TaggedIsSmi(start_from), &call_runtime); |
| 1715 |
| 1716 Node* intptr_start_from = SmiUntag(start_from); |
| 1717 index_var.Bind(intptr_start_from); |
| 1718 |
| 1719 Label if_negative(this); |
| 1720 Branch(IntPtrLessThan(intptr_start_from, intptr_zero), &if_negative, &done); |
| 1721 |
| 1722 BIND(&if_negative); |
| 1728 { | 1723 { |
| 1729 // The fromIndex is a Smi. | 1724 Node* len_minus_start_from = IntPtrAdd(array_length, intptr_start_from); |
| 1730 start_from_var.Bind(SmiUntag(start_from)); | 1725 index_var.Bind(IntPtrMax(len_minus_start_from, intptr_zero)); |
| 1731 Goto(&init_k_n); | 1726 Goto(&done); |
| 1732 } | 1727 } |
| 1733 | 1728 |
| 1734 BIND(&init_k_other); | 1729 BIND(&done); |
| 1735 { | 1730 } |
| 1736 // The fromIndex must be undefined then, otherwise bailout and let the | |
| 1737 // runtime deal with the full ToInteger conversion. | |
| 1738 GotoIfNot(IsUndefined(start_from), &call_runtime); | |
| 1739 start_from_var.Bind(intptr_zero); | |
| 1740 Goto(&init_k_n); | |
| 1741 } | |
| 1742 | 1731 |
| 1743 BIND(&init_k_n); | 1732 // Fail early if startIndex >= array.length. |
| 1744 { | 1733 GotoIf(IntPtrGreaterThanOrEqual(index_var.value(), array_length), |
| 1745 Label if_positive(this), if_negative(this), done(this); | 1734 &return_not_found); |
| 1746 Branch(IntPtrLessThan(start_from_var.value(), intptr_zero), &if_negative, | |
| 1747 &if_positive); | |
| 1748 | |
| 1749 BIND(&if_positive); | |
| 1750 { | |
| 1751 index_var.Bind(start_from_var.value()); | |
| 1752 Goto(&done); | |
| 1753 } | |
| 1754 | |
| 1755 BIND(&if_negative); | |
| 1756 { | |
| 1757 index_var.Bind(IntPtrAdd(len_var.value(), start_from_var.value())); | |
| 1758 Branch(IntPtrLessThan(index_var.value(), intptr_zero), &init_k_zero, | |
| 1759 &done); | |
| 1760 } | |
| 1761 | |
| 1762 BIND(&init_k_zero); | |
| 1763 { | |
| 1764 index_var.Bind(intptr_zero); | |
| 1765 Goto(&done); | |
| 1766 } | |
| 1767 | |
| 1768 BIND(&done); | |
| 1769 } | |
| 1770 } | |
| 1771 | 1735 |
| 1772 static int32_t kElementsKind[] = { | 1736 static int32_t kElementsKind[] = { |
| 1773 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, | 1737 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, |
| 1774 FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, | 1738 FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, |
| 1775 }; | 1739 }; |
| 1776 | 1740 |
| 1777 Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this); | 1741 Label if_smiorobjects(this), if_packed_doubles(this), if_holey_doubles(this); |
| 1778 Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, | 1742 Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, |
| 1779 &if_smiorobjects, &if_smiorobjects, | 1743 &if_smiorobjects, &if_smiorobjects, |
| 1780 &if_packed_doubles, &if_holey_doubles}; | 1744 &if_packed_doubles, &if_holey_doubles}; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1801 search_num.Bind(LoadHeapNumberValue(search_element)); | 1765 search_num.Bind(LoadHeapNumberValue(search_element)); |
| 1802 Goto(&heap_num_loop); | 1766 Goto(&heap_num_loop); |
| 1803 | 1767 |
| 1804 BIND(¬_heap_num); | 1768 BIND(¬_heap_num); |
| 1805 Node* search_type = LoadMapInstanceType(map); | 1769 Node* search_type = LoadMapInstanceType(map); |
| 1806 GotoIf(IsStringInstanceType(search_type), &string_loop); | 1770 GotoIf(IsStringInstanceType(search_type), &string_loop); |
| 1807 Goto(&ident_loop); | 1771 Goto(&ident_loop); |
| 1808 | 1772 |
| 1809 BIND(&ident_loop); | 1773 BIND(&ident_loop); |
| 1810 { | 1774 { |
| 1811 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), | 1775 GotoIfNot(UintPtrLessThan(index_var.value(), array_length), |
| 1812 &return_not_found); | 1776 &return_not_found); |
| 1813 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | 1777 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
| 1814 GotoIf(WordEqual(element_k, search_element), &return_found); | 1778 GotoIf(WordEqual(element_k, search_element), &return_found); |
| 1815 | 1779 |
| 1816 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); | 1780 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); |
| 1817 Goto(&ident_loop); | 1781 Goto(&ident_loop); |
| 1818 } | 1782 } |
| 1819 | 1783 |
| 1820 BIND(&heap_num_loop); | 1784 BIND(&heap_num_loop); |
| 1821 { | 1785 { |
| 1822 Label not_nan_loop(this, &index_var); | 1786 Label not_nan_loop(this, &index_var); |
| 1823 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, | 1787 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, |
| 1824 ¬_nan_loop); | 1788 ¬_nan_loop); |
| 1825 | 1789 |
| 1826 BIND(¬_nan_loop); | 1790 BIND(¬_nan_loop); |
| 1827 { | 1791 { |
| 1828 Label continue_loop(this), not_smi(this); | 1792 Label continue_loop(this), not_smi(this); |
| 1829 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), | 1793 GotoIfNot(UintPtrLessThan(index_var.value(), array_length), |
| 1830 &return_not_found); | 1794 &return_not_found); |
| 1831 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | 1795 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
| 1832 GotoIfNot(TaggedIsSmi(element_k), ¬_smi); | 1796 GotoIfNot(TaggedIsSmi(element_k), ¬_smi); |
| 1833 Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)), | 1797 Branch(Float64Equal(search_num.value(), SmiToFloat64(element_k)), |
| 1834 &return_found, &continue_loop); | 1798 &return_found, &continue_loop); |
| 1835 | 1799 |
| 1836 BIND(¬_smi); | 1800 BIND(¬_smi); |
| 1837 GotoIfNot(IsHeapNumber(element_k), &continue_loop); | 1801 GotoIfNot(IsHeapNumber(element_k), &continue_loop); |
| 1838 Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)), | 1802 Branch(Float64Equal(search_num.value(), LoadHeapNumberValue(element_k)), |
| 1839 &return_found, &continue_loop); | 1803 &return_found, &continue_loop); |
| 1840 | 1804 |
| 1841 BIND(&continue_loop); | 1805 BIND(&continue_loop); |
| 1842 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); | 1806 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); |
| 1843 Goto(¬_nan_loop); | 1807 Goto(¬_nan_loop); |
| 1844 } | 1808 } |
| 1845 } | 1809 } |
| 1846 | 1810 |
| 1847 BIND(&string_loop); | 1811 BIND(&string_loop); |
| 1848 { | 1812 { |
| 1813 CSA_ASSERT(this, IsString(search_element)); |
| 1849 Label continue_loop(this); | 1814 Label continue_loop(this); |
| 1850 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), | 1815 GotoIfNot(UintPtrLessThan(index_var.value(), array_length), |
| 1851 &return_not_found); | 1816 &return_not_found); |
| 1852 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); | 1817 Node* element_k = LoadFixedArrayElement(elements, index_var.value()); |
| 1853 GotoIf(TaggedIsSmi(element_k), &continue_loop); | 1818 GotoIf(TaggedIsSmi(element_k), &continue_loop); |
| 1854 GotoIfNot(IsString(element_k), &continue_loop); | 1819 GotoIfNot(IsString(element_k), &continue_loop); |
| 1855 | 1820 |
| 1856 // TODO(bmeurer): Consider inlining the StringEqual logic here. | 1821 // TODO(bmeurer): Consider inlining the StringEqual logic here. |
| 1857 Callable callable = CodeFactory::StringEqual(isolate()); | 1822 Callable callable = CodeFactory::StringEqual(isolate()); |
| 1858 Node* result = CallStub(callable, context, search_element, element_k); | 1823 Node* result = CallStub(callable, context, search_element, element_k); |
| 1859 Branch(WordEqual(BooleanConstant(true), result), &return_found, | 1824 Branch(WordEqual(BooleanConstant(true), result), &return_found, |
| 1860 &continue_loop); | 1825 &continue_loop); |
| 1861 | 1826 |
| 1862 BIND(&continue_loop); | 1827 BIND(&continue_loop); |
| 1863 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); | 1828 Increment(index_var); |
| 1864 Goto(&string_loop); | 1829 Goto(&string_loop); |
| 1865 } | 1830 } |
| 1866 } | 1831 } |
| 1867 | 1832 |
| 1868 BIND(&if_packed_doubles); | 1833 BIND(&if_packed_doubles); |
| 1869 { | 1834 { |
| 1870 Label not_nan_loop(this, &index_var), search_notnan(this); | 1835 Label not_nan_loop(this, &index_var), search_notnan(this); |
| 1871 VARIABLE(search_num, MachineRepresentation::kFloat64); | 1836 VARIABLE(search_num, MachineRepresentation::kFloat64); |
| 1872 | 1837 |
| 1873 GotoIfNot(TaggedIsSmi(search_element), &search_notnan); | 1838 GotoIfNot(TaggedIsSmi(search_element), &search_notnan); |
| 1874 search_num.Bind(SmiToFloat64(search_element)); | 1839 search_num.Bind(SmiToFloat64(search_element)); |
| 1875 Goto(¬_nan_loop); | 1840 Goto(¬_nan_loop); |
| 1876 | 1841 |
| 1877 BIND(&search_notnan); | 1842 BIND(&search_notnan); |
| 1878 GotoIfNot(IsHeapNumber(search_element), &return_not_found); | 1843 GotoIfNot(IsHeapNumber(search_element), &return_not_found); |
| 1879 | 1844 |
| 1880 search_num.Bind(LoadHeapNumberValue(search_element)); | 1845 search_num.Bind(LoadHeapNumberValue(search_element)); |
| 1881 | 1846 |
| 1882 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, ¬_nan_loop); | 1847 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, ¬_nan_loop); |
| 1883 | 1848 |
| 1884 // Search for HeapNumber | 1849 // Search for HeapNumber |
| 1885 BIND(¬_nan_loop); | 1850 BIND(¬_nan_loop); |
| 1886 { | 1851 { |
| 1887 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), | 1852 GotoIfNot(UintPtrLessThan(index_var.value(), array_length), |
| 1888 &return_not_found); | 1853 &return_not_found); |
| 1889 Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(), | 1854 Node* element_k = LoadFixedDoubleArrayElement(elements, index_var.value(), |
| 1890 MachineType::Float64()); | 1855 MachineType::Float64()); |
| 1891 GotoIf(Float64Equal(element_k, search_num.value()), &return_found); | 1856 GotoIf(Float64Equal(element_k, search_num.value()), &return_found); |
| 1892 | 1857 |
| 1893 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); | 1858 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); |
| 1894 Goto(¬_nan_loop); | 1859 Goto(¬_nan_loop); |
| 1895 } | 1860 } |
| 1896 } | 1861 } |
| 1897 | 1862 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1908 GotoIfNot(IsHeapNumber(search_element), &return_not_found); | 1873 GotoIfNot(IsHeapNumber(search_element), &return_not_found); |
| 1909 | 1874 |
| 1910 search_num.Bind(LoadHeapNumberValue(search_element)); | 1875 search_num.Bind(LoadHeapNumberValue(search_element)); |
| 1911 | 1876 |
| 1912 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, ¬_nan_loop); | 1877 BranchIfFloat64IsNaN(search_num.value(), &return_not_found, ¬_nan_loop); |
| 1913 | 1878 |
| 1914 // Search for HeapNumber | 1879 // Search for HeapNumber |
| 1915 BIND(¬_nan_loop); | 1880 BIND(¬_nan_loop); |
| 1916 { | 1881 { |
| 1917 Label continue_loop(this); | 1882 Label continue_loop(this); |
| 1918 GotoIfNot(UintPtrLessThan(index_var.value(), len_var.value()), | 1883 GotoIfNot(UintPtrLessThan(index_var.value(), array_length), |
| 1919 &return_not_found); | 1884 &return_not_found); |
| 1920 | 1885 |
| 1921 // Load double value or continue if it contains a double hole. | 1886 // Load double value or continue if it contains a double hole. |
| 1922 Node* element_k = LoadFixedDoubleArrayElement( | 1887 Node* element_k = LoadFixedDoubleArrayElement( |
| 1923 elements, index_var.value(), MachineType::Float64(), 0, | 1888 elements, index_var.value(), MachineType::Float64(), 0, |
| 1924 INTPTR_PARAMETERS, &continue_loop); | 1889 INTPTR_PARAMETERS, &continue_loop); |
| 1925 | 1890 |
| 1926 Branch(Float64Equal(element_k, search_num.value()), &return_found, | 1891 Branch(Float64Equal(element_k, search_num.value()), &return_found, |
| 1927 &continue_loop); | 1892 &continue_loop); |
| 1928 BIND(&continue_loop); | 1893 BIND(&continue_loop); |
| 1929 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); | 1894 index_var.Bind(IntPtrAdd(index_var.value(), intptr_one)); |
| 1930 Goto(¬_nan_loop); | 1895 Goto(¬_nan_loop); |
| 1931 } | 1896 } |
| 1932 } | 1897 } |
| 1933 | 1898 |
| 1934 BIND(&return_found); | 1899 BIND(&return_found); |
| 1935 args.PopAndReturn(SmiTag(index_var.value())); | 1900 args.PopAndReturn(SmiTag(index_var.value())); |
| 1936 | 1901 |
| 1937 BIND(&return_not_found); | 1902 BIND(&return_not_found); |
| 1938 args.PopAndReturn(NumberConstant(-1)); | 1903 args.PopAndReturn(NumberConstant(-1)); |
| 1939 | 1904 |
| 1940 BIND(&call_runtime); | 1905 BIND(&call_runtime); |
| 1941 args.PopAndReturn(CallRuntime(Runtime::kArrayIndexOf, context, array, | 1906 { |
| 1942 search_element, start_from)); | 1907 Node* start_from = |
| 1908 args.GetOptionalArgumentValue(kFromIndexArg, UndefinedConstant()); |
| 1909 args.PopAndReturn(CallRuntime(Runtime::kArrayIndexOf, context, array, |
| 1910 search_element, start_from)); |
| 1911 } |
| 1943 } | 1912 } |
| 1944 | 1913 |
| 1945 class ArrayPrototypeIterationAssembler : public CodeStubAssembler { | 1914 class ArrayPrototypeIterationAssembler : public CodeStubAssembler { |
| 1946 public: | 1915 public: |
| 1947 explicit ArrayPrototypeIterationAssembler(compiler::CodeAssemblerState* state) | 1916 explicit ArrayPrototypeIterationAssembler(compiler::CodeAssemblerState* state) |
| 1948 : CodeStubAssembler(state) {} | 1917 : CodeStubAssembler(state) {} |
| 1949 | 1918 |
| 1950 protected: | 1919 protected: |
| 1951 void Generate_ArrayPrototypeIterationMethod(Node* context, Node* receiver, | 1920 void Generate_ArrayPrototypeIterationMethod(Node* context, Node* receiver, |
| 1952 IterationKind iteration_kind) { | 1921 IterationKind iteration_kind) { |
| (...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2416 { | 2385 { |
| 2417 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); | 2386 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); |
| 2418 CallRuntime(Runtime::kThrowTypeError, context, message, | 2387 CallRuntime(Runtime::kThrowTypeError, context, message, |
| 2419 HeapConstant(operation)); | 2388 HeapConstant(operation)); |
| 2420 Unreachable(); | 2389 Unreachable(); |
| 2421 } | 2390 } |
| 2422 } | 2391 } |
| 2423 | 2392 |
| 2424 } // namespace internal | 2393 } // namespace internal |
| 2425 } // namespace v8 | 2394 } // namespace v8 |
| OLD | NEW |