| 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 |