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/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/api.h" | 8 #include "src/api.h" |
9 #include "src/arguments.h" | 9 #include "src/arguments.h" |
10 #include "src/base/bits.h" | 10 #include "src/base/bits.h" |
(...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 isolate, StoreIC::GetStrictMode(target->extra_ic_state())), | 545 isolate, StoreIC::GetStrictMode(target->extra_ic_state())), |
546 constant_pool); | 546 constant_pool); |
547 } | 547 } |
548 | 548 |
549 | 549 |
550 void CompareIC::Clear(Isolate* isolate, Address address, Code* target, | 550 void CompareIC::Clear(Isolate* isolate, Address address, Code* target, |
551 ConstantPoolArray* constant_pool) { | 551 ConstantPoolArray* constant_pool) { |
552 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC); | 552 DCHECK(CodeStub::GetMajorKey(target) == CodeStub::CompareIC); |
553 CompareICStub stub(target->stub_key(), isolate); | 553 CompareICStub stub(target->stub_key(), isolate); |
554 // Only clear CompareICs that can retain objects. | 554 // Only clear CompareICs that can retain objects. |
555 if (stub.state() != KNOWN_OBJECT) return; | 555 if (stub.state() != CompareICState::KNOWN_OBJECT) return; |
556 SetTargetAtAddress(address, GetRawUninitialized(isolate, stub.op()), | 556 SetTargetAtAddress(address, GetRawUninitialized(isolate, stub.op()), |
557 constant_pool); | 557 constant_pool); |
558 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); | 558 PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); |
559 } | 559 } |
560 | 560 |
561 | 561 |
562 // static | 562 // static |
563 Handle<Code> KeyedLoadIC::generic_stub(Isolate* isolate) { | 563 Handle<Code> KeyedLoadIC::generic_stub(Isolate* isolate) { |
564 if (FLAG_compiled_keyed_generic_loads) { | 564 if (FLAG_compiled_keyed_generic_loads) { |
565 return KeyedLoadGenericStub(isolate).GetCode(); | 565 return KeyedLoadGenericStub(isolate).GetCode(); |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
808 | 808 |
809 | 809 |
810 Handle<Code> LoadIC::initialize_stub(Isolate* isolate, | 810 Handle<Code> LoadIC::initialize_stub(Isolate* isolate, |
811 ExtraICState extra_state) { | 811 ExtraICState extra_state) { |
812 return PropertyICCompiler::ComputeLoad(isolate, UNINITIALIZED, extra_state); | 812 return PropertyICCompiler::ComputeLoad(isolate, UNINITIALIZED, extra_state); |
813 } | 813 } |
814 | 814 |
815 | 815 |
816 Handle<Code> LoadIC::megamorphic_stub() { | 816 Handle<Code> LoadIC::megamorphic_stub() { |
817 if (kind() == Code::LOAD_IC) { | 817 if (kind() == Code::LOAD_IC) { |
818 MegamorphicLoadStub stub(isolate(), State(extra_ic_state())); | 818 MegamorphicLoadStub stub(isolate(), LoadICState(extra_ic_state())); |
819 return stub.GetCode(); | 819 return stub.GetCode(); |
820 } else { | 820 } else { |
821 DCHECK_EQ(Code::KEYED_LOAD_IC, kind()); | 821 DCHECK_EQ(Code::KEYED_LOAD_IC, kind()); |
822 return KeyedLoadIC::generic_stub(isolate()); | 822 return KeyedLoadIC::generic_stub(isolate()); |
823 } | 823 } |
824 } | 824 } |
825 | 825 |
826 | 826 |
827 Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate, | 827 Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate, |
828 ExtraICState extra_state) { | 828 ExtraICState extra_state) { |
(...skipping 503 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1332 | 1332 |
1333 // Set the property. | 1333 // Set the property. |
1334 Handle<Object> result; | 1334 Handle<Object> result; |
1335 ASSIGN_RETURN_ON_EXCEPTION( | 1335 ASSIGN_RETURN_ON_EXCEPTION( |
1336 isolate(), result, | 1336 isolate(), result, |
1337 Object::SetProperty(&it, value, strict_mode(), store_mode), Object); | 1337 Object::SetProperty(&it, value, strict_mode(), store_mode), Object); |
1338 return result; | 1338 return result; |
1339 } | 1339 } |
1340 | 1340 |
1341 | 1341 |
1342 OStream& operator<<(OStream& os, const CallIC::State& s) { | |
1343 return os << "(args(" << s.arg_count() << "), " | |
1344 << (s.call_type() == CallIC::METHOD ? "METHOD" : "FUNCTION") | |
1345 << ", "; | |
1346 } | |
1347 | |
1348 | |
1349 Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc, | 1342 Handle<Code> CallIC::initialize_stub(Isolate* isolate, int argc, |
1350 CallType call_type) { | 1343 CallICState::CallType call_type) { |
1351 CallICStub stub(isolate, State(argc, call_type)); | 1344 CallICStub stub(isolate, CallICState(argc, call_type)); |
1352 Handle<Code> code = stub.GetCode(); | 1345 Handle<Code> code = stub.GetCode(); |
1353 return code; | 1346 return code; |
1354 } | 1347 } |
1355 | 1348 |
1356 | 1349 |
1357 Handle<Code> StoreIC::initialize_stub(Isolate* isolate, | 1350 Handle<Code> StoreIC::initialize_stub(Isolate* isolate, |
1358 StrictMode strict_mode) { | 1351 StrictMode strict_mode) { |
1359 ExtraICState extra_state = ComputeExtraICState(strict_mode); | 1352 ExtraICState extra_state = ComputeExtraICState(strict_mode); |
1360 Handle<Code> ic = | 1353 Handle<Code> ic = |
1361 PropertyICCompiler::ComputeStore(isolate, UNINITIALIZED, extra_state); | 1354 PropertyICCompiler::ComputeStore(isolate, UNINITIALIZED, extra_state); |
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1829 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); | 1822 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic"); |
1830 } | 1823 } |
1831 DCHECK(!stub.is_null()); | 1824 DCHECK(!stub.is_null()); |
1832 set_target(*stub); | 1825 set_target(*stub); |
1833 TRACE_IC("StoreIC", key); | 1826 TRACE_IC("StoreIC", key); |
1834 | 1827 |
1835 return store_handle; | 1828 return store_handle; |
1836 } | 1829 } |
1837 | 1830 |
1838 | 1831 |
1839 CallIC::State::State(ExtraICState extra_ic_state) | |
1840 : argc_(ArgcBits::decode(extra_ic_state)), | |
1841 call_type_(CallTypeBits::decode(extra_ic_state)) {} | |
1842 | |
1843 | |
1844 ExtraICState CallIC::State::GetExtraICState() const { | |
1845 ExtraICState extra_ic_state = | |
1846 ArgcBits::encode(argc_) | CallTypeBits::encode(call_type_); | |
1847 return extra_ic_state; | |
1848 } | |
1849 | |
1850 | |
1851 bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function, | 1832 bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function, |
1852 Handle<FixedArray> vector, Handle<Smi> slot, | 1833 Handle<FixedArray> vector, Handle<Smi> slot, |
1853 const State& state) { | 1834 const CallICState& state) { |
1854 DCHECK(FLAG_use_ic && function->IsJSFunction()); | 1835 DCHECK(FLAG_use_ic && function->IsJSFunction()); |
1855 | 1836 |
1856 // Are we the array function? | 1837 // Are we the array function? |
1857 Handle<JSFunction> array_function = | 1838 Handle<JSFunction> array_function = |
1858 Handle<JSFunction>(isolate()->native_context()->array_function()); | 1839 Handle<JSFunction>(isolate()->native_context()->array_function()); |
1859 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) { | 1840 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) { |
1860 // Alter the slot. | 1841 // Alter the slot. |
1861 IC::State old_state = FeedbackToState(vector, slot); | 1842 IC::State old_state = FeedbackToState(vector, slot); |
1862 Object* feedback = vector->get(slot->value()); | 1843 Object* feedback = vector->get(slot->value()); |
1863 if (!feedback->IsAllocationSite()) { | 1844 if (!feedback->IsAllocationSite()) { |
(...skipping 14 matching lines...) Expand all Loading... |
1878 OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true); | 1859 OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true); |
1879 TRACE_VECTOR_IC("CallIC (custom handler)", name, old_state, new_state); | 1860 TRACE_VECTOR_IC("CallIC (custom handler)", name, old_state, new_state); |
1880 return true; | 1861 return true; |
1881 } | 1862 } |
1882 return false; | 1863 return false; |
1883 } | 1864 } |
1884 | 1865 |
1885 | 1866 |
1886 void CallIC::PatchMegamorphic(Handle<Object> function, | 1867 void CallIC::PatchMegamorphic(Handle<Object> function, |
1887 Handle<FixedArray> vector, Handle<Smi> slot) { | 1868 Handle<FixedArray> vector, Handle<Smi> slot) { |
1888 State state(target()->extra_ic_state()); | 1869 CallICState state(target()->extra_ic_state()); |
1889 IC::State old_state = FeedbackToState(vector, slot); | 1870 IC::State old_state = FeedbackToState(vector, slot); |
1890 | 1871 |
1891 // We are going generic. | 1872 // We are going generic. |
1892 vector->set(slot->value(), *TypeFeedbackInfo::MegamorphicSentinel(isolate()), | 1873 vector->set(slot->value(), *TypeFeedbackInfo::MegamorphicSentinel(isolate()), |
1893 SKIP_WRITE_BARRIER); | 1874 SKIP_WRITE_BARRIER); |
1894 | 1875 |
1895 CallICStub stub(isolate(), state); | 1876 CallICStub stub(isolate(), state); |
1896 Handle<Code> code = stub.GetCode(); | 1877 Handle<Code> code = stub.GetCode(); |
1897 set_target(*code); | 1878 set_target(*code); |
1898 | 1879 |
1899 Handle<Object> name = isolate()->factory()->empty_string(); | 1880 Handle<Object> name = isolate()->factory()->empty_string(); |
1900 if (function->IsJSFunction()) { | 1881 if (function->IsJSFunction()) { |
1901 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); | 1882 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); |
1902 name = handle(js_function->shared()->name(), isolate()); | 1883 name = handle(js_function->shared()->name(), isolate()); |
1903 } | 1884 } |
1904 | 1885 |
1905 IC::State new_state = FeedbackToState(vector, slot); | 1886 IC::State new_state = FeedbackToState(vector, slot); |
1906 OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true); | 1887 OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true); |
1907 TRACE_VECTOR_IC("CallIC", name, old_state, new_state); | 1888 TRACE_VECTOR_IC("CallIC", name, old_state, new_state); |
1908 } | 1889 } |
1909 | 1890 |
1910 | 1891 |
1911 void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function, | 1892 void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function, |
1912 Handle<FixedArray> vector, Handle<Smi> slot) { | 1893 Handle<FixedArray> vector, Handle<Smi> slot) { |
1913 State state(target()->extra_ic_state()); | 1894 CallICState state(target()->extra_ic_state()); |
1914 IC::State old_state = FeedbackToState(vector, slot); | 1895 IC::State old_state = FeedbackToState(vector, slot); |
1915 Handle<Object> name = isolate()->factory()->empty_string(); | 1896 Handle<Object> name = isolate()->factory()->empty_string(); |
1916 Object* feedback = vector->get(slot->value()); | 1897 Object* feedback = vector->get(slot->value()); |
1917 | 1898 |
1918 // Hand-coded MISS handling is easier if CallIC slots don't contain smis. | 1899 // Hand-coded MISS handling is easier if CallIC slots don't contain smis. |
1919 DCHECK(!feedback->IsSmi()); | 1900 DCHECK(!feedback->IsSmi()); |
1920 | 1901 |
1921 if (feedback->IsJSFunction() || !function->IsJSFunction()) { | 1902 if (feedback->IsJSFunction() || !function->IsJSFunction()) { |
1922 // We are going generic. | 1903 // We are going generic. |
1923 vector->set(slot->value(), | 1904 vector->set(slot->value(), |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2166 map->elements_kind()); | 2147 map->elements_kind()); |
2167 } | 2148 } |
2168 Handle<Object> result; | 2149 Handle<Object> result; |
2169 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2150 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2170 isolate, result, | 2151 isolate, result, |
2171 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode)); | 2152 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode)); |
2172 return *result; | 2153 return *result; |
2173 } | 2154 } |
2174 | 2155 |
2175 | 2156 |
2176 BinaryOpIC::State::State(Isolate* isolate, ExtraICState extra_ic_state) | |
2177 : isolate_(isolate) { | |
2178 op_ = | |
2179 static_cast<Token::Value>(FIRST_TOKEN + OpField::decode(extra_ic_state)); | |
2180 mode_ = OverwriteModeField::decode(extra_ic_state); | |
2181 fixed_right_arg_ = | |
2182 Maybe<int>(HasFixedRightArgField::decode(extra_ic_state), | |
2183 1 << FixedRightArgValueField::decode(extra_ic_state)); | |
2184 left_kind_ = LeftKindField::decode(extra_ic_state); | |
2185 if (fixed_right_arg_.has_value) { | |
2186 right_kind_ = Smi::IsValid(fixed_right_arg_.value) ? SMI : INT32; | |
2187 } else { | |
2188 right_kind_ = RightKindField::decode(extra_ic_state); | |
2189 } | |
2190 result_kind_ = ResultKindField::decode(extra_ic_state); | |
2191 DCHECK_LE(FIRST_TOKEN, op_); | |
2192 DCHECK_LE(op_, LAST_TOKEN); | |
2193 } | |
2194 | |
2195 | |
2196 ExtraICState BinaryOpIC::State::GetExtraICState() const { | |
2197 ExtraICState extra_ic_state = | |
2198 OpField::encode(op_ - FIRST_TOKEN) | OverwriteModeField::encode(mode_) | | |
2199 LeftKindField::encode(left_kind_) | | |
2200 ResultKindField::encode(result_kind_) | | |
2201 HasFixedRightArgField::encode(fixed_right_arg_.has_value); | |
2202 if (fixed_right_arg_.has_value) { | |
2203 extra_ic_state = FixedRightArgValueField::update( | |
2204 extra_ic_state, WhichPowerOf2(fixed_right_arg_.value)); | |
2205 } else { | |
2206 extra_ic_state = RightKindField::update(extra_ic_state, right_kind_); | |
2207 } | |
2208 return extra_ic_state; | |
2209 } | |
2210 | |
2211 | |
2212 // static | |
2213 void BinaryOpIC::State::GenerateAheadOfTime(Isolate* isolate, | |
2214 void (*Generate)(Isolate*, | |
2215 const State&)) { | |
2216 // TODO(olivf) We should investigate why adding stubs to the snapshot is so | |
2217 // expensive at runtime. When solved we should be able to add most binops to | |
2218 // the snapshot instead of hand-picking them. | |
2219 // Generated list of commonly used stubs | |
2220 #define GENERATE(op, left_kind, right_kind, result_kind, mode) \ | |
2221 do { \ | |
2222 State state(isolate, op, mode); \ | |
2223 state.left_kind_ = left_kind; \ | |
2224 state.fixed_right_arg_.has_value = false; \ | |
2225 state.right_kind_ = right_kind; \ | |
2226 state.result_kind_ = result_kind; \ | |
2227 Generate(isolate, state); \ | |
2228 } while (false) | |
2229 GENERATE(Token::ADD, INT32, INT32, INT32, NO_OVERWRITE); | |
2230 GENERATE(Token::ADD, INT32, INT32, INT32, OVERWRITE_LEFT); | |
2231 GENERATE(Token::ADD, INT32, INT32, NUMBER, NO_OVERWRITE); | |
2232 GENERATE(Token::ADD, INT32, INT32, NUMBER, OVERWRITE_LEFT); | |
2233 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, NO_OVERWRITE); | |
2234 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2235 GENERATE(Token::ADD, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT); | |
2236 GENERATE(Token::ADD, INT32, SMI, INT32, NO_OVERWRITE); | |
2237 GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_LEFT); | |
2238 GENERATE(Token::ADD, INT32, SMI, INT32, OVERWRITE_RIGHT); | |
2239 GENERATE(Token::ADD, NUMBER, INT32, NUMBER, NO_OVERWRITE); | |
2240 GENERATE(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_LEFT); | |
2241 GENERATE(Token::ADD, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT); | |
2242 GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, NO_OVERWRITE); | |
2243 GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2244 GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT); | |
2245 GENERATE(Token::ADD, NUMBER, SMI, NUMBER, NO_OVERWRITE); | |
2246 GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); | |
2247 GENERATE(Token::ADD, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT); | |
2248 GENERATE(Token::ADD, SMI, INT32, INT32, NO_OVERWRITE); | |
2249 GENERATE(Token::ADD, SMI, INT32, INT32, OVERWRITE_LEFT); | |
2250 GENERATE(Token::ADD, SMI, INT32, NUMBER, NO_OVERWRITE); | |
2251 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, NO_OVERWRITE); | |
2252 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2253 GENERATE(Token::ADD, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT); | |
2254 GENERATE(Token::ADD, SMI, SMI, INT32, OVERWRITE_LEFT); | |
2255 GENERATE(Token::ADD, SMI, SMI, SMI, OVERWRITE_RIGHT); | |
2256 GENERATE(Token::BIT_AND, INT32, INT32, INT32, NO_OVERWRITE); | |
2257 GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_LEFT); | |
2258 GENERATE(Token::BIT_AND, INT32, INT32, INT32, OVERWRITE_RIGHT); | |
2259 GENERATE(Token::BIT_AND, INT32, INT32, SMI, NO_OVERWRITE); | |
2260 GENERATE(Token::BIT_AND, INT32, INT32, SMI, OVERWRITE_RIGHT); | |
2261 GENERATE(Token::BIT_AND, INT32, SMI, INT32, NO_OVERWRITE); | |
2262 GENERATE(Token::BIT_AND, INT32, SMI, INT32, OVERWRITE_RIGHT); | |
2263 GENERATE(Token::BIT_AND, INT32, SMI, SMI, NO_OVERWRITE); | |
2264 GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_LEFT); | |
2265 GENERATE(Token::BIT_AND, INT32, SMI, SMI, OVERWRITE_RIGHT); | |
2266 GENERATE(Token::BIT_AND, NUMBER, INT32, INT32, OVERWRITE_RIGHT); | |
2267 GENERATE(Token::BIT_AND, NUMBER, SMI, SMI, NO_OVERWRITE); | |
2268 GENERATE(Token::BIT_AND, NUMBER, SMI, SMI, OVERWRITE_RIGHT); | |
2269 GENERATE(Token::BIT_AND, SMI, INT32, INT32, NO_OVERWRITE); | |
2270 GENERATE(Token::BIT_AND, SMI, INT32, SMI, OVERWRITE_RIGHT); | |
2271 GENERATE(Token::BIT_AND, SMI, NUMBER, SMI, OVERWRITE_RIGHT); | |
2272 GENERATE(Token::BIT_AND, SMI, SMI, SMI, NO_OVERWRITE); | |
2273 GENERATE(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_LEFT); | |
2274 GENERATE(Token::BIT_AND, SMI, SMI, SMI, OVERWRITE_RIGHT); | |
2275 GENERATE(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_LEFT); | |
2276 GENERATE(Token::BIT_OR, INT32, INT32, INT32, OVERWRITE_RIGHT); | |
2277 GENERATE(Token::BIT_OR, INT32, INT32, SMI, OVERWRITE_LEFT); | |
2278 GENERATE(Token::BIT_OR, INT32, SMI, INT32, NO_OVERWRITE); | |
2279 GENERATE(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_LEFT); | |
2280 GENERATE(Token::BIT_OR, INT32, SMI, INT32, OVERWRITE_RIGHT); | |
2281 GENERATE(Token::BIT_OR, INT32, SMI, SMI, NO_OVERWRITE); | |
2282 GENERATE(Token::BIT_OR, INT32, SMI, SMI, OVERWRITE_RIGHT); | |
2283 GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, NO_OVERWRITE); | |
2284 GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_LEFT); | |
2285 GENERATE(Token::BIT_OR, NUMBER, SMI, INT32, OVERWRITE_RIGHT); | |
2286 GENERATE(Token::BIT_OR, NUMBER, SMI, SMI, NO_OVERWRITE); | |
2287 GENERATE(Token::BIT_OR, NUMBER, SMI, SMI, OVERWRITE_LEFT); | |
2288 GENERATE(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_LEFT); | |
2289 GENERATE(Token::BIT_OR, SMI, INT32, INT32, OVERWRITE_RIGHT); | |
2290 GENERATE(Token::BIT_OR, SMI, INT32, SMI, OVERWRITE_RIGHT); | |
2291 GENERATE(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_LEFT); | |
2292 GENERATE(Token::BIT_OR, SMI, SMI, SMI, OVERWRITE_RIGHT); | |
2293 GENERATE(Token::BIT_XOR, INT32, INT32, INT32, NO_OVERWRITE); | |
2294 GENERATE(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_LEFT); | |
2295 GENERATE(Token::BIT_XOR, INT32, INT32, INT32, OVERWRITE_RIGHT); | |
2296 GENERATE(Token::BIT_XOR, INT32, INT32, SMI, NO_OVERWRITE); | |
2297 GENERATE(Token::BIT_XOR, INT32, INT32, SMI, OVERWRITE_LEFT); | |
2298 GENERATE(Token::BIT_XOR, INT32, NUMBER, SMI, NO_OVERWRITE); | |
2299 GENERATE(Token::BIT_XOR, INT32, SMI, INT32, NO_OVERWRITE); | |
2300 GENERATE(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_LEFT); | |
2301 GENERATE(Token::BIT_XOR, INT32, SMI, INT32, OVERWRITE_RIGHT); | |
2302 GENERATE(Token::BIT_XOR, NUMBER, INT32, INT32, NO_OVERWRITE); | |
2303 GENERATE(Token::BIT_XOR, NUMBER, SMI, INT32, NO_OVERWRITE); | |
2304 GENERATE(Token::BIT_XOR, NUMBER, SMI, SMI, NO_OVERWRITE); | |
2305 GENERATE(Token::BIT_XOR, SMI, INT32, INT32, NO_OVERWRITE); | |
2306 GENERATE(Token::BIT_XOR, SMI, INT32, INT32, OVERWRITE_LEFT); | |
2307 GENERATE(Token::BIT_XOR, SMI, INT32, SMI, OVERWRITE_LEFT); | |
2308 GENERATE(Token::BIT_XOR, SMI, SMI, SMI, NO_OVERWRITE); | |
2309 GENERATE(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_LEFT); | |
2310 GENERATE(Token::BIT_XOR, SMI, SMI, SMI, OVERWRITE_RIGHT); | |
2311 GENERATE(Token::DIV, INT32, INT32, INT32, NO_OVERWRITE); | |
2312 GENERATE(Token::DIV, INT32, INT32, NUMBER, NO_OVERWRITE); | |
2313 GENERATE(Token::DIV, INT32, NUMBER, NUMBER, NO_OVERWRITE); | |
2314 GENERATE(Token::DIV, INT32, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2315 GENERATE(Token::DIV, INT32, SMI, INT32, NO_OVERWRITE); | |
2316 GENERATE(Token::DIV, INT32, SMI, NUMBER, NO_OVERWRITE); | |
2317 GENERATE(Token::DIV, NUMBER, INT32, NUMBER, NO_OVERWRITE); | |
2318 GENERATE(Token::DIV, NUMBER, INT32, NUMBER, OVERWRITE_LEFT); | |
2319 GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, NO_OVERWRITE); | |
2320 GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2321 GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT); | |
2322 GENERATE(Token::DIV, NUMBER, SMI, NUMBER, NO_OVERWRITE); | |
2323 GENERATE(Token::DIV, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); | |
2324 GENERATE(Token::DIV, SMI, INT32, INT32, NO_OVERWRITE); | |
2325 GENERATE(Token::DIV, SMI, INT32, NUMBER, NO_OVERWRITE); | |
2326 GENERATE(Token::DIV, SMI, INT32, NUMBER, OVERWRITE_LEFT); | |
2327 GENERATE(Token::DIV, SMI, NUMBER, NUMBER, NO_OVERWRITE); | |
2328 GENERATE(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2329 GENERATE(Token::DIV, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT); | |
2330 GENERATE(Token::DIV, SMI, SMI, NUMBER, NO_OVERWRITE); | |
2331 GENERATE(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_LEFT); | |
2332 GENERATE(Token::DIV, SMI, SMI, NUMBER, OVERWRITE_RIGHT); | |
2333 GENERATE(Token::DIV, SMI, SMI, SMI, NO_OVERWRITE); | |
2334 GENERATE(Token::DIV, SMI, SMI, SMI, OVERWRITE_LEFT); | |
2335 GENERATE(Token::DIV, SMI, SMI, SMI, OVERWRITE_RIGHT); | |
2336 GENERATE(Token::MOD, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); | |
2337 GENERATE(Token::MOD, SMI, SMI, SMI, NO_OVERWRITE); | |
2338 GENERATE(Token::MOD, SMI, SMI, SMI, OVERWRITE_LEFT); | |
2339 GENERATE(Token::MUL, INT32, INT32, INT32, NO_OVERWRITE); | |
2340 GENERATE(Token::MUL, INT32, INT32, NUMBER, NO_OVERWRITE); | |
2341 GENERATE(Token::MUL, INT32, NUMBER, NUMBER, NO_OVERWRITE); | |
2342 GENERATE(Token::MUL, INT32, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2343 GENERATE(Token::MUL, INT32, SMI, INT32, NO_OVERWRITE); | |
2344 GENERATE(Token::MUL, INT32, SMI, INT32, OVERWRITE_LEFT); | |
2345 GENERATE(Token::MUL, INT32, SMI, NUMBER, NO_OVERWRITE); | |
2346 GENERATE(Token::MUL, NUMBER, INT32, NUMBER, NO_OVERWRITE); | |
2347 GENERATE(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_LEFT); | |
2348 GENERATE(Token::MUL, NUMBER, INT32, NUMBER, OVERWRITE_RIGHT); | |
2349 GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER, NO_OVERWRITE); | |
2350 GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2351 GENERATE(Token::MUL, NUMBER, SMI, NUMBER, NO_OVERWRITE); | |
2352 GENERATE(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); | |
2353 GENERATE(Token::MUL, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT); | |
2354 GENERATE(Token::MUL, SMI, INT32, INT32, NO_OVERWRITE); | |
2355 GENERATE(Token::MUL, SMI, INT32, INT32, OVERWRITE_LEFT); | |
2356 GENERATE(Token::MUL, SMI, INT32, NUMBER, NO_OVERWRITE); | |
2357 GENERATE(Token::MUL, SMI, NUMBER, NUMBER, NO_OVERWRITE); | |
2358 GENERATE(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2359 GENERATE(Token::MUL, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT); | |
2360 GENERATE(Token::MUL, SMI, SMI, INT32, NO_OVERWRITE); | |
2361 GENERATE(Token::MUL, SMI, SMI, NUMBER, NO_OVERWRITE); | |
2362 GENERATE(Token::MUL, SMI, SMI, NUMBER, OVERWRITE_LEFT); | |
2363 GENERATE(Token::MUL, SMI, SMI, SMI, NO_OVERWRITE); | |
2364 GENERATE(Token::MUL, SMI, SMI, SMI, OVERWRITE_LEFT); | |
2365 GENERATE(Token::MUL, SMI, SMI, SMI, OVERWRITE_RIGHT); | |
2366 GENERATE(Token::SAR, INT32, SMI, INT32, OVERWRITE_RIGHT); | |
2367 GENERATE(Token::SAR, INT32, SMI, SMI, NO_OVERWRITE); | |
2368 GENERATE(Token::SAR, INT32, SMI, SMI, OVERWRITE_RIGHT); | |
2369 GENERATE(Token::SAR, NUMBER, SMI, SMI, NO_OVERWRITE); | |
2370 GENERATE(Token::SAR, NUMBER, SMI, SMI, OVERWRITE_RIGHT); | |
2371 GENERATE(Token::SAR, SMI, SMI, SMI, OVERWRITE_LEFT); | |
2372 GENERATE(Token::SAR, SMI, SMI, SMI, OVERWRITE_RIGHT); | |
2373 GENERATE(Token::SHL, INT32, SMI, INT32, NO_OVERWRITE); | |
2374 GENERATE(Token::SHL, INT32, SMI, INT32, OVERWRITE_RIGHT); | |
2375 GENERATE(Token::SHL, INT32, SMI, SMI, NO_OVERWRITE); | |
2376 GENERATE(Token::SHL, INT32, SMI, SMI, OVERWRITE_RIGHT); | |
2377 GENERATE(Token::SHL, NUMBER, SMI, SMI, OVERWRITE_RIGHT); | |
2378 GENERATE(Token::SHL, SMI, SMI, INT32, NO_OVERWRITE); | |
2379 GENERATE(Token::SHL, SMI, SMI, INT32, OVERWRITE_LEFT); | |
2380 GENERATE(Token::SHL, SMI, SMI, INT32, OVERWRITE_RIGHT); | |
2381 GENERATE(Token::SHL, SMI, SMI, SMI, NO_OVERWRITE); | |
2382 GENERATE(Token::SHL, SMI, SMI, SMI, OVERWRITE_LEFT); | |
2383 GENERATE(Token::SHL, SMI, SMI, SMI, OVERWRITE_RIGHT); | |
2384 GENERATE(Token::SHR, INT32, SMI, SMI, NO_OVERWRITE); | |
2385 GENERATE(Token::SHR, INT32, SMI, SMI, OVERWRITE_LEFT); | |
2386 GENERATE(Token::SHR, INT32, SMI, SMI, OVERWRITE_RIGHT); | |
2387 GENERATE(Token::SHR, NUMBER, SMI, SMI, NO_OVERWRITE); | |
2388 GENERATE(Token::SHR, NUMBER, SMI, SMI, OVERWRITE_LEFT); | |
2389 GENERATE(Token::SHR, NUMBER, SMI, INT32, OVERWRITE_RIGHT); | |
2390 GENERATE(Token::SHR, SMI, SMI, SMI, NO_OVERWRITE); | |
2391 GENERATE(Token::SHR, SMI, SMI, SMI, OVERWRITE_LEFT); | |
2392 GENERATE(Token::SHR, SMI, SMI, SMI, OVERWRITE_RIGHT); | |
2393 GENERATE(Token::SUB, INT32, INT32, INT32, NO_OVERWRITE); | |
2394 GENERATE(Token::SUB, INT32, INT32, INT32, OVERWRITE_LEFT); | |
2395 GENERATE(Token::SUB, INT32, NUMBER, NUMBER, NO_OVERWRITE); | |
2396 GENERATE(Token::SUB, INT32, NUMBER, NUMBER, OVERWRITE_RIGHT); | |
2397 GENERATE(Token::SUB, INT32, SMI, INT32, OVERWRITE_LEFT); | |
2398 GENERATE(Token::SUB, INT32, SMI, INT32, OVERWRITE_RIGHT); | |
2399 GENERATE(Token::SUB, NUMBER, INT32, NUMBER, NO_OVERWRITE); | |
2400 GENERATE(Token::SUB, NUMBER, INT32, NUMBER, OVERWRITE_LEFT); | |
2401 GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, NO_OVERWRITE); | |
2402 GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2403 GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER, OVERWRITE_RIGHT); | |
2404 GENERATE(Token::SUB, NUMBER, SMI, NUMBER, NO_OVERWRITE); | |
2405 GENERATE(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_LEFT); | |
2406 GENERATE(Token::SUB, NUMBER, SMI, NUMBER, OVERWRITE_RIGHT); | |
2407 GENERATE(Token::SUB, SMI, INT32, INT32, NO_OVERWRITE); | |
2408 GENERATE(Token::SUB, SMI, NUMBER, NUMBER, NO_OVERWRITE); | |
2409 GENERATE(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_LEFT); | |
2410 GENERATE(Token::SUB, SMI, NUMBER, NUMBER, OVERWRITE_RIGHT); | |
2411 GENERATE(Token::SUB, SMI, SMI, SMI, NO_OVERWRITE); | |
2412 GENERATE(Token::SUB, SMI, SMI, SMI, OVERWRITE_LEFT); | |
2413 GENERATE(Token::SUB, SMI, SMI, SMI, OVERWRITE_RIGHT); | |
2414 #undef GENERATE | |
2415 #define GENERATE(op, left_kind, fixed_right_arg_value, result_kind, mode) \ | |
2416 do { \ | |
2417 State state(isolate, op, mode); \ | |
2418 state.left_kind_ = left_kind; \ | |
2419 state.fixed_right_arg_.has_value = true; \ | |
2420 state.fixed_right_arg_.value = fixed_right_arg_value; \ | |
2421 state.right_kind_ = SMI; \ | |
2422 state.result_kind_ = result_kind; \ | |
2423 Generate(isolate, state); \ | |
2424 } while (false) | |
2425 GENERATE(Token::MOD, SMI, 2, SMI, NO_OVERWRITE); | |
2426 GENERATE(Token::MOD, SMI, 4, SMI, NO_OVERWRITE); | |
2427 GENERATE(Token::MOD, SMI, 4, SMI, OVERWRITE_LEFT); | |
2428 GENERATE(Token::MOD, SMI, 8, SMI, NO_OVERWRITE); | |
2429 GENERATE(Token::MOD, SMI, 16, SMI, OVERWRITE_LEFT); | |
2430 GENERATE(Token::MOD, SMI, 32, SMI, NO_OVERWRITE); | |
2431 GENERATE(Token::MOD, SMI, 2048, SMI, NO_OVERWRITE); | |
2432 #undef GENERATE | |
2433 } | |
2434 | |
2435 | |
2436 Type* BinaryOpIC::State::GetResultType(Zone* zone) const { | |
2437 Kind result_kind = result_kind_; | |
2438 if (HasSideEffects()) { | |
2439 result_kind = NONE; | |
2440 } else if (result_kind == GENERIC && op_ == Token::ADD) { | |
2441 return Type::Union(Type::Number(zone), Type::String(zone), zone); | |
2442 } else if (result_kind == NUMBER && op_ == Token::SHR) { | |
2443 return Type::Unsigned32(zone); | |
2444 } | |
2445 DCHECK_NE(GENERIC, result_kind); | |
2446 return KindToType(result_kind, zone); | |
2447 } | |
2448 | |
2449 | |
2450 OStream& operator<<(OStream& os, const BinaryOpIC::State& s) { | |
2451 os << "(" << Token::Name(s.op_); | |
2452 if (s.mode_ == OVERWRITE_LEFT) | |
2453 os << "_ReuseLeft"; | |
2454 else if (s.mode_ == OVERWRITE_RIGHT) | |
2455 os << "_ReuseRight"; | |
2456 if (s.CouldCreateAllocationMementos()) os << "_CreateAllocationMementos"; | |
2457 os << ":" << BinaryOpIC::State::KindToString(s.left_kind_) << "*"; | |
2458 if (s.fixed_right_arg_.has_value) { | |
2459 os << s.fixed_right_arg_.value; | |
2460 } else { | |
2461 os << BinaryOpIC::State::KindToString(s.right_kind_); | |
2462 } | |
2463 return os << "->" << BinaryOpIC::State::KindToString(s.result_kind_) << ")"; | |
2464 } | |
2465 | |
2466 | |
2467 void BinaryOpIC::State::Update(Handle<Object> left, Handle<Object> right, | |
2468 Handle<Object> result) { | |
2469 ExtraICState old_extra_ic_state = GetExtraICState(); | |
2470 | |
2471 left_kind_ = UpdateKind(left, left_kind_); | |
2472 right_kind_ = UpdateKind(right, right_kind_); | |
2473 | |
2474 int32_t fixed_right_arg_value = 0; | |
2475 bool has_fixed_right_arg = | |
2476 op_ == Token::MOD && right->ToInt32(&fixed_right_arg_value) && | |
2477 fixed_right_arg_value > 0 && | |
2478 base::bits::IsPowerOfTwo32(fixed_right_arg_value) && | |
2479 FixedRightArgValueField::is_valid(WhichPowerOf2(fixed_right_arg_value)) && | |
2480 (left_kind_ == SMI || left_kind_ == INT32) && | |
2481 (result_kind_ == NONE || !fixed_right_arg_.has_value); | |
2482 fixed_right_arg_ = Maybe<int32_t>(has_fixed_right_arg, fixed_right_arg_value); | |
2483 | |
2484 result_kind_ = UpdateKind(result, result_kind_); | |
2485 | |
2486 if (!Token::IsTruncatingBinaryOp(op_)) { | |
2487 Kind input_kind = Max(left_kind_, right_kind_); | |
2488 if (result_kind_ < input_kind && input_kind <= NUMBER) { | |
2489 result_kind_ = input_kind; | |
2490 } | |
2491 } | |
2492 | |
2493 // We don't want to distinguish INT32 and NUMBER for string add (because | |
2494 // NumberToString can't make use of this anyway). | |
2495 if (left_kind_ == STRING && right_kind_ == INT32) { | |
2496 DCHECK_EQ(STRING, result_kind_); | |
2497 DCHECK_EQ(Token::ADD, op_); | |
2498 right_kind_ = NUMBER; | |
2499 } else if (right_kind_ == STRING && left_kind_ == INT32) { | |
2500 DCHECK_EQ(STRING, result_kind_); | |
2501 DCHECK_EQ(Token::ADD, op_); | |
2502 left_kind_ = NUMBER; | |
2503 } | |
2504 | |
2505 // Reset overwrite mode unless we can actually make use of it, or may be able | |
2506 // to make use of it at some point in the future. | |
2507 if ((mode_ == OVERWRITE_LEFT && left_kind_ > NUMBER) || | |
2508 (mode_ == OVERWRITE_RIGHT && right_kind_ > NUMBER) || | |
2509 result_kind_ > NUMBER) { | |
2510 mode_ = NO_OVERWRITE; | |
2511 } | |
2512 | |
2513 if (old_extra_ic_state == GetExtraICState()) { | |
2514 // Tagged operations can lead to non-truncating HChanges | |
2515 if (left->IsUndefined() || left->IsBoolean()) { | |
2516 left_kind_ = GENERIC; | |
2517 } else { | |
2518 DCHECK(right->IsUndefined() || right->IsBoolean()); | |
2519 right_kind_ = GENERIC; | |
2520 } | |
2521 } | |
2522 } | |
2523 | |
2524 | |
2525 BinaryOpIC::State::Kind BinaryOpIC::State::UpdateKind(Handle<Object> object, | |
2526 Kind kind) const { | |
2527 Kind new_kind = GENERIC; | |
2528 bool is_truncating = Token::IsTruncatingBinaryOp(op()); | |
2529 if (object->IsBoolean() && is_truncating) { | |
2530 // Booleans will be automatically truncated by HChange. | |
2531 new_kind = INT32; | |
2532 } else if (object->IsUndefined()) { | |
2533 // Undefined will be automatically truncated by HChange. | |
2534 new_kind = is_truncating ? INT32 : NUMBER; | |
2535 } else if (object->IsSmi()) { | |
2536 new_kind = SMI; | |
2537 } else if (object->IsHeapNumber()) { | |
2538 double value = Handle<HeapNumber>::cast(object)->value(); | |
2539 new_kind = IsInt32Double(value) ? INT32 : NUMBER; | |
2540 } else if (object->IsString() && op() == Token::ADD) { | |
2541 new_kind = STRING; | |
2542 } | |
2543 if (new_kind == INT32 && SmiValuesAre32Bits()) { | |
2544 new_kind = NUMBER; | |
2545 } | |
2546 if (kind != NONE && ((new_kind <= NUMBER && kind > NUMBER) || | |
2547 (new_kind > NUMBER && kind <= NUMBER))) { | |
2548 new_kind = GENERIC; | |
2549 } | |
2550 return Max(kind, new_kind); | |
2551 } | |
2552 | |
2553 | |
2554 // static | |
2555 const char* BinaryOpIC::State::KindToString(Kind kind) { | |
2556 switch (kind) { | |
2557 case NONE: | |
2558 return "None"; | |
2559 case SMI: | |
2560 return "Smi"; | |
2561 case INT32: | |
2562 return "Int32"; | |
2563 case NUMBER: | |
2564 return "Number"; | |
2565 case STRING: | |
2566 return "String"; | |
2567 case GENERIC: | |
2568 return "Generic"; | |
2569 } | |
2570 UNREACHABLE(); | |
2571 return NULL; | |
2572 } | |
2573 | |
2574 | |
2575 // static | |
2576 Type* BinaryOpIC::State::KindToType(Kind kind, Zone* zone) { | |
2577 switch (kind) { | |
2578 case NONE: | |
2579 return Type::None(zone); | |
2580 case SMI: | |
2581 return Type::SignedSmall(zone); | |
2582 case INT32: | |
2583 return Type::Signed32(zone); | |
2584 case NUMBER: | |
2585 return Type::Number(zone); | |
2586 case STRING: | |
2587 return Type::String(zone); | |
2588 case GENERIC: | |
2589 return Type::Any(zone); | |
2590 } | |
2591 UNREACHABLE(); | |
2592 return NULL; | |
2593 } | |
2594 | |
2595 | |
2596 MaybeHandle<Object> BinaryOpIC::Transition( | 2157 MaybeHandle<Object> BinaryOpIC::Transition( |
2597 Handle<AllocationSite> allocation_site, Handle<Object> left, | 2158 Handle<AllocationSite> allocation_site, Handle<Object> left, |
2598 Handle<Object> right) { | 2159 Handle<Object> right) { |
2599 State state(isolate(), target()->extra_ic_state()); | 2160 BinaryOpICState state(isolate(), target()->extra_ic_state()); |
2600 | 2161 |
2601 // Compute the actual result using the builtin for the binary operation. | 2162 // Compute the actual result using the builtin for the binary operation. |
2602 Object* builtin = isolate()->js_builtins_object()->javascript_builtin( | 2163 Object* builtin = isolate()->js_builtins_object()->javascript_builtin( |
2603 TokenToJSBuiltin(state.op())); | 2164 TokenToJSBuiltin(state.op())); |
2604 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate()); | 2165 Handle<JSFunction> function = handle(JSFunction::cast(builtin), isolate()); |
2605 Handle<Object> result; | 2166 Handle<Object> result; |
2606 ASSIGN_RETURN_ON_EXCEPTION( | 2167 ASSIGN_RETURN_ON_EXCEPTION( |
2607 isolate(), result, Execution::Call(isolate(), function, left, 1, &right), | 2168 isolate(), result, Execution::Call(isolate(), function, left, 1, &right), |
2608 Object); | 2169 Object); |
2609 | 2170 |
2610 // Execution::Call can execute arbitrary JavaScript, hence potentially | 2171 // Execution::Call can execute arbitrary JavaScript, hence potentially |
2611 // update the state of this very IC, so we must update the stored state. | 2172 // update the state of this very IC, so we must update the stored state. |
2612 UpdateTarget(); | 2173 UpdateTarget(); |
2613 // Compute the new state. | 2174 // Compute the new state. |
2614 State old_state(isolate(), target()->extra_ic_state()); | 2175 BinaryOpICState old_state(isolate(), target()->extra_ic_state()); |
2615 state.Update(left, right, result); | 2176 state.Update(left, right, result); |
2616 | 2177 |
2617 // Check if we have a string operation here. | 2178 // Check if we have a string operation here. |
2618 Handle<Code> target; | 2179 Handle<Code> target; |
2619 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) { | 2180 if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) { |
2620 // Setup the allocation site on-demand. | 2181 // Setup the allocation site on-demand. |
2621 if (allocation_site.is_null()) { | 2182 if (allocation_site.is_null()) { |
2622 allocation_site = isolate()->factory()->NewAllocationSite(); | 2183 allocation_site = isolate()->factory()->NewAllocationSite(); |
2623 } | 2184 } |
2624 | 2185 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2686 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight); | 2247 args.at<Object>(BinaryOpWithAllocationSiteStub::kRight); |
2687 BinaryOpIC ic(isolate); | 2248 BinaryOpIC ic(isolate); |
2688 Handle<Object> result; | 2249 Handle<Object> result; |
2689 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 2250 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
2690 isolate, result, ic.Transition(allocation_site, left, right)); | 2251 isolate, result, ic.Transition(allocation_site, left, right)); |
2691 return *result; | 2252 return *result; |
2692 } | 2253 } |
2693 | 2254 |
2694 | 2255 |
2695 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { | 2256 Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) { |
2696 CompareICStub stub(isolate, op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2257 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED, |
| 2258 CompareICState::UNINITIALIZED, |
| 2259 CompareICState::UNINITIALIZED); |
2697 Code* code = NULL; | 2260 Code* code = NULL; |
2698 CHECK(stub.FindCodeInCache(&code)); | 2261 CHECK(stub.FindCodeInCache(&code)); |
2699 return code; | 2262 return code; |
2700 } | 2263 } |
2701 | 2264 |
2702 | 2265 |
2703 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { | 2266 Handle<Code> CompareIC::GetUninitialized(Isolate* isolate, Token::Value op) { |
2704 CompareICStub stub(isolate, op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); | 2267 CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED, |
| 2268 CompareICState::UNINITIALIZED, |
| 2269 CompareICState::UNINITIALIZED); |
2705 return stub.GetCode(); | 2270 return stub.GetCode(); |
2706 } | 2271 } |
2707 | 2272 |
2708 | 2273 |
2709 const char* CompareIC::GetStateName(State state) { | |
2710 switch (state) { | |
2711 case UNINITIALIZED: | |
2712 return "UNINITIALIZED"; | |
2713 case SMI: | |
2714 return "SMI"; | |
2715 case NUMBER: | |
2716 return "NUMBER"; | |
2717 case INTERNALIZED_STRING: | |
2718 return "INTERNALIZED_STRING"; | |
2719 case STRING: | |
2720 return "STRING"; | |
2721 case UNIQUE_NAME: | |
2722 return "UNIQUE_NAME"; | |
2723 case OBJECT: | |
2724 return "OBJECT"; | |
2725 case KNOWN_OBJECT: | |
2726 return "KNOWN_OBJECT"; | |
2727 case GENERIC: | |
2728 return "GENERIC"; | |
2729 } | |
2730 UNREACHABLE(); | |
2731 return NULL; | |
2732 } | |
2733 | |
2734 | |
2735 Type* CompareIC::StateToType(Zone* zone, CompareIC::State state, | |
2736 Handle<Map> map) { | |
2737 switch (state) { | |
2738 case CompareIC::UNINITIALIZED: | |
2739 return Type::None(zone); | |
2740 case CompareIC::SMI: | |
2741 return Type::SignedSmall(zone); | |
2742 case CompareIC::NUMBER: | |
2743 return Type::Number(zone); | |
2744 case CompareIC::STRING: | |
2745 return Type::String(zone); | |
2746 case CompareIC::INTERNALIZED_STRING: | |
2747 return Type::InternalizedString(zone); | |
2748 case CompareIC::UNIQUE_NAME: | |
2749 return Type::UniqueName(zone); | |
2750 case CompareIC::OBJECT: | |
2751 return Type::Receiver(zone); | |
2752 case CompareIC::KNOWN_OBJECT: | |
2753 return map.is_null() ? Type::Receiver(zone) : Type::Class(map, zone); | |
2754 case CompareIC::GENERIC: | |
2755 return Type::Any(zone); | |
2756 } | |
2757 UNREACHABLE(); | |
2758 return NULL; | |
2759 } | |
2760 | |
2761 | |
2762 CompareIC::State CompareIC::NewInputState(State old_state, | |
2763 Handle<Object> value) { | |
2764 switch (old_state) { | |
2765 case UNINITIALIZED: | |
2766 if (value->IsSmi()) return SMI; | |
2767 if (value->IsHeapNumber()) return NUMBER; | |
2768 if (value->IsInternalizedString()) return INTERNALIZED_STRING; | |
2769 if (value->IsString()) return STRING; | |
2770 if (value->IsSymbol()) return UNIQUE_NAME; | |
2771 if (value->IsJSObject()) return OBJECT; | |
2772 break; | |
2773 case SMI: | |
2774 if (value->IsSmi()) return SMI; | |
2775 if (value->IsHeapNumber()) return NUMBER; | |
2776 break; | |
2777 case NUMBER: | |
2778 if (value->IsNumber()) return NUMBER; | |
2779 break; | |
2780 case INTERNALIZED_STRING: | |
2781 if (value->IsInternalizedString()) return INTERNALIZED_STRING; | |
2782 if (value->IsString()) return STRING; | |
2783 if (value->IsSymbol()) return UNIQUE_NAME; | |
2784 break; | |
2785 case STRING: | |
2786 if (value->IsString()) return STRING; | |
2787 break; | |
2788 case UNIQUE_NAME: | |
2789 if (value->IsUniqueName()) return UNIQUE_NAME; | |
2790 break; | |
2791 case OBJECT: | |
2792 if (value->IsJSObject()) return OBJECT; | |
2793 break; | |
2794 case GENERIC: | |
2795 break; | |
2796 case KNOWN_OBJECT: | |
2797 UNREACHABLE(); | |
2798 break; | |
2799 } | |
2800 return GENERIC; | |
2801 } | |
2802 | |
2803 | |
2804 CompareIC::State CompareIC::TargetState(State old_state, State old_left, | |
2805 State old_right, | |
2806 bool has_inlined_smi_code, | |
2807 Handle<Object> x, Handle<Object> y) { | |
2808 switch (old_state) { | |
2809 case UNINITIALIZED: | |
2810 if (x->IsSmi() && y->IsSmi()) return SMI; | |
2811 if (x->IsNumber() && y->IsNumber()) return NUMBER; | |
2812 if (Token::IsOrderedRelationalCompareOp(op_)) { | |
2813 // Ordered comparisons treat undefined as NaN, so the | |
2814 // NUMBER stub will do the right thing. | |
2815 if ((x->IsNumber() && y->IsUndefined()) || | |
2816 (y->IsNumber() && x->IsUndefined())) { | |
2817 return NUMBER; | |
2818 } | |
2819 } | |
2820 if (x->IsInternalizedString() && y->IsInternalizedString()) { | |
2821 // We compare internalized strings as plain ones if we need to determine | |
2822 // the order in a non-equality compare. | |
2823 return Token::IsEqualityOp(op_) ? INTERNALIZED_STRING : STRING; | |
2824 } | |
2825 if (x->IsString() && y->IsString()) return STRING; | |
2826 if (!Token::IsEqualityOp(op_)) return GENERIC; | |
2827 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME; | |
2828 if (x->IsJSObject() && y->IsJSObject()) { | |
2829 if (Handle<JSObject>::cast(x)->map() == | |
2830 Handle<JSObject>::cast(y)->map()) { | |
2831 return KNOWN_OBJECT; | |
2832 } else { | |
2833 return OBJECT; | |
2834 } | |
2835 } | |
2836 return GENERIC; | |
2837 case SMI: | |
2838 return x->IsNumber() && y->IsNumber() ? NUMBER : GENERIC; | |
2839 case INTERNALIZED_STRING: | |
2840 DCHECK(Token::IsEqualityOp(op_)); | |
2841 if (x->IsString() && y->IsString()) return STRING; | |
2842 if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME; | |
2843 return GENERIC; | |
2844 case NUMBER: | |
2845 // If the failure was due to one side changing from smi to heap number, | |
2846 // then keep the state (if other changed at the same time, we will get | |
2847 // a second miss and then go to generic). | |
2848 if (old_left == SMI && x->IsHeapNumber()) return NUMBER; | |
2849 if (old_right == SMI && y->IsHeapNumber()) return NUMBER; | |
2850 return GENERIC; | |
2851 case KNOWN_OBJECT: | |
2852 DCHECK(Token::IsEqualityOp(op_)); | |
2853 if (x->IsJSObject() && y->IsJSObject()) return OBJECT; | |
2854 return GENERIC; | |
2855 case STRING: | |
2856 case UNIQUE_NAME: | |
2857 case OBJECT: | |
2858 case GENERIC: | |
2859 return GENERIC; | |
2860 } | |
2861 UNREACHABLE(); | |
2862 return GENERIC; // Make the compiler happy. | |
2863 } | |
2864 | |
2865 | |
2866 Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { | 2274 Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { |
2867 HandleScope scope(isolate()); | 2275 HandleScope scope(isolate()); |
2868 CompareICStub old_stub(target()->stub_key(), isolate()); | 2276 CompareICStub old_stub(target()->stub_key(), isolate()); |
2869 State new_left = NewInputState(old_stub.left(), x); | 2277 CompareICState::State new_left = |
2870 State new_right = NewInputState(old_stub.right(), y); | 2278 CompareICState::NewInputState(old_stub.left(), x); |
2871 State state = TargetState(old_stub.state(), old_stub.left(), old_stub.right(), | 2279 CompareICState::State new_right = |
2872 HasInlinedSmiCode(address()), x, y); | 2280 CompareICState::NewInputState(old_stub.right(), y); |
| 2281 CompareICState::State state = CompareICState::TargetState( |
| 2282 old_stub.state(), old_stub.left(), old_stub.right(), op_, |
| 2283 HasInlinedSmiCode(address()), x, y); |
2873 CompareICStub stub(isolate(), op_, new_left, new_right, state); | 2284 CompareICStub stub(isolate(), op_, new_left, new_right, state); |
2874 if (state == KNOWN_OBJECT) { | 2285 if (state == CompareICState::KNOWN_OBJECT) { |
2875 stub.set_known_map( | 2286 stub.set_known_map( |
2876 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate())); | 2287 Handle<Map>(Handle<JSObject>::cast(x)->map(), isolate())); |
2877 } | 2288 } |
2878 Handle<Code> new_target = stub.GetCode(); | 2289 Handle<Code> new_target = stub.GetCode(); |
2879 set_target(*new_target); | 2290 set_target(*new_target); |
2880 | 2291 |
2881 if (FLAG_trace_ic) { | 2292 if (FLAG_trace_ic) { |
2882 PrintF("[CompareIC in "); | 2293 PrintF("[CompareIC in "); |
2883 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); | 2294 JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
2884 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", | 2295 PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", |
2885 GetStateName(old_stub.left()), GetStateName(old_stub.right()), | 2296 CompareICState::GetStateName(old_stub.left()), |
2886 GetStateName(old_stub.state()), GetStateName(new_left), | 2297 CompareICState::GetStateName(old_stub.right()), |
2887 GetStateName(new_right), GetStateName(state), Token::Name(op_), | 2298 CompareICState::GetStateName(old_stub.state()), |
| 2299 CompareICState::GetStateName(new_left), |
| 2300 CompareICState::GetStateName(new_right), |
| 2301 CompareICState::GetStateName(state), Token::Name(op_), |
2888 static_cast<void*>(*stub.GetCode())); | 2302 static_cast<void*>(*stub.GetCode())); |
2889 } | 2303 } |
2890 | 2304 |
2891 // Activate inlined smi code. | 2305 // Activate inlined smi code. |
2892 if (old_stub.state() == UNINITIALIZED) { | 2306 if (old_stub.state() == CompareICState::UNINITIALIZED) { |
2893 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); | 2307 PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); |
2894 } | 2308 } |
2895 | 2309 |
2896 return *new_target; | 2310 return *new_target; |
2897 } | 2311 } |
2898 | 2312 |
2899 | 2313 |
2900 // Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc. | 2314 // Used from CompareICStub::GenerateMiss in code-stubs-<arch>.cc. |
2901 RUNTIME_FUNCTION(CompareIC_Miss) { | 2315 RUNTIME_FUNCTION(CompareIC_Miss) { |
2902 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2316 TimerEventScope<TimerEventIcMiss> timer(isolate); |
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3205 static const Address IC_utilities[] = { | 2619 static const Address IC_utilities[] = { |
3206 #define ADDR(name) FUNCTION_ADDR(name), | 2620 #define ADDR(name) FUNCTION_ADDR(name), |
3207 IC_UTIL_LIST(ADDR) NULL | 2621 IC_UTIL_LIST(ADDR) NULL |
3208 #undef ADDR | 2622 #undef ADDR |
3209 }; | 2623 }; |
3210 | 2624 |
3211 | 2625 |
3212 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; } | 2626 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; } |
3213 } | 2627 } |
3214 } // namespace v8::internal | 2628 } // namespace v8::internal |
OLD | NEW |