| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "accessors.h" | 30 #include "accessors.h" |
| 31 #include "api.h" | 31 #include "api.h" |
| 32 #include "arguments.h" | 32 #include "arguments.h" |
| 33 #include "codegen.h" |
| 33 #include "execution.h" | 34 #include "execution.h" |
| 34 #include "ic-inl.h" | 35 #include "ic-inl.h" |
| 35 #include "runtime.h" | 36 #include "runtime.h" |
| 36 #include "stub-cache.h" | 37 #include "stub-cache.h" |
| 37 | 38 |
| 38 namespace v8 { | 39 namespace v8 { |
| 39 namespace internal { | 40 namespace internal { |
| 40 | 41 |
| 41 #ifdef DEBUG | 42 #ifdef DEBUG |
| 42 static char TransitionMarkFromState(IC::State state) { | 43 static char TransitionMarkFromState(IC::State state) { |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 } | 152 } |
| 152 } | 153 } |
| 153 | 154 |
| 154 return false; | 155 return false; |
| 155 } | 156 } |
| 156 | 157 |
| 157 | 158 |
| 158 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { | 159 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { |
| 159 IC::State state = target->ic_state(); | 160 IC::State state = target->ic_state(); |
| 160 | 161 |
| 161 if (state != MONOMORPHIC) return state; | 162 if (state != MONOMORPHIC || !name->IsString()) return state; |
| 162 if (receiver->IsUndefined() || receiver->IsNull()) return state; | 163 if (receiver->IsUndefined() || receiver->IsNull()) return state; |
| 163 | 164 |
| 164 InlineCacheHolderFlag cache_holder = | 165 InlineCacheHolderFlag cache_holder = |
| 165 Code::ExtractCacheHolderFromFlags(target->flags()); | 166 Code::ExtractCacheHolderFromFlags(target->flags()); |
| 166 | 167 |
| 167 | 168 |
| 168 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { | 169 if (cache_holder == OWN_MAP && !receiver->IsJSObject()) { |
| 169 // The stub was generated for JSObject but called for non-JSObject. | 170 // The stub was generated for JSObject but called for non-JSObject. |
| 170 // IC::GetCodeCacheHolder is not applicable. | 171 // IC::GetCodeCacheHolder is not applicable. |
| 171 return MONOMORPHIC; | 172 return MONOMORPHIC; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 // Don't clear debug break inline cache as it will remove the break point. | 255 // Don't clear debug break inline cache as it will remove the break point. |
| 255 if (target->ic_state() == DEBUG_BREAK) return; | 256 if (target->ic_state() == DEBUG_BREAK) return; |
| 256 | 257 |
| 257 switch (target->kind()) { | 258 switch (target->kind()) { |
| 258 case Code::LOAD_IC: return LoadIC::Clear(address, target); | 259 case Code::LOAD_IC: return LoadIC::Clear(address, target); |
| 259 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); | 260 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); |
| 260 case Code::STORE_IC: return StoreIC::Clear(address, target); | 261 case Code::STORE_IC: return StoreIC::Clear(address, target); |
| 261 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); | 262 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); |
| 262 case Code::CALL_IC: return CallIC::Clear(address, target); | 263 case Code::CALL_IC: return CallIC::Clear(address, target); |
| 263 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); | 264 case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); |
| 264 case Code::BINARY_OP_IC: return; // Clearing these is tricky and does not | 265 case Code::BINARY_OP_IC: |
| 265 // make any performance difference. | 266 case Code::TYPE_RECORDING_BINARY_OP_IC: |
| 267 case Code::COMPARE_IC: |
| 268 // Clearing these is tricky and does not |
| 269 // make any performance difference. |
| 270 return; |
| 266 default: UNREACHABLE(); | 271 default: UNREACHABLE(); |
| 267 } | 272 } |
| 268 } | 273 } |
| 269 | 274 |
| 270 | 275 |
| 271 void CallICBase::Clear(Address address, Code* target) { | 276 void CallICBase::Clear(Address address, Code* target) { |
| 272 State state = target->ic_state(); | 277 State state = target->ic_state(); |
| 273 if (state == UNINITIALIZED) return; | 278 if (state == UNINITIALIZED) return; |
| 274 Code* code = | 279 Code* code = |
| 275 Isolate::Current()->stub_cache()->FindCallInitialize( | 280 Isolate::Current()->stub_cache()->FindCallInitialize( |
| (...skipping 884 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1160 if (use_ic) { | 1165 if (use_ic) { |
| 1161 Code* stub = generic_stub(); | 1166 Code* stub = generic_stub(); |
| 1162 if (object->IsString() && key->IsNumber()) { | 1167 if (object->IsString() && key->IsNumber()) { |
| 1163 stub = string_stub(); | 1168 stub = string_stub(); |
| 1164 } else if (object->IsJSObject()) { | 1169 } else if (object->IsJSObject()) { |
| 1165 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1170 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1166 if (receiver->HasExternalArrayElements()) { | 1171 if (receiver->HasExternalArrayElements()) { |
| 1167 stub = external_array_stub(receiver->GetElementsKind()); | 1172 stub = external_array_stub(receiver->GetElementsKind()); |
| 1168 } else if (receiver->HasIndexedInterceptor()) { | 1173 } else if (receiver->HasIndexedInterceptor()) { |
| 1169 stub = indexed_interceptor_stub(); | 1174 stub = indexed_interceptor_stub(); |
| 1175 } else if (state == UNINITIALIZED && |
| 1176 key->IsSmi() && |
| 1177 receiver->map()->has_fast_elements()) { |
| 1178 StubCache* stub_cache = isolate()->stub_cache(); |
| 1179 MaybeObject* probe = stub_cache->ComputeKeyedLoadSpecialized(*receiver); |
| 1180 stub = |
| 1181 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1170 } | 1182 } |
| 1171 } | 1183 } |
| 1172 set_target(stub); | 1184 if (stub != NULL) set_target(stub); |
| 1185 |
| 1186 #ifdef DEBUG |
| 1187 TraceIC("KeyedLoadIC", key, state, target()); |
| 1188 #endif // DEBUG |
| 1189 |
| 1173 // For JSObjects with fast elements that are not value wrappers | 1190 // For JSObjects with fast elements that are not value wrappers |
| 1174 // and that do not have indexed interceptors, we initialize the | 1191 // and that do not have indexed interceptors, we initialize the |
| 1175 // inlined fast case (if present) by patching the inlined map | 1192 // inlined fast case (if present) by patching the inlined map |
| 1176 // check. | 1193 // check. |
| 1177 if (object->IsJSObject() && | 1194 if (object->IsJSObject() && |
| 1178 !object->IsJSValue() && | 1195 !object->IsJSValue() && |
| 1179 !JSObject::cast(*object)->HasIndexedInterceptor() && | 1196 !JSObject::cast(*object)->HasIndexedInterceptor() && |
| 1180 JSObject::cast(*object)->HasFastElements()) { | 1197 JSObject::cast(*object)->HasFastElements()) { |
| 1181 Map* map = JSObject::cast(*object)->map(); | 1198 Map* map = JSObject::cast(*object)->map(); |
| 1182 PatchInlinedLoad(address(), map); | 1199 PatchInlinedLoad(address(), map); |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1382 } | 1399 } |
| 1383 } | 1400 } |
| 1384 } | 1401 } |
| 1385 | 1402 |
| 1386 // If no inlined store ic was patched, generate a stub for this | 1403 // If no inlined store ic was patched, generate a stub for this |
| 1387 // store. | 1404 // store. |
| 1388 UpdateCaches(&lookup, state, receiver, name, value); | 1405 UpdateCaches(&lookup, state, receiver, name, value); |
| 1389 } | 1406 } |
| 1390 } | 1407 } |
| 1391 | 1408 |
| 1409 if (receiver->IsJSGlobalProxy()) { |
| 1410 // Generate a generic stub that goes to the runtime when we see a global |
| 1411 // proxy as receiver. |
| 1412 if (target() != global_proxy_stub()) { |
| 1413 set_target(global_proxy_stub()); |
| 1414 #ifdef DEBUG |
| 1415 TraceIC("StoreIC", name, state, target()); |
| 1416 #endif |
| 1417 } |
| 1418 } |
| 1419 |
| 1392 // Set the property. | 1420 // Set the property. |
| 1393 return receiver->SetProperty(*name, *value, NONE); | 1421 return receiver->SetProperty(*name, *value, NONE); |
| 1394 } | 1422 } |
| 1395 | 1423 |
| 1396 | 1424 |
| 1397 void StoreIC::UpdateCaches(LookupResult* lookup, | 1425 void StoreIC::UpdateCaches(LookupResult* lookup, |
| 1398 State state, | 1426 State state, |
| 1399 Handle<JSObject> receiver, | 1427 Handle<JSObject> receiver, |
| 1400 Handle<String> name, | 1428 Handle<String> name, |
| 1401 Handle<Object> value) { | 1429 Handle<Object> value) { |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1531 // the global object). | 1559 // the global object). |
| 1532 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); | 1560 bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); |
| 1533 ASSERT(!(use_ic && object->IsJSGlobalProxy())); | 1561 ASSERT(!(use_ic && object->IsJSGlobalProxy())); |
| 1534 | 1562 |
| 1535 if (use_ic) { | 1563 if (use_ic) { |
| 1536 Code* stub = generic_stub(); | 1564 Code* stub = generic_stub(); |
| 1537 if (object->IsJSObject()) { | 1565 if (object->IsJSObject()) { |
| 1538 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1566 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 1539 if (receiver->HasExternalArrayElements()) { | 1567 if (receiver->HasExternalArrayElements()) { |
| 1540 stub = external_array_stub(receiver->GetElementsKind()); | 1568 stub = external_array_stub(receiver->GetElementsKind()); |
| 1569 } else if (state == UNINITIALIZED && |
| 1570 key->IsSmi() && |
| 1571 receiver->map()->has_fast_elements()) { |
| 1572 MaybeObject* probe = |
| 1573 isolate()->stub_cache()->ComputeKeyedStoreSpecialized(*receiver); |
| 1574 stub = |
| 1575 probe->IsFailure() ? NULL : Code::cast(probe->ToObjectUnchecked()); |
| 1541 } | 1576 } |
| 1542 } | 1577 } |
| 1543 set_target(stub); | 1578 if (stub != NULL) set_target(stub); |
| 1544 } | 1579 } |
| 1545 | 1580 |
| 1546 // Set the property. | 1581 // Set the property. |
| 1547 return Runtime::SetObjectProperty(isolate(), object, key, value, NONE); | 1582 return Runtime::SetObjectProperty(isolate(), object, key, value, NONE); |
| 1548 } | 1583 } |
| 1549 | 1584 |
| 1550 | 1585 |
| 1551 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, | 1586 void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
| 1552 State state, | 1587 State state, |
| 1553 Handle<JSObject> receiver, | 1588 Handle<JSObject> receiver, |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1787 } | 1822 } |
| 1788 | 1823 |
| 1789 | 1824 |
| 1790 void BinaryOpIC::patch(Code* code) { | 1825 void BinaryOpIC::patch(Code* code) { |
| 1791 set_target(code); | 1826 set_target(code); |
| 1792 } | 1827 } |
| 1793 | 1828 |
| 1794 | 1829 |
| 1795 const char* BinaryOpIC::GetName(TypeInfo type_info) { | 1830 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| 1796 switch (type_info) { | 1831 switch (type_info) { |
| 1832 case UNINIT_OR_SMI: return "UninitOrSmi"; |
| 1797 case DEFAULT: return "Default"; | 1833 case DEFAULT: return "Default"; |
| 1798 case GENERIC: return "Generic"; | 1834 case GENERIC: return "Generic"; |
| 1799 case HEAP_NUMBERS: return "HeapNumbers"; | 1835 case HEAP_NUMBERS: return "HeapNumbers"; |
| 1800 case STRINGS: return "Strings"; | 1836 case STRINGS: return "Strings"; |
| 1801 default: return "Invalid"; | 1837 default: return "Invalid"; |
| 1802 } | 1838 } |
| 1803 } | 1839 } |
| 1804 | 1840 |
| 1805 | 1841 |
| 1806 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { | 1842 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { |
| 1807 switch (type_info) { | 1843 switch (type_info) { |
| 1808 // DEFAULT is mapped to UNINITIALIZED so that calls to DEFAULT stubs | 1844 case UNINIT_OR_SMI: |
| 1809 // are not cleared at GC. | 1845 return UNINITIALIZED; |
| 1810 case DEFAULT: return UNINITIALIZED; | 1846 case DEFAULT: |
| 1811 | 1847 case HEAP_NUMBERS: |
| 1812 // Could have mapped GENERIC to MONOMORPHIC just as well but MEGAMORPHIC is | 1848 case STRINGS: |
| 1813 // conceptually closer. | 1849 return MONOMORPHIC; |
| 1814 case GENERIC: return MEGAMORPHIC; | 1850 case GENERIC: |
| 1815 | 1851 return MEGAMORPHIC; |
| 1816 default: return MONOMORPHIC; | |
| 1817 } | 1852 } |
| 1853 UNREACHABLE(); |
| 1854 return UNINITIALIZED; |
| 1818 } | 1855 } |
| 1819 | 1856 |
| 1820 | 1857 |
| 1821 BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Object* left, | 1858 BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Object* left, |
| 1822 Object* right) { | 1859 Object* right) { |
| 1823 if (left->IsSmi() && right->IsSmi()) { | 1860 if (left->IsSmi() && right->IsSmi()) { |
| 1824 return GENERIC; | 1861 // If we have two smi inputs we can reach here because |
| 1862 // of an overflow. Enter default state. |
| 1863 return DEFAULT; |
| 1825 } | 1864 } |
| 1826 | 1865 |
| 1827 if (left->IsNumber() && right->IsNumber()) { | 1866 if (left->IsNumber() && right->IsNumber()) { |
| 1828 return HEAP_NUMBERS; | 1867 return HEAP_NUMBERS; |
| 1829 } | 1868 } |
| 1830 | 1869 |
| 1831 if (left->IsString() || right->IsString()) { | 1870 if (left->IsString() || right->IsString()) { |
| 1832 // Patching for fast string ADD makes sense even if only one of the | 1871 // Patching for fast string ADD makes sense even if only one of the |
| 1833 // arguments is a string. | 1872 // arguments is a string. |
| 1834 return STRINGS; | 1873 return STRINGS; |
| 1835 } | 1874 } |
| 1836 | 1875 |
| 1837 return GENERIC; | 1876 return GENERIC; |
| 1838 } | 1877 } |
| 1839 | 1878 |
| 1840 | 1879 |
| 1841 // defined in codegen-<arch>.cc | 1880 // defined in code-stubs-<arch>.cc |
| 1842 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info); | 1881 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info); |
| 1843 | 1882 |
| 1844 | 1883 |
| 1845 MUST_USE_RESULT MaybeObject* BinaryOp_Patch(RUNTIME_CALLING_CONVENTION) { | 1884 MUST_USE_RESULT MaybeObject* BinaryOp_Patch(RUNTIME_CALLING_CONVENTION) { |
| 1846 RUNTIME_GET_ISOLATE; | 1885 RUNTIME_GET_ISOLATE; |
| 1847 ASSERT(args.length() == 5); | 1886 ASSERT(args.length() == 5); |
| 1848 | 1887 |
| 1888 HandleScope scope; |
| 1849 Handle<Object> left = args.at<Object>(0); | 1889 Handle<Object> left = args.at<Object>(0); |
| 1850 Handle<Object> right = args.at<Object>(1); | 1890 Handle<Object> right = args.at<Object>(1); |
| 1851 int key = Smi::cast(args[2])->value(); | 1891 int key = Smi::cast(args[2])->value(); |
| 1852 Token::Value op = static_cast<Token::Value>(Smi::cast(args[3])->value()); | 1892 Token::Value op = static_cast<Token::Value>(Smi::cast(args[3])->value()); |
| 1853 #ifdef DEBUG | 1893 BinaryOpIC::TypeInfo previous_type = |
| 1854 BinaryOpIC::TypeInfo prev_type_info = | |
| 1855 static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[4])->value()); | 1894 static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[4])->value()); |
| 1856 #endif // DEBUG | 1895 |
| 1857 { HandleScope scope; | 1896 BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(*left, *right); |
| 1858 BinaryOpIC::TypeInfo type_info = BinaryOpIC::GetTypeInfo(*left, *right); | 1897 Handle<Code> code = GetBinaryOpStub(key, type); |
| 1859 Handle<Code> code = GetBinaryOpStub(key, type_info); | 1898 if (!code.is_null()) { |
| 1860 if (!code.is_null()) { | 1899 BinaryOpIC ic(isolate); |
| 1861 BinaryOpIC ic(isolate); | 1900 ic.patch(*code); |
| 1862 ic.patch(*code); | 1901 if (FLAG_trace_ic) { |
| 1863 #ifdef DEBUG | 1902 PrintF("[BinaryOpIC (%s->%s)#%s]\n", |
| 1864 if (FLAG_trace_ic) { | 1903 BinaryOpIC::GetName(previous_type), |
| 1865 PrintF("[BinaryOpIC (%s->%s)#%s]\n", | 1904 BinaryOpIC::GetName(type), |
| 1866 BinaryOpIC::GetName(prev_type_info), | 1905 Token::Name(op)); |
| 1867 BinaryOpIC::GetName(type_info), | |
| 1868 Token::Name(op)); | |
| 1869 } | |
| 1870 #endif // DEBUG | |
| 1871 } | 1906 } |
| 1872 } | 1907 } |
| 1873 | 1908 |
| 1874 HandleScope scope; | |
| 1875 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( | 1909 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( |
| 1876 isolate->thread_local_top()->context_->builtins()); | 1910 isolate->thread_local_top()->context_->builtins()); |
| 1877 | |
| 1878 Object* builtin = NULL; // Initialization calms down the compiler. | 1911 Object* builtin = NULL; // Initialization calms down the compiler. |
| 1879 | |
| 1880 switch (op) { | 1912 switch (op) { |
| 1881 case Token::ADD: | 1913 case Token::ADD: |
| 1882 builtin = builtins->javascript_builtin(Builtins::ADD); | 1914 builtin = builtins->javascript_builtin(Builtins::ADD); |
| 1915 break; |
| 1916 case Token::SUB: |
| 1917 builtin = builtins->javascript_builtin(Builtins::SUB); |
| 1918 break; |
| 1919 case Token::MUL: |
| 1920 builtin = builtins->javascript_builtin(Builtins::MUL); |
| 1921 break; |
| 1922 case Token::DIV: |
| 1923 builtin = builtins->javascript_builtin(Builtins::DIV); |
| 1924 break; |
| 1925 case Token::MOD: |
| 1926 builtin = builtins->javascript_builtin(Builtins::MOD); |
| 1927 break; |
| 1928 case Token::BIT_AND: |
| 1929 builtin = builtins->javascript_builtin(Builtins::BIT_AND); |
| 1930 break; |
| 1931 case Token::BIT_OR: |
| 1932 builtin = builtins->javascript_builtin(Builtins::BIT_OR); |
| 1933 break; |
| 1934 case Token::BIT_XOR: |
| 1935 builtin = builtins->javascript_builtin(Builtins::BIT_XOR); |
| 1936 break; |
| 1937 case Token::SHR: |
| 1938 builtin = builtins->javascript_builtin(Builtins::SHR); |
| 1939 break; |
| 1940 case Token::SAR: |
| 1941 builtin = builtins->javascript_builtin(Builtins::SAR); |
| 1942 break; |
| 1943 case Token::SHL: |
| 1944 builtin = builtins->javascript_builtin(Builtins::SHL); |
| 1945 break; |
| 1946 default: |
| 1947 UNREACHABLE(); |
| 1948 } |
| 1949 |
| 1950 Handle<JSFunction> builtin_function(JSFunction::cast(builtin)); |
| 1951 |
| 1952 bool caught_exception; |
| 1953 Object** builtin_args[] = { right.location() }; |
| 1954 Handle<Object> result = Execution::Call(builtin_function, |
| 1955 left, |
| 1956 ARRAY_SIZE(builtin_args), |
| 1957 builtin_args, |
| 1958 &caught_exception); |
| 1959 if (caught_exception) { |
| 1960 return Failure::Exception(); |
| 1961 } |
| 1962 return *result; |
| 1963 } |
| 1964 |
| 1965 |
| 1966 void TRBinaryOpIC::patch(Code* code) { |
| 1967 set_target(code); |
| 1968 } |
| 1969 |
| 1970 |
| 1971 const char* TRBinaryOpIC::GetName(TypeInfo type_info) { |
| 1972 switch (type_info) { |
| 1973 case UNINITIALIZED: return "Uninitialized"; |
| 1974 case SMI: return "SMI"; |
| 1975 case INT32: return "Int32s"; |
| 1976 case HEAP_NUMBER: return "HeapNumbers"; |
| 1977 case STRING: return "Strings"; |
| 1978 case GENERIC: return "Generic"; |
| 1979 default: return "Invalid"; |
| 1980 } |
| 1981 } |
| 1982 |
| 1983 |
| 1984 TRBinaryOpIC::State TRBinaryOpIC::ToState(TypeInfo type_info) { |
| 1985 switch (type_info) { |
| 1986 case UNINITIALIZED: |
| 1987 return ::v8::internal::UNINITIALIZED; |
| 1988 case SMI: |
| 1989 case INT32: |
| 1990 case HEAP_NUMBER: |
| 1991 case STRING: |
| 1992 return MONOMORPHIC; |
| 1993 case GENERIC: |
| 1994 return MEGAMORPHIC; |
| 1995 } |
| 1996 UNREACHABLE(); |
| 1997 return ::v8::internal::UNINITIALIZED; |
| 1998 } |
| 1999 |
| 2000 |
| 2001 TRBinaryOpIC::TypeInfo TRBinaryOpIC::JoinTypes(TRBinaryOpIC::TypeInfo x, |
| 2002 TRBinaryOpIC::TypeInfo y) { |
| 2003 if (x == UNINITIALIZED) return y; |
| 2004 if (y == UNINITIALIZED) return x; |
| 2005 if (x == STRING && y == STRING) return STRING; |
| 2006 if (x == STRING || y == STRING) return GENERIC; |
| 2007 if (x >= y) return x; |
| 2008 return y; |
| 2009 } |
| 2010 |
| 2011 TRBinaryOpIC::TypeInfo TRBinaryOpIC::GetTypeInfo(Handle<Object> left, |
| 2012 Handle<Object> right) { |
| 2013 ::v8::internal::TypeInfo left_type = |
| 2014 ::v8::internal::TypeInfo::TypeFromValue(left); |
| 2015 ::v8::internal::TypeInfo right_type = |
| 2016 ::v8::internal::TypeInfo::TypeFromValue(right); |
| 2017 |
| 2018 if (left_type.IsSmi() && right_type.IsSmi()) { |
| 2019 return SMI; |
| 2020 } |
| 2021 |
| 2022 if (left_type.IsInteger32() && right_type.IsInteger32()) { |
| 2023 return INT32; |
| 2024 } |
| 2025 |
| 2026 if (left_type.IsNumber() && right_type.IsNumber()) { |
| 2027 return HEAP_NUMBER; |
| 2028 } |
| 2029 |
| 2030 if (left_type.IsString() || right_type.IsString()) { |
| 2031 // Patching for fast string ADD makes sense even if only one of the |
| 2032 // arguments is a string. |
| 2033 return STRING; |
| 2034 } |
| 2035 |
| 2036 return GENERIC; |
| 2037 } |
| 2038 |
| 2039 |
| 2040 // defined in code-stubs-<arch>.cc |
| 2041 // Only needed to remove dependency of ic.cc on code-stubs-<arch>.h. |
| 2042 Handle<Code> GetTypeRecordingBinaryOpStub(int key, |
| 2043 TRBinaryOpIC::TypeInfo type_info, |
| 2044 TRBinaryOpIC::TypeInfo result_type); |
| 2045 |
| 2046 |
| 2047 MaybeObject* TypeRecordingBinaryOp_Patch(RUNTIME_CALLING_CONVENTION) { |
| 2048 RUNTIME_GET_ISOLATE; |
| 2049 ASSERT(args.length() == 5); |
| 2050 |
| 2051 HandleScope scope(isolate); |
| 2052 Handle<Object> left = args.at<Object>(0); |
| 2053 Handle<Object> right = args.at<Object>(1); |
| 2054 int key = Smi::cast(args[2])->value(); |
| 2055 Token::Value op = static_cast<Token::Value>(Smi::cast(args[3])->value()); |
| 2056 TRBinaryOpIC::TypeInfo previous_type = |
| 2057 static_cast<TRBinaryOpIC::TypeInfo>(Smi::cast(args[4])->value()); |
| 2058 |
| 2059 TRBinaryOpIC::TypeInfo type = TRBinaryOpIC::GetTypeInfo(left, right); |
| 2060 type = TRBinaryOpIC::JoinTypes(type, previous_type); |
| 2061 TRBinaryOpIC::TypeInfo result_type = TRBinaryOpIC::UNINITIALIZED; |
| 2062 if (type == TRBinaryOpIC::STRING && op != Token::ADD) { |
| 2063 type = TRBinaryOpIC::GENERIC; |
| 2064 } |
| 2065 if (type == TRBinaryOpIC::SMI && |
| 2066 previous_type == TRBinaryOpIC::SMI) { |
| 2067 if (op == Token::DIV || op == Token::MUL) { |
| 2068 // Arithmetic on two Smi inputs has yielded a heap number. |
| 2069 // That is the only way to get here from the Smi stub. |
| 2070 result_type = TRBinaryOpIC::HEAP_NUMBER; |
| 2071 } else { |
| 2072 // Other operations on SMIs that overflow yield int32s. |
| 2073 result_type = TRBinaryOpIC::INT32; |
| 2074 } |
| 2075 } |
| 2076 if (type == TRBinaryOpIC::INT32 && |
| 2077 previous_type == TRBinaryOpIC::INT32) { |
| 2078 // We must be here because an operation on two INT32 types overflowed. |
| 2079 result_type = TRBinaryOpIC::HEAP_NUMBER; |
| 2080 } |
| 2081 |
| 2082 Handle<Code> code = GetTypeRecordingBinaryOpStub(key, type, result_type); |
| 2083 if (!code.is_null()) { |
| 2084 TRBinaryOpIC ic(isolate); |
| 2085 ic.patch(*code); |
| 2086 if (FLAG_trace_ic) { |
| 2087 PrintF("[TypeRecordingBinaryOpIC (%s->(%s->%s))#%s]\n", |
| 2088 TRBinaryOpIC::GetName(previous_type), |
| 2089 TRBinaryOpIC::GetName(type), |
| 2090 TRBinaryOpIC::GetName(result_type), |
| 2091 Token::Name(op)); |
| 2092 } |
| 2093 } |
| 2094 |
| 2095 Handle<JSBuiltinsObject> builtins = Handle<JSBuiltinsObject>( |
| 2096 isolate->thread_local_top()->context_->builtins()); |
| 2097 Object* builtin = NULL; // Initialization calms down the compiler. |
| 2098 switch (op) { |
| 2099 case Token::ADD: |
| 2100 builtin = builtins->javascript_builtin(Builtins::ADD); |
| 1883 break; | 2101 break; |
| 1884 case Token::SUB: | 2102 case Token::SUB: |
| 1885 builtin = builtins->javascript_builtin(Builtins::SUB); | 2103 builtin = builtins->javascript_builtin(Builtins::SUB); |
| 1886 break; | 2104 break; |
| 1887 case Token::MUL: | 2105 case Token::MUL: |
| 1888 builtin = builtins->javascript_builtin(Builtins::MUL); | 2106 builtin = builtins->javascript_builtin(Builtins::MUL); |
| 1889 break; | 2107 break; |
| 1890 case Token::DIV: | 2108 case Token::DIV: |
| 1891 builtin = builtins->javascript_builtin(Builtins::DIV); | 2109 builtin = builtins->javascript_builtin(Builtins::DIV); |
| 1892 break; | 2110 break; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1924 ARRAY_SIZE(builtin_args), | 2142 ARRAY_SIZE(builtin_args), |
| 1925 builtin_args, | 2143 builtin_args, |
| 1926 &caught_exception); | 2144 &caught_exception); |
| 1927 if (caught_exception) { | 2145 if (caught_exception) { |
| 1928 return Failure::Exception(); | 2146 return Failure::Exception(); |
| 1929 } | 2147 } |
| 1930 return *result; | 2148 return *result; |
| 1931 } | 2149 } |
| 1932 | 2150 |
| 1933 | 2151 |
| 2152 Handle<Code> CompareIC::GetUninitialized(Token::Value op) { |
| 2153 ICCompareStub stub(op, UNINITIALIZED); |
| 2154 return stub.GetCode(); |
| 2155 } |
| 2156 |
| 2157 |
| 2158 CompareIC::State CompareIC::ComputeState(Code* target) { |
| 2159 int key = target->major_key(); |
| 2160 if (key == CodeStub::Compare) return GENERIC; |
| 2161 ASSERT(key == CodeStub::CompareIC); |
| 2162 return static_cast<State>(target->compare_state()); |
| 2163 } |
| 2164 |
| 2165 |
| 2166 const char* CompareIC::GetStateName(State state) { |
| 2167 switch (state) { |
| 2168 case UNINITIALIZED: return "UNINITIALIZED"; |
| 2169 case SMIS: return "SMIS"; |
| 2170 case HEAP_NUMBERS: return "HEAP_NUMBERS"; |
| 2171 case OBJECTS: return "OBJECTS"; |
| 2172 case GENERIC: return "GENERIC"; |
| 2173 default: |
| 2174 UNREACHABLE(); |
| 2175 return NULL; |
| 2176 } |
| 2177 } |
| 2178 |
| 2179 |
| 2180 CompareIC::State CompareIC::TargetState(Handle<Object> x, Handle<Object> y) { |
| 2181 State state = GetState(); |
| 2182 if (state != UNINITIALIZED) return GENERIC; |
| 2183 if (x->IsSmi() && y->IsSmi()) return SMIS; |
| 2184 if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS; |
| 2185 if (op_ != Token::EQ && op_ != Token::EQ_STRICT) return GENERIC; |
| 2186 if (x->IsJSObject() && y->IsJSObject()) return OBJECTS; |
| 2187 return GENERIC; |
| 2188 } |
| 2189 |
| 2190 |
| 2191 // Used from ic_<arch>.cc. |
| 2192 Code* CompareIC_Miss(RUNTIME_CALLING_CONVENTION) { |
| 2193 RUNTIME_GET_ISOLATE; |
| 2194 NoHandleAllocation na; |
| 2195 ASSERT(args.length() == 3); |
| 2196 CompareIC ic(isolate, static_cast<Token::Value>(Smi::cast(args[2])->value())); |
| 2197 ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1)); |
| 2198 return ic.target(); |
| 2199 } |
| 2200 |
| 2201 |
| 1934 static const Address IC_utilities[] = { | 2202 static const Address IC_utilities[] = { |
| 1935 #define ADDR(name) FUNCTION_ADDR(name), | 2203 #define ADDR(name) FUNCTION_ADDR(name), |
| 1936 IC_UTIL_LIST(ADDR) | 2204 IC_UTIL_LIST(ADDR) |
| 1937 NULL | 2205 NULL |
| 1938 #undef ADDR | 2206 #undef ADDR |
| 1939 }; | 2207 }; |
| 1940 | 2208 |
| 1941 | 2209 |
| 1942 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2210 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 1943 return IC_utilities[id]; | 2211 return IC_utilities[id]; |
| 1944 } | 2212 } |
| 1945 | 2213 |
| 1946 | 2214 |
| 1947 } } // namespace v8::internal | 2215 } } // namespace v8::internal |
| OLD | NEW |