OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/code-stubs.h" | 5 #include "src/code-stubs.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 | 8 |
9 #include "src/ast/ast.h" | 9 #include "src/ast/ast.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 1741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1752 OFStream os(stdout); | 1752 OFStream os(stdout); |
1753 os << "["; | 1753 os << "["; |
1754 PrintBaseName(os); | 1754 PrintBaseName(os); |
1755 os << ": " << from << "=>" << to << "]" << std::endl; | 1755 os << ": " << from << "=>" << to << "]" << std::endl; |
1756 } | 1756 } |
1757 | 1757 |
1758 void CallICStub::PrintState(std::ostream& os) const { // NOLINT | 1758 void CallICStub::PrintState(std::ostream& os) const { // NOLINT |
1759 os << convert_mode() << ", " << tail_call_mode(); | 1759 os << convert_mode() << ", " << tail_call_mode(); |
1760 } | 1760 } |
1761 | 1761 |
| 1762 void CallICStub::GenerateAssembly(compiler::CodeAssemblerState* state) const { |
| 1763 typedef CodeStubAssembler::Label Label; |
| 1764 typedef compiler::Node Node; |
| 1765 CodeStubAssembler assembler(state); |
| 1766 |
| 1767 Node* context = assembler.Parameter(Descriptor::kContext); |
| 1768 Node* target = assembler.Parameter(Descriptor::kTarget); |
| 1769 Node* argc = assembler.Parameter(Descriptor::kActualArgumentsCount); |
| 1770 Node* slot = assembler.Parameter(Descriptor::kSlot); |
| 1771 Node* vector = assembler.Parameter(Descriptor::kVector); |
| 1772 |
| 1773 // TODO(bmeurer): The slot should actually be an IntPtr, but TurboFan's |
| 1774 // SimplifiedLowering cannot deal with IntPtr machine type properly yet. |
| 1775 slot = assembler.ChangeInt32ToIntPtr(slot); |
| 1776 |
| 1777 // Static checks to assert it is safe to examine the type feedback element. |
| 1778 // We don't know that we have a weak cell. We might have a private symbol |
| 1779 // or an AllocationSite, but the memory is safe to examine. |
| 1780 // AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to |
| 1781 // FixedArray. |
| 1782 // WeakCell::kValueOffset - contains a JSFunction or Smi(0) |
| 1783 // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not |
| 1784 // computed, meaning that it can't appear to be a pointer. If the low bit is |
| 1785 // 0, then hash is computed, but the 0 bit prevents the field from appearing |
| 1786 // to be a pointer. |
| 1787 STATIC_ASSERT(WeakCell::kSize >= kPointerSize); |
| 1788 STATIC_ASSERT(AllocationSite::kTransitionInfoOffset == |
| 1789 WeakCell::kValueOffset && |
| 1790 WeakCell::kValueOffset == Symbol::kHashFieldSlot); |
| 1791 |
| 1792 // Increment the call count. |
| 1793 // TODO(bmeurer): Would it be beneficial to use Int32Add on 64-bit? |
| 1794 assembler.Comment("increment call count"); |
| 1795 Node* call_count = |
| 1796 assembler.LoadFixedArrayElement(vector, slot, 1 * kPointerSize); |
| 1797 Node* new_count = assembler.SmiAdd(call_count, assembler.SmiConstant(1)); |
| 1798 // Count is Smi, so we don't need a write barrier. |
| 1799 assembler.StoreFixedArrayElement(vector, slot, new_count, SKIP_WRITE_BARRIER, |
| 1800 1 * kPointerSize); |
| 1801 |
| 1802 Label call_function(&assembler), extra_checks(&assembler), call(&assembler); |
| 1803 |
| 1804 // The checks. First, does function match the recorded monomorphic target? |
| 1805 Node* feedback_element = assembler.LoadFixedArrayElement(vector, slot); |
| 1806 Node* feedback_value = assembler.LoadWeakCellValueUnchecked(feedback_element); |
| 1807 Node* is_monomorphic = assembler.WordEqual(target, feedback_value); |
| 1808 assembler.GotoUnless(is_monomorphic, &extra_checks); |
| 1809 |
| 1810 // The compare above could have been a SMI/SMI comparison. Guard against |
| 1811 // this convincing us that we have a monomorphic JSFunction. |
| 1812 Node* is_smi = assembler.TaggedIsSmi(target); |
| 1813 assembler.Branch(is_smi, &extra_checks, &call_function); |
| 1814 |
| 1815 assembler.Bind(&call_function); |
| 1816 { |
| 1817 // Call using CallFunction builtin. |
| 1818 Callable callable = |
| 1819 CodeFactory::CallFunction(isolate(), convert_mode(), tail_call_mode()); |
| 1820 assembler.TailCallStub(callable, context, target, argc); |
| 1821 } |
| 1822 |
| 1823 assembler.Bind(&extra_checks); |
| 1824 { |
| 1825 Label check_initialized(&assembler), mark_megamorphic(&assembler), |
| 1826 create_allocation_site(&assembler, Label::kDeferred), |
| 1827 create_weak_cell(&assembler, Label::kDeferred); |
| 1828 |
| 1829 assembler.Comment("check if megamorphic"); |
| 1830 // Check if it is a megamorphic target. |
| 1831 Node* is_megamorphic = assembler.WordEqual( |
| 1832 feedback_element, |
| 1833 assembler.HeapConstant( |
| 1834 TypeFeedbackVector::MegamorphicSentinel(isolate()))); |
| 1835 assembler.GotoIf(is_megamorphic, &call); |
| 1836 |
| 1837 assembler.Comment("check if it is an allocation site"); |
| 1838 assembler.GotoUnless( |
| 1839 assembler.IsAllocationSiteMap(assembler.LoadMap(feedback_element)), |
| 1840 &check_initialized); |
| 1841 |
| 1842 // If it is not the Array() function, mark megamorphic. |
| 1843 Node* context_slot = assembler.LoadContextElement( |
| 1844 assembler.LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX); |
| 1845 Node* is_array_function = assembler.WordEqual(context_slot, target); |
| 1846 assembler.GotoUnless(is_array_function, &mark_megamorphic); |
| 1847 |
| 1848 // Call ArrayConstructorStub. |
| 1849 Callable callable = CodeFactory::ArrayConstructor(isolate()); |
| 1850 assembler.TailCallStub(callable, context, target, target, argc, |
| 1851 feedback_element); |
| 1852 |
| 1853 assembler.Bind(&check_initialized); |
| 1854 { |
| 1855 assembler.Comment("check if uninitialized"); |
| 1856 // Check if it is uninitialized target first. |
| 1857 Node* is_uninitialized = assembler.WordEqual( |
| 1858 feedback_element, |
| 1859 assembler.HeapConstant( |
| 1860 TypeFeedbackVector::UninitializedSentinel(isolate()))); |
| 1861 assembler.GotoUnless(is_uninitialized, &mark_megamorphic); |
| 1862 |
| 1863 assembler.Comment("handle unitinitialized"); |
| 1864 // If it is not a JSFunction mark it as megamorphic. |
| 1865 Node* is_smi = assembler.TaggedIsSmi(target); |
| 1866 assembler.GotoIf(is_smi, &mark_megamorphic); |
| 1867 |
| 1868 // Check if function is an object of JSFunction type. |
| 1869 Node* is_js_function = assembler.IsJSFunction(target); |
| 1870 assembler.GotoUnless(is_js_function, &mark_megamorphic); |
| 1871 |
| 1872 // Check if it is the Array() function. |
| 1873 Node* context_slot = assembler.LoadContextElement( |
| 1874 assembler.LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX); |
| 1875 Node* is_array_function = assembler.WordEqual(context_slot, target); |
| 1876 assembler.GotoIf(is_array_function, &create_allocation_site); |
| 1877 |
| 1878 // Check if the function belongs to the same native context. |
| 1879 Node* native_context = assembler.LoadNativeContext( |
| 1880 assembler.LoadObjectField(target, JSFunction::kContextOffset)); |
| 1881 Node* is_same_native_context = assembler.WordEqual( |
| 1882 native_context, assembler.LoadNativeContext(context)); |
| 1883 assembler.Branch(is_same_native_context, &create_weak_cell, |
| 1884 &mark_megamorphic); |
| 1885 } |
| 1886 |
| 1887 assembler.Bind(&create_weak_cell); |
| 1888 { |
| 1889 // Wrap the {target} in a WeakCell and remember it. |
| 1890 assembler.Comment("create weak cell"); |
| 1891 assembler.CreateWeakCellInFeedbackVector(vector, assembler.SmiTag(slot), |
| 1892 target); |
| 1893 |
| 1894 // Call using CallFunction builtin. |
| 1895 assembler.Goto(&call_function); |
| 1896 } |
| 1897 |
| 1898 assembler.Bind(&create_allocation_site); |
| 1899 { |
| 1900 // Create an AllocationSite for the {target}. |
| 1901 assembler.Comment("create allocation site"); |
| 1902 assembler.CreateAllocationSiteInFeedbackVector(vector, |
| 1903 assembler.SmiTag(slot)); |
| 1904 |
| 1905 // Call using CallFunction builtin. CallICs have a PREMONOMORPHIC state. |
| 1906 // They start collecting feedback only when a call is executed the second |
| 1907 // time. So, do not pass any feedback here. |
| 1908 assembler.Goto(&call_function); |
| 1909 } |
| 1910 |
| 1911 assembler.Bind(&mark_megamorphic); |
| 1912 { |
| 1913 // Mark it as a megamorphic. |
| 1914 // MegamorphicSentinel is created as a part of Heap::InitialObjects |
| 1915 // and will not move during a GC. So it is safe to skip write barrier. |
| 1916 DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); |
| 1917 assembler.StoreFixedArrayElement( |
| 1918 vector, slot, assembler.HeapConstant( |
| 1919 TypeFeedbackVector::MegamorphicSentinel(isolate())), |
| 1920 SKIP_WRITE_BARRIER); |
| 1921 assembler.Goto(&call); |
| 1922 } |
| 1923 } |
| 1924 |
| 1925 assembler.Bind(&call); |
| 1926 { |
| 1927 // Call using call builtin. |
| 1928 assembler.Comment("call using Call builtin"); |
| 1929 Callable callable_call = |
| 1930 CodeFactory::Call(isolate(), convert_mode(), tail_call_mode()); |
| 1931 assembler.TailCallStub(callable_call, context, target, argc); |
| 1932 } |
| 1933 } |
| 1934 |
1762 void CallICTrampolineStub::PrintState(std::ostream& os) const { // NOLINT | 1935 void CallICTrampolineStub::PrintState(std::ostream& os) const { // NOLINT |
1763 os << convert_mode() << ", " << tail_call_mode(); | 1936 os << convert_mode() << ", " << tail_call_mode(); |
1764 } | 1937 } |
1765 | 1938 |
1766 void CallICTrampolineStub::GenerateAssembly( | 1939 void CallICTrampolineStub::GenerateAssembly( |
1767 compiler::CodeAssemblerState* state) const { | 1940 compiler::CodeAssemblerState* state) const { |
1768 typedef compiler::Node Node; | 1941 typedef compiler::Node Node; |
1769 CodeStubAssembler assembler(state); | 1942 CodeStubAssembler assembler(state); |
1770 | 1943 |
1771 Node* context = assembler.Parameter(Descriptor::kContext); | 1944 Node* context = assembler.Parameter(Descriptor::kContext); |
1772 Node* target = assembler.Parameter(Descriptor::kFunction); | 1945 Node* target = assembler.Parameter(Descriptor::kTarget); |
1773 Node* argc = assembler.Parameter(Descriptor::kActualArgumentsCount); | 1946 Node* argc = assembler.Parameter(Descriptor::kActualArgumentsCount); |
1774 Node* slot = assembler.Parameter(Descriptor::kSlot); | 1947 Node* slot = assembler.Parameter(Descriptor::kSlot); |
1775 Node* vector = assembler.LoadTypeFeedbackVectorForStub(); | 1948 Node* vector = assembler.LoadTypeFeedbackVectorForStub(); |
1776 | 1949 |
1777 Callable callable = | 1950 Callable callable = |
1778 CodeFactory::CallIC(isolate(), convert_mode(), tail_call_mode()); | 1951 CodeFactory::CallIC(isolate(), convert_mode(), tail_call_mode()); |
1779 assembler.TailCallStub(callable, context, target, argc, slot, vector); | 1952 assembler.TailCallStub(callable, context, target, argc, slot, vector); |
1780 } | 1953 } |
1781 | 1954 |
1782 void JSEntryStub::FinishCode(Handle<Code> code) { | 1955 void JSEntryStub::FinishCode(Handle<Code> code) { |
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2196 } | 2369 } |
2197 | 2370 |
2198 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate) | 2371 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate) |
2199 : PlatformCodeStub(isolate) {} | 2372 : PlatformCodeStub(isolate) {} |
2200 | 2373 |
2201 InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate) | 2374 InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate) |
2202 : PlatformCodeStub(isolate) {} | 2375 : PlatformCodeStub(isolate) {} |
2203 | 2376 |
2204 } // namespace internal | 2377 } // namespace internal |
2205 } // namespace v8 | 2378 } // namespace v8 |
OLD | NEW |