OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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 <limits> | 5 #include <limits> |
6 | 6 |
7 #include "src/compiler/access-builder.h" | 7 #include "src/compiler/access-builder.h" |
8 #include "src/compiler/change-lowering.h" | 8 #include "src/compiler/change-lowering.h" |
9 #include "src/compiler/control-builders.h" | 9 #include "src/compiler/control-builders.h" |
10 #include "src/compiler/generic-node-inl.h" | 10 #include "src/compiler/generic-node-inl.h" |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 CompilationInfo info(zone->isolate(), zone); | 62 CompilationInfo info(zone->isolate(), zone); |
63 Linkage linkage( | 63 Linkage linkage( |
64 &info, Linkage::GetSimplifiedCDescriptor(zone, this->machine_sig_)); | 64 &info, Linkage::GetSimplifiedCDescriptor(zone, this->machine_sig_)); |
65 ChangeLowering lowering(&jsgraph, &linkage); | 65 ChangeLowering lowering(&jsgraph, &linkage); |
66 GraphReducer reducer(this->graph()); | 66 GraphReducer reducer(this->graph()); |
67 reducer.AddReducer(&lowering); | 67 reducer.AddReducer(&lowering); |
68 reducer.ReduceGraph(); | 68 reducer.ReduceGraph(); |
69 Verifier::Run(this->graph()); | 69 Verifier::Run(this->graph()); |
70 } | 70 } |
71 | 71 |
| 72 void CheckNumberCall(double expected, double input) { |
| 73 // TODO(titzer): make calls to NewNumber work in cctests. |
| 74 if (expected <= Smi::kMinValue) return; |
| 75 if (expected >= Smi::kMaxValue) return; |
| 76 Handle<Object> num = factory()->NewNumber(input); |
| 77 Object* result = this->Call(*num); |
| 78 CHECK(factory()->NewNumber(expected)->SameValue(result)); |
| 79 } |
| 80 |
72 Factory* factory() { return this->isolate()->factory(); } | 81 Factory* factory() { return this->isolate()->factory(); } |
73 Heap* heap() { return this->isolate()->heap(); } | 82 Heap* heap() { return this->isolate()->heap(); } |
74 }; | 83 }; |
75 | 84 |
76 | 85 |
77 // TODO(titzer): factor these tests out to test-run-simplifiedops.cc. | 86 // TODO(titzer): factor these tests out to test-run-simplifiedops.cc. |
78 // TODO(titzer): test tagged representation for input to NumberToInt32. | 87 // TODO(titzer): test tagged representation for input to NumberToInt32. |
79 TEST(RunNumberToInt32_float64) { | 88 TEST(RunNumberToInt32_float64) { |
80 // TODO(titzer): explicit load/stores here are only because of representations | 89 // TODO(titzer): explicit load/stores here are only because of representations |
81 double input; | 90 double input; |
(...skipping 1475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1557 Node* num = t.NumberToInt32(t.Parameter(0)); | 1566 Node* num = t.NumberToInt32(t.Parameter(0)); |
1558 Node* div = t.NumberDivide(num, t.jsgraph.Constant(-1)); | 1567 Node* div = t.NumberDivide(num, t.jsgraph.Constant(-1)); |
1559 Node* trunc = t.NumberToInt32(div); | 1568 Node* trunc = t.NumberToInt32(div); |
1560 t.Return(trunc); | 1569 t.Return(trunc); |
1561 | 1570 |
1562 if (Pipeline::SupportedTarget()) { | 1571 if (Pipeline::SupportedTarget()) { |
1563 t.LowerAllNodesAndLowerChanges(); | 1572 t.LowerAllNodesAndLowerChanges(); |
1564 t.GenerateCode(); | 1573 t.GenerateCode(); |
1565 | 1574 |
1566 FOR_INT32_INPUTS(i) { | 1575 FOR_INT32_INPUTS(i) { |
1567 Handle<HeapNumber> num = t.factory()->NewHeapNumber(*i); | |
1568 int32_t x = 0 - *i; | 1576 int32_t x = 0 - *i; |
1569 // TODO(titzer): make calls to NewHeapNumber work in cctests. | 1577 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); |
1570 if (x <= Smi::kMinValue) continue; | |
1571 if (x >= Smi::kMaxValue) continue; | |
1572 Handle<HeapNumber> expected = t.factory()->NewHeapNumber(x); | |
1573 Object* result = t.Call(*num); | |
1574 CHECK(expected->SameValue(result)); | |
1575 } | 1578 } |
1576 } | 1579 } |
1577 } | 1580 } |
| 1581 |
| 1582 |
| 1583 TEST(NumberMultiply_TruncatingToInt32) { |
| 1584 int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000}; |
| 1585 |
| 1586 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1587 TestingGraph t(Type::Signed32()); |
| 1588 Node* k = t.jsgraph.Constant(constants[i]); |
| 1589 Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k); |
| 1590 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul); |
| 1591 t.Return(trunc); |
| 1592 t.Lower(); |
| 1593 |
| 1594 CHECK_EQ(IrOpcode::kInt32Mul, mul->opcode()); |
| 1595 } |
| 1596 } |
| 1597 |
| 1598 |
| 1599 TEST(RunNumberMultiply_TruncatingToInt32) { |
| 1600 int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999}; |
| 1601 |
| 1602 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1603 double k = static_cast<double>(constants[i]); |
| 1604 SimplifiedLoweringTester<Object*> t(kMachAnyTagged); |
| 1605 Node* num = t.NumberToInt32(t.Parameter(0)); |
| 1606 Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k)); |
| 1607 Node* trunc = t.NumberToInt32(mul); |
| 1608 t.Return(trunc); |
| 1609 |
| 1610 if (Pipeline::SupportedTarget()) { |
| 1611 t.LowerAllNodesAndLowerChanges(); |
| 1612 t.GenerateCode(); |
| 1613 |
| 1614 FOR_INT32_INPUTS(i) { |
| 1615 int32_t x = DoubleToInt32(static_cast<double>(*i) * k); |
| 1616 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); |
| 1617 } |
| 1618 } |
| 1619 } |
| 1620 } |
| 1621 |
| 1622 |
| 1623 TEST(RunNumberMultiply_TruncatingToUint32) { |
| 1624 uint32_t constants[] = {0, 1, 2, 3, 4, 100, 1000, 1024, 2048, 3000999}; |
| 1625 |
| 1626 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1627 double k = static_cast<double>(constants[i]); |
| 1628 SimplifiedLoweringTester<Object*> t(kMachAnyTagged); |
| 1629 Node* num = t.NumberToUint32(t.Parameter(0)); |
| 1630 Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k)); |
| 1631 Node* trunc = t.NumberToUint32(mul); |
| 1632 t.Return(trunc); |
| 1633 |
| 1634 if (Pipeline::SupportedTarget()) { |
| 1635 t.LowerAllNodesAndLowerChanges(); |
| 1636 t.GenerateCode(); |
| 1637 |
| 1638 FOR_UINT32_INPUTS(i) { |
| 1639 uint32_t x = DoubleToUint32(static_cast<double>(*i) * k); |
| 1640 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); |
| 1641 } |
| 1642 } |
| 1643 } |
| 1644 } |
1578 | 1645 |
1579 | 1646 |
1580 TEST(RunNumberDivide_2_TruncatingToUint32) { | 1647 TEST(RunNumberDivide_2_TruncatingToUint32) { |
1581 SimplifiedLoweringTester<Object*> t(kMachAnyTagged); | 1648 SimplifiedLoweringTester<Object*> t(kMachAnyTagged); |
1582 Node* num = t.NumberToUint32(t.Parameter(0)); | 1649 Node* num = t.NumberToUint32(t.Parameter(0)); |
1583 Node* div = t.NumberDivide(num, t.jsgraph.Constant(2)); | 1650 Node* div = t.NumberDivide(num, t.jsgraph.Constant(2)); |
1584 Node* trunc = t.NumberToUint32(div); | 1651 Node* trunc = t.NumberToUint32(div); |
1585 t.Return(trunc); | 1652 t.Return(trunc); |
1586 | 1653 |
1587 if (Pipeline::SupportedTarget()) { | 1654 if (Pipeline::SupportedTarget()) { |
1588 t.LowerAllNodesAndLowerChanges(); | 1655 t.LowerAllNodesAndLowerChanges(); |
1589 { | |
1590 FILE* dot_file = fopen("/tmp/test.dot", "w+"); | |
1591 OFStream dot_of(dot_file); | |
1592 dot_of << AsDOT(*t.jsgraph.graph()); | |
1593 fclose(dot_file); | |
1594 } | |
1595 t.GenerateCode(); | 1656 t.GenerateCode(); |
1596 | 1657 |
1597 FOR_UINT32_INPUTS(i) { | 1658 FOR_UINT32_INPUTS(i) { |
1598 Handle<HeapNumber> num = | 1659 uint32_t x = DoubleToUint32(static_cast<double>(*i / 2.0)); |
1599 t.factory()->NewHeapNumber(static_cast<double>(*i)); | 1660 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); |
1600 uint32_t x = *i / 2; | 1661 } |
1601 // TODO(titzer): make calls to NewHeapNumber work in cctests. | 1662 } |
1602 if (x >= static_cast<uint32_t>(Smi::kMaxValue)) continue; | 1663 } |
1603 Handle<HeapNumber> expected = | 1664 |
1604 t.factory()->NewHeapNumber(static_cast<double>(x)); | 1665 |
1605 Object* result = t.Call(*num); | 1666 TEST(NumberMultiply_ConstantOutOfRange) { |
1606 CHECK(expected->SameValue(result)); | 1667 TestingGraph t(Type::Signed32()); |
1607 } | 1668 Node* k = t.jsgraph.Constant(1000000023); |
1608 } | 1669 Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k); |
1609 } | 1670 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul); |
| 1671 t.Return(trunc); |
| 1672 t.Lower(); |
| 1673 |
| 1674 CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode()); |
| 1675 } |
| 1676 |
| 1677 |
| 1678 TEST(NumberMultiply_NonTruncating) { |
| 1679 TestingGraph t(Type::Signed32()); |
| 1680 Node* k = t.jsgraph.Constant(111); |
| 1681 Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k); |
| 1682 t.Return(mul); |
| 1683 t.Lower(); |
| 1684 |
| 1685 CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode()); |
| 1686 } |
| 1687 |
| 1688 |
| 1689 TEST(NumberDivide_TruncatingToInt32) { |
| 1690 int32_t constants[] = {-100, -10, 1, 4, 100, 1000}; |
| 1691 |
| 1692 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1693 TestingGraph t(Type::Signed32()); |
| 1694 Node* k = t.jsgraph.Constant(constants[i]); |
| 1695 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); |
| 1696 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), div); |
| 1697 t.Return(trunc); |
| 1698 t.Lower(); |
| 1699 |
| 1700 CHECK_EQ(IrOpcode::kInt32Div, div->opcode()); |
| 1701 } |
| 1702 } |
| 1703 |
| 1704 |
| 1705 TEST(RunNumberDivide_TruncatingToInt32) { |
| 1706 int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048}; |
| 1707 |
| 1708 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1709 int32_t k = constants[i]; |
| 1710 SimplifiedLoweringTester<Object*> t(kMachAnyTagged); |
| 1711 Node* num = t.NumberToInt32(t.Parameter(0)); |
| 1712 Node* div = t.NumberDivide(num, t.jsgraph.Constant(k)); |
| 1713 Node* trunc = t.NumberToInt32(div); |
| 1714 t.Return(trunc); |
| 1715 |
| 1716 if (Pipeline::SupportedTarget()) { |
| 1717 t.LowerAllNodesAndLowerChanges(); |
| 1718 t.GenerateCode(); |
| 1719 |
| 1720 FOR_INT32_INPUTS(i) { |
| 1721 if (*i == INT_MAX) continue; // exclude max int. |
| 1722 int32_t x = DoubleToInt32(static_cast<double>(*i) / k); |
| 1723 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); |
| 1724 } |
| 1725 } |
| 1726 } |
| 1727 } |
| 1728 |
| 1729 |
| 1730 TEST(NumberDivide_TruncatingToUint32) { |
| 1731 double constants[] = {1, 3, 100, 1000, 100998348}; |
| 1732 |
| 1733 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1734 TestingGraph t(Type::Unsigned32()); |
| 1735 Node* k = t.jsgraph.Constant(constants[i]); |
| 1736 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); |
| 1737 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), div); |
| 1738 t.Return(trunc); |
| 1739 t.Lower(); |
| 1740 |
| 1741 CHECK_EQ(IrOpcode::kUint32Div, div->opcode()); |
| 1742 } |
| 1743 } |
| 1744 |
| 1745 |
| 1746 TEST(RunNumberDivide_TruncatingToUint32) { |
| 1747 uint32_t constants[] = {100, 10, 1, 1, 2, 4, 1000, 1024, 2048}; |
| 1748 |
| 1749 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1750 uint32_t k = constants[i]; |
| 1751 SimplifiedLoweringTester<Object*> t(kMachAnyTagged); |
| 1752 Node* num = t.NumberToUint32(t.Parameter(0)); |
| 1753 Node* div = t.NumberDivide(num, t.jsgraph.Constant(static_cast<double>(k))); |
| 1754 Node* trunc = t.NumberToUint32(div); |
| 1755 t.Return(trunc); |
| 1756 |
| 1757 if (Pipeline::SupportedTarget()) { |
| 1758 t.LowerAllNodesAndLowerChanges(); |
| 1759 t.GenerateCode(); |
| 1760 |
| 1761 FOR_UINT32_INPUTS(i) { |
| 1762 uint32_t x = *i / k; |
| 1763 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); |
| 1764 } |
| 1765 } |
| 1766 } |
| 1767 } |
| 1768 |
| 1769 |
| 1770 TEST(NumberDivide_BadConstants) { |
| 1771 int32_t constants[] = {-1, 0}; |
| 1772 |
| 1773 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1774 TestingGraph t(Type::Signed32()); |
| 1775 Node* k = t.jsgraph.Constant(constants[i]); |
| 1776 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); |
| 1777 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), div); |
| 1778 t.Return(trunc); |
| 1779 t.Lower(); |
| 1780 |
| 1781 CHECK_EQ(IrOpcode::kFloat64Div, div->opcode()); |
| 1782 } |
| 1783 |
| 1784 { |
| 1785 TestingGraph t(Type::Unsigned32()); |
| 1786 Node* k = t.jsgraph.Constant(0); |
| 1787 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k); |
| 1788 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), div); |
| 1789 t.Return(trunc); |
| 1790 t.Lower(); |
| 1791 |
| 1792 CHECK_EQ(IrOpcode::kFloat64Div, div->opcode()); |
| 1793 } |
| 1794 } |
| 1795 |
| 1796 |
| 1797 TEST(NumberModulus_TruncatingToInt32) { |
| 1798 int32_t constants[] = {-100, -10, 1, 4, 100, 1000}; |
| 1799 |
| 1800 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1801 TestingGraph t(Type::Signed32()); |
| 1802 Node* k = t.jsgraph.Constant(constants[i]); |
| 1803 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); |
| 1804 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mod); |
| 1805 t.Return(trunc); |
| 1806 t.Lower(); |
| 1807 |
| 1808 CHECK_EQ(IrOpcode::kInt32Mod, mod->opcode()); |
| 1809 } |
| 1810 } |
| 1811 |
| 1812 |
| 1813 TEST(RunNumberModulus_TruncatingToInt32) { |
| 1814 int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048}; |
| 1815 |
| 1816 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1817 int32_t k = constants[i]; |
| 1818 SimplifiedLoweringTester<Object*> t(kMachAnyTagged); |
| 1819 Node* num = t.NumberToInt32(t.Parameter(0)); |
| 1820 Node* mod = t.NumberModulus(num, t.jsgraph.Constant(k)); |
| 1821 Node* trunc = t.NumberToInt32(mod); |
| 1822 t.Return(trunc); |
| 1823 |
| 1824 if (Pipeline::SupportedTarget()) { |
| 1825 t.LowerAllNodesAndLowerChanges(); |
| 1826 t.GenerateCode(); |
| 1827 |
| 1828 FOR_INT32_INPUTS(i) { |
| 1829 if (*i == INT_MAX) continue; // exclude max int. |
| 1830 int32_t x = DoubleToInt32(std::fmod(static_cast<double>(*i), k)); |
| 1831 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); |
| 1832 } |
| 1833 } |
| 1834 } |
| 1835 } |
| 1836 |
| 1837 |
| 1838 TEST(NumberModulus_TruncatingToUint32) { |
| 1839 double constants[] = {1, 3, 100, 1000, 100998348}; |
| 1840 |
| 1841 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1842 TestingGraph t(Type::Unsigned32()); |
| 1843 Node* k = t.jsgraph.Constant(constants[i]); |
| 1844 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); |
| 1845 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod); |
| 1846 t.Return(trunc); |
| 1847 t.Lower(); |
| 1848 |
| 1849 CHECK_EQ(IrOpcode::kUint32Mod, mod->opcode()); |
| 1850 } |
| 1851 } |
| 1852 |
| 1853 |
| 1854 TEST(RunNumberModulus_TruncatingToUint32) { |
| 1855 uint32_t constants[] = {1, 2, 100, 1000, 1024, 2048}; |
| 1856 |
| 1857 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1858 uint32_t k = constants[i]; |
| 1859 SimplifiedLoweringTester<Object*> t(kMachAnyTagged); |
| 1860 Node* num = t.NumberToUint32(t.Parameter(0)); |
| 1861 Node* mod = |
| 1862 t.NumberModulus(num, t.jsgraph.Constant(static_cast<double>(k))); |
| 1863 Node* trunc = t.NumberToUint32(mod); |
| 1864 t.Return(trunc); |
| 1865 |
| 1866 if (Pipeline::SupportedTarget()) { |
| 1867 t.LowerAllNodesAndLowerChanges(); |
| 1868 t.GenerateCode(); |
| 1869 |
| 1870 FOR_UINT32_INPUTS(i) { |
| 1871 uint32_t x = *i % k; |
| 1872 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i)); |
| 1873 } |
| 1874 } |
| 1875 } |
| 1876 } |
| 1877 |
| 1878 |
| 1879 TEST(NumberModulus_Int32) { |
| 1880 int32_t constants[] = {-100, -10, 1, 4, 100, 1000}; |
| 1881 |
| 1882 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1883 TestingGraph t(Type::Signed32()); |
| 1884 Node* k = t.jsgraph.Constant(constants[i]); |
| 1885 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); |
| 1886 t.Return(mod); |
| 1887 t.Lower(); |
| 1888 |
| 1889 CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode()); // Pesky -0 behavior. |
| 1890 } |
| 1891 } |
| 1892 |
| 1893 |
| 1894 TEST(NumberModulus_Uint32) { |
| 1895 double constants[] = {1, 3, 100, 1000, 100998348}; |
| 1896 |
| 1897 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1898 TestingGraph t(Type::Unsigned32()); |
| 1899 Node* k = t.jsgraph.Constant(constants[i]); |
| 1900 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); |
| 1901 t.Return(mod); |
| 1902 t.Lower(); |
| 1903 |
| 1904 CHECK_EQ(IrOpcode::kUint32Mod, mod->opcode()); |
| 1905 } |
| 1906 } |
| 1907 |
| 1908 |
| 1909 TEST(NumberModulus_BadConstants) { |
| 1910 int32_t constants[] = {-1, 0}; |
| 1911 |
| 1912 for (size_t i = 0; i < arraysize(constants); i++) { |
| 1913 TestingGraph t(Type::Signed32()); |
| 1914 Node* k = t.jsgraph.Constant(constants[i]); |
| 1915 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); |
| 1916 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mod); |
| 1917 t.Return(trunc); |
| 1918 t.Lower(); |
| 1919 |
| 1920 CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode()); |
| 1921 } |
| 1922 |
| 1923 { |
| 1924 TestingGraph t(Type::Unsigned32()); |
| 1925 Node* k = t.jsgraph.Constant(0); |
| 1926 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k); |
| 1927 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod); |
| 1928 t.Return(trunc); |
| 1929 t.Lower(); |
| 1930 |
| 1931 CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode()); |
| 1932 } |
| 1933 } |
OLD | NEW |