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 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 | 484 |
485 switch (target->kind()) { | 485 switch (target->kind()) { |
486 case Code::LOAD_IC: | 486 case Code::LOAD_IC: |
487 return LoadIC::Clear(isolate, address, target, constant_pool); | 487 return LoadIC::Clear(isolate, address, target, constant_pool); |
488 case Code::KEYED_LOAD_IC: | 488 case Code::KEYED_LOAD_IC: |
489 return KeyedLoadIC::Clear(isolate, address, target, constant_pool); | 489 return KeyedLoadIC::Clear(isolate, address, target, constant_pool); |
490 case Code::STORE_IC: | 490 case Code::STORE_IC: |
491 return StoreIC::Clear(isolate, address, target, constant_pool); | 491 return StoreIC::Clear(isolate, address, target, constant_pool); |
492 case Code::KEYED_STORE_IC: | 492 case Code::KEYED_STORE_IC: |
493 return KeyedStoreIC::Clear(isolate, address, target, constant_pool); | 493 return KeyedStoreIC::Clear(isolate, address, target, constant_pool); |
494 case Code::CALL_IC: | |
495 return CallIC::Clear(isolate, address, target, constant_pool); | |
496 case Code::COMPARE_IC: | 494 case Code::COMPARE_IC: |
497 return CompareIC::Clear(isolate, address, target, constant_pool); | 495 return CompareIC::Clear(isolate, address, target, constant_pool); |
498 case Code::COMPARE_NIL_IC: | 496 case Code::COMPARE_NIL_IC: |
499 return CompareNilIC::Clear(address, target, constant_pool); | 497 return CompareNilIC::Clear(address, target, constant_pool); |
| 498 case Code::CALL_IC: // CallICs are vector-based and cleared differently. |
500 case Code::BINARY_OP_IC: | 499 case Code::BINARY_OP_IC: |
501 case Code::TO_BOOLEAN_IC: | 500 case Code::TO_BOOLEAN_IC: |
502 // Clearing these is tricky and does not | 501 // Clearing these is tricky and does not |
503 // make any performance difference. | 502 // make any performance difference. |
504 return; | 503 return; |
505 default: | 504 default: |
506 UNREACHABLE(); | 505 UNREACHABLE(); |
507 } | 506 } |
508 } | 507 } |
509 | 508 |
510 | 509 |
| 510 void IC::Clear(Isolate* isolate, Code::Kind kind, Code* host, |
| 511 TypeFeedbackVector* vector, FeedbackVectorICSlot slot) { |
| 512 switch (kind) { |
| 513 case Code::CALL_IC: |
| 514 return CallIC::Clear(isolate, host, vector, slot); |
| 515 default: |
| 516 UNREACHABLE(); |
| 517 } |
| 518 } |
| 519 |
| 520 |
511 void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target, | 521 void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target, |
512 ConstantPoolArray* constant_pool) { | 522 ConstantPoolArray* constant_pool) { |
513 if (IsCleared(target)) return; | 523 if (IsCleared(target)) return; |
514 | 524 |
515 // Make sure to also clear the map used in inline fast cases. If we | 525 // Make sure to also clear the map used in inline fast cases. If we |
516 // do not clear these maps, cached code can keep objects alive | 526 // do not clear these maps, cached code can keep objects alive |
517 // through the embedded maps. | 527 // through the embedded maps. |
518 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate), constant_pool); | 528 SetTargetAtAddress(address, *pre_monomorphic_stub(isolate), constant_pool); |
519 } | 529 } |
520 | 530 |
521 | 531 |
522 void CallIC::Clear(Isolate* isolate, Address address, Code* target, | 532 void CallIC::Clear(Isolate* isolate, Code* host, TypeFeedbackVector* vector, |
523 ConstantPoolArray* constant_pool) { | 533 FeedbackVectorICSlot slot) { |
524 // Currently, CallIC doesn't have state changes. | 534 DCHECK(vector != NULL && !slot.IsInvalid()); |
| 535 Object* feedback = vector->Get(slot); |
| 536 // Determine our state. |
| 537 State state = FeedbackToState(isolate, vector, slot); |
| 538 |
| 539 if (state != UNINITIALIZED && !feedback->IsAllocationSite()) { |
| 540 vector->Set(slot, isolate->heap()->uninitialized_symbol(), |
| 541 SKIP_WRITE_BARRIER); |
| 542 // The change in state must be processed. |
| 543 OnTypeFeedbackChanged(isolate, host, vector, state, UNINITIALIZED); |
| 544 } |
525 } | 545 } |
526 | 546 |
527 | 547 |
528 void LoadIC::Clear(Isolate* isolate, Address address, Code* target, | 548 void LoadIC::Clear(Isolate* isolate, Address address, Code* target, |
529 ConstantPoolArray* constant_pool) { | 549 ConstantPoolArray* constant_pool) { |
530 if (IsCleared(target)) return; | 550 if (IsCleared(target)) return; |
531 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::LOAD_IC, | 551 Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::LOAD_IC, |
532 target->extra_ic_state()); | 552 target->extra_ic_state()); |
533 SetTargetAtAddress(address, code, constant_pool); | 553 SetTargetAtAddress(address, code, constant_pool); |
534 } | 554 } |
(...skipping 1378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1913 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "slow stub"); | 1933 TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "slow stub"); |
1914 } | 1934 } |
1915 DCHECK(!stub.is_null()); | 1935 DCHECK(!stub.is_null()); |
1916 set_target(*stub); | 1936 set_target(*stub); |
1917 TRACE_IC("StoreIC", key); | 1937 TRACE_IC("StoreIC", key); |
1918 | 1938 |
1919 return store_handle; | 1939 return store_handle; |
1920 } | 1940 } |
1921 | 1941 |
1922 | 1942 |
| 1943 // static |
| 1944 void CallIC::OnTypeFeedbackChanged(Isolate* isolate, Code* host, |
| 1945 TypeFeedbackVector* vector, State old_state, |
| 1946 State new_state) { |
| 1947 if (host->kind() != Code::FUNCTION) return; |
| 1948 |
| 1949 if (FLAG_type_info_threshold > 0) { |
| 1950 int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic. |
| 1951 int generic_delta = 0; // "Generic" here includes megamorphic. |
| 1952 ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta, |
| 1953 &generic_delta); |
| 1954 vector->change_ic_with_type_info_count(polymorphic_delta); |
| 1955 vector->change_ic_generic_count(generic_delta); |
| 1956 } |
| 1957 TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info()); |
| 1958 info->change_own_type_change_checksum(); |
| 1959 host->set_profiler_ticks(0); |
| 1960 isolate->runtime_profiler()->NotifyICChanged(); |
| 1961 // TODO(2029): When an optimized function is patched, it would |
| 1962 // be nice to propagate the corresponding type information to its |
| 1963 // unoptimized version for the benefit of later inlining. |
| 1964 } |
| 1965 |
| 1966 |
1923 bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function, | 1967 bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function, |
1924 Handle<TypeFeedbackVector> vector, | 1968 Handle<TypeFeedbackVector> vector, |
1925 Handle<Smi> slot, const CallICState& state) { | 1969 FeedbackVectorICSlot slot, |
| 1970 const CallICState& state) { |
1926 DCHECK(FLAG_use_ic && function->IsJSFunction()); | 1971 DCHECK(FLAG_use_ic && function->IsJSFunction()); |
1927 | 1972 |
1928 // Are we the array function? | 1973 // Are we the array function? |
1929 Handle<JSFunction> array_function = | 1974 Handle<JSFunction> array_function = |
1930 Handle<JSFunction>(isolate()->native_context()->array_function()); | 1975 Handle<JSFunction>(isolate()->native_context()->array_function()); |
1931 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) { | 1976 if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) { |
1932 // Alter the slot. | 1977 // Alter the slot. |
1933 IC::State old_state = FeedbackToState(vector, slot); | 1978 IC::State old_state = FeedbackToState(isolate(), *vector, slot); |
1934 Object* feedback = vector->get(slot->value()); | 1979 Object* feedback = vector->Get(slot); |
1935 if (!feedback->IsAllocationSite()) { | 1980 if (!feedback->IsAllocationSite()) { |
1936 Handle<AllocationSite> new_site = | 1981 Handle<AllocationSite> new_site = |
1937 isolate()->factory()->NewAllocationSite(); | 1982 isolate()->factory()->NewAllocationSite(); |
1938 vector->set(slot->value(), *new_site); | 1983 vector->Set(slot, *new_site); |
1939 } | 1984 } |
1940 | 1985 |
1941 CallIC_ArrayStub stub(isolate(), state); | 1986 CallIC_ArrayStub stub(isolate(), state); |
1942 set_target(*stub.GetCode()); | 1987 set_target(*stub.GetCode()); |
1943 Handle<String> name; | 1988 Handle<String> name; |
1944 if (array_function->shared()->name()->IsString()) { | 1989 if (array_function->shared()->name()->IsString()) { |
1945 name = Handle<String>(String::cast(array_function->shared()->name()), | 1990 name = Handle<String>(String::cast(array_function->shared()->name()), |
1946 isolate()); | 1991 isolate()); |
1947 } | 1992 } |
1948 | 1993 |
1949 IC::State new_state = FeedbackToState(vector, slot); | 1994 IC::State new_state = FeedbackToState(isolate(), *vector, slot); |
1950 OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true); | 1995 OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state); |
1951 TRACE_VECTOR_IC("CallIC (custom handler)", name, old_state, new_state); | 1996 TRACE_VECTOR_IC("CallIC (custom handler)", name, old_state, new_state); |
1952 return true; | 1997 return true; |
1953 } | 1998 } |
1954 return false; | 1999 return false; |
1955 } | 2000 } |
1956 | 2001 |
1957 | 2002 |
1958 void CallIC::PatchMegamorphic(Handle<Object> function, | 2003 void CallIC::PatchMegamorphic(Handle<Object> function, |
1959 Handle<TypeFeedbackVector> vector, | 2004 Handle<TypeFeedbackVector> vector, |
1960 Handle<Smi> slot) { | 2005 FeedbackVectorICSlot slot) { |
1961 CallICState state(target()->extra_ic_state()); | 2006 CallICState state(target()->extra_ic_state()); |
1962 IC::State old_state = FeedbackToState(vector, slot); | 2007 IC::State old_state = FeedbackToState(isolate(), *vector, slot); |
1963 | 2008 |
1964 // We are going generic. | 2009 // We are going generic. |
1965 vector->set(slot->value(), | 2010 vector->Set(slot, *TypeFeedbackVector::MegamorphicSentinel(isolate()), |
1966 *TypeFeedbackVector::MegamorphicSentinel(isolate()), | |
1967 SKIP_WRITE_BARRIER); | 2011 SKIP_WRITE_BARRIER); |
1968 | 2012 |
1969 CallICStub stub(isolate(), state); | 2013 CallICStub stub(isolate(), state); |
1970 Handle<Code> code = stub.GetCode(); | 2014 Handle<Code> code = stub.GetCode(); |
1971 set_target(*code); | 2015 set_target(*code); |
1972 | 2016 |
1973 Handle<Object> name = isolate()->factory()->empty_string(); | 2017 Handle<Object> name = isolate()->factory()->empty_string(); |
1974 if (function->IsJSFunction()) { | 2018 if (function->IsJSFunction()) { |
1975 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); | 2019 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); |
1976 name = handle(js_function->shared()->name(), isolate()); | 2020 name = handle(js_function->shared()->name(), isolate()); |
1977 } | 2021 } |
1978 | 2022 |
1979 IC::State new_state = FeedbackToState(vector, slot); | 2023 IC::State new_state = FeedbackToState(isolate(), *vector, slot); |
1980 OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true); | 2024 OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state); |
1981 TRACE_VECTOR_IC("CallIC", name, old_state, new_state); | 2025 TRACE_VECTOR_IC("CallIC", name, old_state, new_state); |
1982 } | 2026 } |
1983 | 2027 |
1984 | 2028 |
1985 void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function, | 2029 void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function, |
1986 Handle<TypeFeedbackVector> vector, Handle<Smi> slot) { | 2030 Handle<TypeFeedbackVector> vector, |
| 2031 FeedbackVectorICSlot slot) { |
1987 CallICState state(target()->extra_ic_state()); | 2032 CallICState state(target()->extra_ic_state()); |
1988 IC::State old_state = FeedbackToState(vector, slot); | 2033 IC::State old_state = FeedbackToState(isolate(), *vector, slot); |
1989 Handle<Object> name = isolate()->factory()->empty_string(); | 2034 Handle<Object> name = isolate()->factory()->empty_string(); |
1990 Object* feedback = vector->get(slot->value()); | 2035 Object* feedback = vector->Get(slot); |
1991 | 2036 |
1992 // Hand-coded MISS handling is easier if CallIC slots don't contain smis. | 2037 // Hand-coded MISS handling is easier if CallIC slots don't contain smis. |
1993 DCHECK(!feedback->IsSmi()); | 2038 DCHECK(!feedback->IsSmi()); |
1994 | 2039 |
1995 if (feedback->IsJSFunction() || !function->IsJSFunction()) { | 2040 if (feedback->IsJSFunction() || !function->IsJSFunction()) { |
1996 // We are going generic. | 2041 // We are going generic. |
1997 vector->set(slot->value(), | 2042 vector->Set(slot, *TypeFeedbackVector::MegamorphicSentinel(isolate()), |
1998 *TypeFeedbackVector::MegamorphicSentinel(isolate()), | |
1999 SKIP_WRITE_BARRIER); | 2043 SKIP_WRITE_BARRIER); |
2000 } else { | 2044 } else { |
2001 // The feedback is either uninitialized or an allocation site. | 2045 // The feedback is either uninitialized or an allocation site. |
2002 // It might be an allocation site because if we re-compile the full code | 2046 // It might be an allocation site because if we re-compile the full code |
2003 // to add deoptimization support, we call with the default call-ic, and | 2047 // to add deoptimization support, we call with the default call-ic, and |
2004 // merely need to patch the target to match the feedback. | 2048 // merely need to patch the target to match the feedback. |
2005 // TODO(mvstanton): the better approach is to dispense with patching | 2049 // TODO(mvstanton): the better approach is to dispense with patching |
2006 // altogether, which is in progress. | 2050 // altogether, which is in progress. |
2007 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()) || | 2051 DCHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()) || |
2008 feedback->IsAllocationSite()); | 2052 feedback->IsAllocationSite()); |
2009 | 2053 |
2010 // Do we want to install a custom handler? | 2054 // Do we want to install a custom handler? |
2011 if (FLAG_use_ic && | 2055 if (FLAG_use_ic && |
2012 DoCustomHandler(receiver, function, vector, slot, state)) { | 2056 DoCustomHandler(receiver, function, vector, slot, state)) { |
2013 return; | 2057 return; |
2014 } | 2058 } |
2015 | 2059 |
2016 vector->set(slot->value(), *function); | 2060 vector->Set(slot, *function); |
2017 } | 2061 } |
2018 | 2062 |
2019 if (function->IsJSFunction()) { | 2063 if (function->IsJSFunction()) { |
2020 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); | 2064 Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); |
2021 name = handle(js_function->shared()->name(), isolate()); | 2065 name = handle(js_function->shared()->name(), isolate()); |
2022 } | 2066 } |
2023 | 2067 |
2024 IC::State new_state = FeedbackToState(vector, slot); | 2068 IC::State new_state = FeedbackToState(isolate(), *vector, slot); |
2025 OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true); | 2069 OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state); |
2026 TRACE_VECTOR_IC("CallIC", name, old_state, new_state); | 2070 TRACE_VECTOR_IC("CallIC", name, old_state, new_state); |
2027 } | 2071 } |
2028 | 2072 |
2029 | 2073 |
2030 #undef TRACE_IC | 2074 #undef TRACE_IC |
2031 | 2075 |
2032 | 2076 |
2033 // ---------------------------------------------------------------------------- | 2077 // ---------------------------------------------------------------------------- |
2034 // Static IC stub generators. | 2078 // Static IC stub generators. |
2035 // | 2079 // |
2036 | 2080 |
2037 // Used from ic-<arch>.cc. | 2081 // Used from ic-<arch>.cc. |
2038 RUNTIME_FUNCTION(CallIC_Miss) { | 2082 RUNTIME_FUNCTION(CallIC_Miss) { |
2039 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2083 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2040 HandleScope scope(isolate); | 2084 HandleScope scope(isolate); |
2041 DCHECK(args.length() == 4); | 2085 DCHECK(args.length() == 4); |
2042 CallIC ic(isolate); | 2086 CallIC ic(isolate); |
2043 Handle<Object> receiver = args.at<Object>(0); | 2087 Handle<Object> receiver = args.at<Object>(0); |
2044 Handle<Object> function = args.at<Object>(1); | 2088 Handle<Object> function = args.at<Object>(1); |
2045 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2); | 2089 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2); |
2046 Handle<Smi> slot = args.at<Smi>(3); | 2090 Handle<Smi> slot = args.at<Smi>(3); |
2047 ic.HandleMiss(receiver, function, vector, slot); | 2091 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value()); |
| 2092 ic.HandleMiss(receiver, function, vector, vector_slot); |
2048 return *function; | 2093 return *function; |
2049 } | 2094 } |
2050 | 2095 |
2051 | 2096 |
2052 RUNTIME_FUNCTION(CallIC_Customization_Miss) { | 2097 RUNTIME_FUNCTION(CallIC_Customization_Miss) { |
2053 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2098 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2054 HandleScope scope(isolate); | 2099 HandleScope scope(isolate); |
2055 DCHECK(args.length() == 4); | 2100 DCHECK(args.length() == 4); |
2056 // A miss on a custom call ic always results in going megamorphic. | 2101 // A miss on a custom call ic always results in going megamorphic. |
2057 CallIC ic(isolate); | 2102 CallIC ic(isolate); |
2058 Handle<Object> function = args.at<Object>(1); | 2103 Handle<Object> function = args.at<Object>(1); |
2059 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2); | 2104 Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2); |
2060 Handle<Smi> slot = args.at<Smi>(3); | 2105 Handle<Smi> slot = args.at<Smi>(3); |
2061 ic.PatchMegamorphic(function, vector, slot); | 2106 FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value()); |
| 2107 ic.PatchMegamorphic(function, vector, vector_slot); |
2062 return *function; | 2108 return *function; |
2063 } | 2109 } |
2064 | 2110 |
2065 | 2111 |
2066 // Used from ic-<arch>.cc. | 2112 // Used from ic-<arch>.cc. |
2067 RUNTIME_FUNCTION(LoadIC_Miss) { | 2113 RUNTIME_FUNCTION(LoadIC_Miss) { |
2068 TimerEventScope<TimerEventIcMiss> timer(isolate); | 2114 TimerEventScope<TimerEventIcMiss> timer(isolate); |
2069 HandleScope scope(isolate); | 2115 HandleScope scope(isolate); |
2070 DCHECK(args.length() == 2); | 2116 DCHECK(args.length() == 2); |
2071 LoadIC ic(IC::NO_EXTRA_FRAME, isolate); | 2117 LoadIC ic(IC::NO_EXTRA_FRAME, isolate); |
(...skipping 618 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2690 static const Address IC_utilities[] = { | 2736 static const Address IC_utilities[] = { |
2691 #define ADDR(name) FUNCTION_ADDR(name), | 2737 #define ADDR(name) FUNCTION_ADDR(name), |
2692 IC_UTIL_LIST(ADDR) NULL | 2738 IC_UTIL_LIST(ADDR) NULL |
2693 #undef ADDR | 2739 #undef ADDR |
2694 }; | 2740 }; |
2695 | 2741 |
2696 | 2742 |
2697 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; } | 2743 Address IC::AddressFromUtilityId(IC::UtilityId id) { return IC_utilities[id]; } |
2698 } | 2744 } |
2699 } // namespace v8::internal | 2745 } // namespace v8::internal |
OLD | NEW |