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 1759 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1770 &if_keyisinvalid); | 1770 &if_keyisinvalid); |
1771 assembler.Bind(&if_keyispositivesmi); | 1771 assembler.Bind(&if_keyispositivesmi); |
1772 assembler.TailCallRuntime(Runtime::kLoadElementWithInterceptor, context, | 1772 assembler.TailCallRuntime(Runtime::kLoadElementWithInterceptor, context, |
1773 receiver, key); | 1773 receiver, key); |
1774 | 1774 |
1775 assembler.Bind(&if_keyisinvalid); | 1775 assembler.Bind(&if_keyisinvalid); |
1776 assembler.TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, | 1776 assembler.TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, |
1777 slot, vector); | 1777 slot, vector); |
1778 } | 1778 } |
1779 | 1779 |
1780 // static | |
1781 int FastCloneShallowObjectStub::PropertiesCount(int literal_length) { | |
1782 // This heuristic of setting empty literals to have | |
1783 // kInitialGlobalObjectUnusedPropertiesCount must remain in-sync with the | |
1784 // runtime. | |
1785 // TODO(verwaest): Unify this with the heuristic in the runtime. | |
1786 return literal_length == 0 | |
1787 ? JSObject::kInitialGlobalObjectUnusedPropertiesCount | |
1788 : literal_length; | |
1789 } | |
1790 | |
1791 // static | |
1792 compiler::Node* FastCloneShallowObjectStub::GenerateFastPath( | |
1793 CodeStubAssembler* assembler, compiler::CodeAssembler::Label* call_runtime, | |
1794 compiler::Node* closure, compiler::Node* literals_index, | |
1795 compiler::Node* properties_count) { | |
1796 typedef compiler::Node Node; | |
1797 typedef compiler::CodeAssembler::Label Label; | |
1798 typedef compiler::CodeAssembler::Variable Variable; | |
1799 | |
1800 Node* literals_array = | |
1801 assembler->LoadObjectField(closure, JSFunction::kLiteralsOffset); | |
1802 Node* allocation_site = assembler->LoadFixedArrayElement( | |
1803 literals_array, literals_index, | |
1804 LiteralsArray::kFirstLiteralIndex * kPointerSize, | |
1805 CodeStubAssembler::SMI_PARAMETERS); | |
1806 assembler->GotoIf(assembler->IsUndefined(allocation_site), call_runtime); | |
1807 | |
1808 // Calculate the object and allocation size based on the properties count. | |
1809 Node* object_size = assembler->IntPtrAdd( | |
1810 assembler->WordShl(properties_count, kPointerSizeLog2), | |
1811 assembler->IntPtrConstant(JSObject::kHeaderSize)); | |
1812 Node* allocation_size = object_size; | |
1813 if (FLAG_allocation_site_pretenuring) { | |
1814 allocation_size = assembler->IntPtrAdd( | |
1815 object_size, assembler->IntPtrConstant(AllocationMemento::kSize)); | |
1816 } | |
1817 Node* boilerplate = assembler->LoadObjectField( | |
1818 allocation_site, AllocationSite::kTransitionInfoOffset); | |
1819 Node* boilerplate_map = assembler->LoadMap(boilerplate); | |
1820 Node* instance_size = assembler->LoadMapInstanceSize(boilerplate_map); | |
1821 Node* size_in_words = assembler->WordShr(object_size, kPointerSizeLog2); | |
1822 assembler->GotoUnless(assembler->WordEqual(instance_size, size_in_words), | |
1823 call_runtime); | |
1824 | |
1825 Node* copy = assembler->Allocate(allocation_size); | |
1826 | |
1827 // Copy boilerplate elements. | |
1828 Variable offset(assembler, MachineType::PointerRepresentation()); | |
1829 offset.Bind(assembler->IntPtrConstant(-kHeapObjectTag)); | |
1830 Node* end_offset = assembler->IntPtrAdd(object_size, offset.value()); | |
1831 Label loop_body(assembler, &offset), loop_check(assembler, &offset); | |
1832 // We should always have an object size greater than zero. | |
1833 assembler->Goto(&loop_body); | |
1834 assembler->Bind(&loop_body); | |
1835 { | |
1836 // The Allocate above guarantees that the copy lies in new space. This | |
1837 // allows us to skip write barriers. This is necessary since we may also be | |
1838 // copying unboxed doubles. | |
1839 Node* field = | |
1840 assembler->Load(MachineType::IntPtr(), boilerplate, offset.value()); | |
1841 assembler->StoreNoWriteBarrier(MachineType::PointerRepresentation(), copy, | |
1842 offset.value(), field); | |
1843 assembler->Goto(&loop_check); | |
1844 } | |
1845 assembler->Bind(&loop_check); | |
1846 { | |
1847 offset.Bind(assembler->IntPtrAdd(offset.value(), | |
1848 assembler->IntPtrConstant(kPointerSize))); | |
1849 assembler->GotoUnless( | |
1850 assembler->IntPtrGreaterThanOrEqual(offset.value(), end_offset), | |
1851 &loop_body); | |
1852 } | |
1853 | |
1854 if (FLAG_allocation_site_pretenuring) { | |
1855 Node* memento = assembler->InnerAllocate(copy, object_size); | |
1856 assembler->StoreMapNoWriteBarrier(memento, | |
1857 Heap::kAllocationMementoMapRootIndex); | |
1858 assembler->StoreObjectFieldNoWriteBarrier( | |
1859 memento, AllocationMemento::kAllocationSiteOffset, allocation_site); | |
1860 Node* memento_create_count = assembler->LoadObjectField( | |
1861 allocation_site, AllocationSite::kPretenureCreateCountOffset); | |
1862 memento_create_count = assembler->SmiAdd( | |
1863 memento_create_count, assembler->SmiConstant(Smi::FromInt(1))); | |
1864 assembler->StoreObjectFieldNoWriteBarrier( | |
1865 allocation_site, AllocationSite::kPretenureCreateCountOffset, | |
1866 memento_create_count); | |
1867 } | |
1868 | |
1869 // TODO(verwaest): Allocate and fill in double boxes. | |
1870 return copy; | |
1871 } | |
1872 | |
1873 void FastCloneShallowObjectStub::GenerateAssembly( | |
1874 compiler::CodeAssemblerState* state) const { | |
1875 typedef CodeStubAssembler::Label Label; | |
1876 typedef compiler::Node Node; | |
1877 CodeStubAssembler assembler(state); | |
1878 | |
1879 Label call_runtime(&assembler); | |
1880 Node* closure = assembler.Parameter(0); | |
1881 Node* literals_index = assembler.Parameter(1); | |
1882 | |
1883 Node* properties_count = | |
1884 assembler.IntPtrConstant(PropertiesCount(this->length())); | |
1885 Node* copy = GenerateFastPath(&assembler, &call_runtime, closure, | |
1886 literals_index, properties_count); | |
1887 assembler.Return(copy); | |
1888 | |
1889 assembler.Bind(&call_runtime); | |
1890 Node* constant_properties = assembler.Parameter(2); | |
1891 Node* flags = assembler.Parameter(3); | |
1892 Node* context = assembler.Parameter(4); | |
1893 assembler.TailCallRuntime(Runtime::kCreateObjectLiteral, context, closure, | |
1894 literals_index, constant_properties, flags); | |
1895 } | |
1896 | |
1897 template<class StateType> | 1780 template<class StateType> |
1898 void HydrogenCodeStub::TraceTransition(StateType from, StateType to) { | 1781 void HydrogenCodeStub::TraceTransition(StateType from, StateType to) { |
1899 // Note: Although a no-op transition is semantically OK, it is hinting at a | 1782 // Note: Although a no-op transition is semantically OK, it is hinting at a |
1900 // bug somewhere in our state transition machinery. | 1783 // bug somewhere in our state transition machinery. |
1901 DCHECK(from != to); | 1784 DCHECK(from != to); |
1902 if (V8_LIKELY(!FLAG_ic_stats)) return; | 1785 if (V8_LIKELY(!FLAG_ic_stats)) return; |
1903 if (FLAG_ic_stats & | 1786 if (FLAG_ic_stats & |
1904 v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { | 1787 v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) { |
1905 auto ic_stats = ICStats::instance(); | 1788 auto ic_stats = ICStats::instance(); |
1906 ic_stats->Begin(); | 1789 ic_stats->Begin(); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2046 { | 1929 { |
2047 var_result.Bind( | 1930 var_result.Bind( |
2048 assembler.CallRuntime(Runtime::kGetProperty, context, object, key)); | 1931 assembler.CallRuntime(Runtime::kGetProperty, context, object, key)); |
2049 assembler.Goto(&end); | 1932 assembler.Goto(&end); |
2050 } | 1933 } |
2051 | 1934 |
2052 assembler.Bind(&end); | 1935 assembler.Bind(&end); |
2053 assembler.Return(var_result.value()); | 1936 assembler.Return(var_result.value()); |
2054 } | 1937 } |
2055 | 1938 |
2056 // static | |
2057 compiler::Node* FastCloneRegExpStub::Generate(CodeStubAssembler* assembler, | |
2058 compiler::Node* closure, | |
2059 compiler::Node* literal_index, | |
2060 compiler::Node* pattern, | |
2061 compiler::Node* flags, | |
2062 compiler::Node* context) { | |
2063 typedef CodeStubAssembler::Label Label; | |
2064 typedef CodeStubAssembler::Variable Variable; | |
2065 typedef compiler::Node Node; | |
2066 | |
2067 Label call_runtime(assembler, Label::kDeferred), end(assembler); | |
2068 | |
2069 Variable result(assembler, MachineRepresentation::kTagged); | |
2070 | |
2071 Node* literals_array = | |
2072 assembler->LoadObjectField(closure, JSFunction::kLiteralsOffset); | |
2073 Node* boilerplate = assembler->LoadFixedArrayElement( | |
2074 literals_array, literal_index, | |
2075 LiteralsArray::kFirstLiteralIndex * kPointerSize, | |
2076 CodeStubAssembler::SMI_PARAMETERS); | |
2077 assembler->GotoIf(assembler->IsUndefined(boilerplate), &call_runtime); | |
2078 | |
2079 { | |
2080 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; | |
2081 Node* copy = assembler->Allocate(size); | |
2082 for (int offset = 0; offset < size; offset += kPointerSize) { | |
2083 Node* value = assembler->LoadObjectField(boilerplate, offset); | |
2084 assembler->StoreObjectFieldNoWriteBarrier(copy, offset, value); | |
2085 } | |
2086 result.Bind(copy); | |
2087 assembler->Goto(&end); | |
2088 } | |
2089 | |
2090 assembler->Bind(&call_runtime); | |
2091 { | |
2092 result.Bind(assembler->CallRuntime(Runtime::kCreateRegExpLiteral, context, | |
2093 closure, literal_index, pattern, flags)); | |
2094 assembler->Goto(&end); | |
2095 } | |
2096 | |
2097 assembler->Bind(&end); | |
2098 return result.value(); | |
2099 } | |
2100 | |
2101 void FastCloneRegExpStub::GenerateAssembly( | |
2102 compiler::CodeAssemblerState* state) const { | |
2103 typedef compiler::Node Node; | |
2104 CodeStubAssembler assembler(state); | |
2105 Node* closure = assembler.Parameter(Descriptor::kClosure); | |
2106 Node* literal_index = assembler.Parameter(Descriptor::kLiteralIndex); | |
2107 Node* pattern = assembler.Parameter(Descriptor::kPattern); | |
2108 Node* flags = assembler.Parameter(Descriptor::kFlags); | |
2109 Node* context = assembler.Parameter(Descriptor::kContext); | |
2110 | |
2111 assembler.Return( | |
2112 Generate(&assembler, closure, literal_index, pattern, flags, context)); | |
2113 } | |
2114 | |
2115 namespace { | |
2116 | |
2117 compiler::Node* NonEmptyShallowClone(CodeStubAssembler* assembler, | |
2118 compiler::Node* boilerplate, | |
2119 compiler::Node* boilerplate_map, | |
2120 compiler::Node* boilerplate_elements, | |
2121 compiler::Node* allocation_site, | |
2122 compiler::Node* capacity, | |
2123 ElementsKind kind) { | |
2124 typedef compiler::Node Node; | |
2125 typedef CodeStubAssembler::ParameterMode ParameterMode; | |
2126 | |
2127 ParameterMode param_mode = assembler->OptimalParameterMode(); | |
2128 | |
2129 Node* length = assembler->LoadJSArrayLength(boilerplate); | |
2130 capacity = assembler->TaggedToParameter(capacity, param_mode); | |
2131 | |
2132 Node *array, *elements; | |
2133 std::tie(array, elements) = | |
2134 assembler->AllocateUninitializedJSArrayWithElements( | |
2135 kind, boilerplate_map, length, allocation_site, capacity, param_mode); | |
2136 | |
2137 assembler->Comment("copy elements header"); | |
2138 // Header consists of map and length. | |
2139 STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize); | |
2140 assembler->StoreMap(elements, assembler->LoadMap(boilerplate_elements)); | |
2141 { | |
2142 int offset = FixedArrayBase::kLengthOffset; | |
2143 assembler->StoreObjectFieldNoWriteBarrier( | |
2144 elements, offset, | |
2145 assembler->LoadObjectField(boilerplate_elements, offset)); | |
2146 } | |
2147 | |
2148 length = assembler->TaggedToParameter(length, param_mode); | |
2149 | |
2150 assembler->Comment("copy boilerplate elements"); | |
2151 assembler->CopyFixedArrayElements(kind, boilerplate_elements, elements, | |
2152 length, SKIP_WRITE_BARRIER, param_mode); | |
2153 assembler->IncrementCounter( | |
2154 assembler->isolate()->counters()->inlined_copied_elements(), 1); | |
2155 | |
2156 return array; | |
2157 } | |
2158 | |
2159 } // namespace | |
2160 | |
2161 // static | |
2162 compiler::Node* FastCloneShallowArrayStub::Generate( | |
2163 CodeStubAssembler* assembler, compiler::Node* closure, | |
2164 compiler::Node* literal_index, compiler::Node* context, | |
2165 CodeStubAssembler::Label* call_runtime, | |
2166 AllocationSiteMode allocation_site_mode) { | |
2167 typedef CodeStubAssembler::Label Label; | |
2168 typedef CodeStubAssembler::Variable Variable; | |
2169 typedef compiler::Node Node; | |
2170 | |
2171 Label zero_capacity(assembler), cow_elements(assembler), | |
2172 fast_elements(assembler), return_result(assembler); | |
2173 Variable result(assembler, MachineRepresentation::kTagged); | |
2174 | |
2175 Node* literals_array = | |
2176 assembler->LoadObjectField(closure, JSFunction::kLiteralsOffset); | |
2177 Node* allocation_site = assembler->LoadFixedArrayElement( | |
2178 literals_array, literal_index, | |
2179 LiteralsArray::kFirstLiteralIndex * kPointerSize, | |
2180 CodeStubAssembler::SMI_PARAMETERS); | |
2181 | |
2182 assembler->GotoIf(assembler->IsUndefined(allocation_site), call_runtime); | |
2183 allocation_site = assembler->LoadFixedArrayElement( | |
2184 literals_array, literal_index, | |
2185 LiteralsArray::kFirstLiteralIndex * kPointerSize, | |
2186 CodeStubAssembler::SMI_PARAMETERS); | |
2187 | |
2188 Node* boilerplate = assembler->LoadObjectField( | |
2189 allocation_site, AllocationSite::kTransitionInfoOffset); | |
2190 Node* boilerplate_map = assembler->LoadMap(boilerplate); | |
2191 Node* boilerplate_elements = assembler->LoadElements(boilerplate); | |
2192 Node* capacity = assembler->LoadFixedArrayBaseLength(boilerplate_elements); | |
2193 allocation_site = | |
2194 allocation_site_mode == TRACK_ALLOCATION_SITE ? allocation_site : nullptr; | |
2195 | |
2196 Node* zero = assembler->SmiConstant(Smi::kZero); | |
2197 assembler->GotoIf(assembler->SmiEqual(capacity, zero), &zero_capacity); | |
2198 | |
2199 Node* elements_map = assembler->LoadMap(boilerplate_elements); | |
2200 assembler->GotoIf(assembler->IsFixedCOWArrayMap(elements_map), &cow_elements); | |
2201 | |
2202 assembler->GotoIf(assembler->IsFixedArrayMap(elements_map), &fast_elements); | |
2203 { | |
2204 assembler->Comment("fast double elements path"); | |
2205 if (FLAG_debug_code) { | |
2206 Label correct_elements_map(assembler), abort(assembler, Label::kDeferred); | |
2207 assembler->Branch(assembler->IsFixedDoubleArrayMap(elements_map), | |
2208 &correct_elements_map, &abort); | |
2209 | |
2210 assembler->Bind(&abort); | |
2211 { | |
2212 Node* abort_id = assembler->SmiConstant( | |
2213 Smi::FromInt(BailoutReason::kExpectedFixedDoubleArrayMap)); | |
2214 assembler->CallRuntime(Runtime::kAbort, context, abort_id); | |
2215 result.Bind(assembler->UndefinedConstant()); | |
2216 assembler->Goto(&return_result); | |
2217 } | |
2218 assembler->Bind(&correct_elements_map); | |
2219 } | |
2220 | |
2221 Node* array = NonEmptyShallowClone(assembler, boilerplate, boilerplate_map, | |
2222 boilerplate_elements, allocation_site, | |
2223 capacity, FAST_DOUBLE_ELEMENTS); | |
2224 result.Bind(array); | |
2225 assembler->Goto(&return_result); | |
2226 } | |
2227 | |
2228 assembler->Bind(&fast_elements); | |
2229 { | |
2230 assembler->Comment("fast elements path"); | |
2231 Node* array = NonEmptyShallowClone(assembler, boilerplate, boilerplate_map, | |
2232 boilerplate_elements, allocation_site, | |
2233 capacity, FAST_ELEMENTS); | |
2234 result.Bind(array); | |
2235 assembler->Goto(&return_result); | |
2236 } | |
2237 | |
2238 Variable length(assembler, MachineRepresentation::kTagged), | |
2239 elements(assembler, MachineRepresentation::kTagged); | |
2240 Label allocate_without_elements(assembler); | |
2241 | |
2242 assembler->Bind(&cow_elements); | |
2243 { | |
2244 assembler->Comment("fixed cow path"); | |
2245 length.Bind(assembler->LoadJSArrayLength(boilerplate)); | |
2246 elements.Bind(boilerplate_elements); | |
2247 | |
2248 assembler->Goto(&allocate_without_elements); | |
2249 } | |
2250 | |
2251 assembler->Bind(&zero_capacity); | |
2252 { | |
2253 assembler->Comment("zero capacity path"); | |
2254 length.Bind(zero); | |
2255 elements.Bind(assembler->LoadRoot(Heap::kEmptyFixedArrayRootIndex)); | |
2256 | |
2257 assembler->Goto(&allocate_without_elements); | |
2258 } | |
2259 | |
2260 assembler->Bind(&allocate_without_elements); | |
2261 { | |
2262 Node* array = assembler->AllocateUninitializedJSArrayWithoutElements( | |
2263 FAST_ELEMENTS, boilerplate_map, length.value(), allocation_site); | |
2264 assembler->StoreObjectField(array, JSObject::kElementsOffset, | |
2265 elements.value()); | |
2266 result.Bind(array); | |
2267 assembler->Goto(&return_result); | |
2268 } | |
2269 | |
2270 assembler->Bind(&return_result); | |
2271 return result.value(); | |
2272 } | |
2273 | |
2274 void FastCloneShallowArrayStub::GenerateAssembly( | |
2275 compiler::CodeAssemblerState* state) const { | |
2276 typedef compiler::Node Node; | |
2277 typedef CodeStubAssembler::Label Label; | |
2278 CodeStubAssembler assembler(state); | |
2279 | |
2280 Node* closure = assembler.Parameter(Descriptor::kClosure); | |
2281 Node* literal_index = assembler.Parameter(Descriptor::kLiteralIndex); | |
2282 Node* constant_elements = assembler.Parameter(Descriptor::kConstantElements); | |
2283 Node* context = assembler.Parameter(Descriptor::kContext); | |
2284 Label call_runtime(&assembler, Label::kDeferred); | |
2285 assembler.Return(Generate(&assembler, closure, literal_index, context, | |
2286 &call_runtime, allocation_site_mode())); | |
2287 | |
2288 assembler.Bind(&call_runtime); | |
2289 { | |
2290 assembler.Comment("call runtime"); | |
2291 Node* flags = assembler.SmiConstant( | |
2292 Smi::FromInt(ArrayLiteral::kShallowElements | | |
2293 (allocation_site_mode() == TRACK_ALLOCATION_SITE | |
2294 ? 0 | |
2295 : ArrayLiteral::kDisableMementos))); | |
2296 assembler.Return(assembler.CallRuntime(Runtime::kCreateArrayLiteral, | |
2297 context, closure, literal_index, | |
2298 constant_elements, flags)); | |
2299 } | |
2300 } | |
2301 | |
2302 void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) { | 1939 void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) { |
2303 CreateAllocationSiteStub stub(isolate); | 1940 CreateAllocationSiteStub stub(isolate); |
2304 stub.GetCode(); | 1941 stub.GetCode(); |
2305 } | 1942 } |
2306 | 1943 |
2307 | 1944 |
2308 void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) { | 1945 void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) { |
2309 CreateWeakCellStub stub(isolate); | 1946 CreateWeakCellStub stub(isolate); |
2310 stub.GetCode(); | 1947 stub.GetCode(); |
2311 } | 1948 } |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2605 } | 2242 } |
2606 | 2243 |
2607 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate) | 2244 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate) |
2608 : PlatformCodeStub(isolate) {} | 2245 : PlatformCodeStub(isolate) {} |
2609 | 2246 |
2610 InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate) | 2247 InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate) |
2611 : PlatformCodeStub(isolate) {} | 2248 : PlatformCodeStub(isolate) {} |
2612 | 2249 |
2613 } // namespace internal | 2250 } // namespace internal |
2614 } // namespace v8 | 2251 } // namespace v8 |
OLD | NEW |