Revert "Introduce FeedbackNexus for vector-based ics."

This reverts commit r24945.

TBR=machenbach@chromium.org

Review URL: https://codereview.chromium.org/683883002

Cr-Commit-Position: refs/heads/master@{#24947}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24947 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 306ce733
...@@ -208,12 +208,30 @@ Handle<Map> IC::GetICCacheHolder(HeapType* type, Isolate* isolate, ...@@ -208,12 +208,30 @@ Handle<Map> IC::GetICCacheHolder(HeapType* type, Isolate* isolate,
} }
inline Code* IC::get_host() { inline Code* CallIC::get_host() {
return isolate() return isolate()
->inner_pointer_to_code_cache() ->inner_pointer_to_code_cache()
->GetCacheEntry(address()) ->GetCacheEntry(address())
->code; ->code;
} }
// static
IC::State CallIC::FeedbackToState(Isolate* isolate, TypeFeedbackVector* vector,
FeedbackVectorICSlot slot) {
IC::State state = UNINITIALIZED;
Object* feedback = vector->Get(slot);
if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
state = GENERIC;
} else if (feedback->IsAllocationSite() || feedback->IsJSFunction()) {
state = MONOMORPHIC;
} else {
CHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate));
}
return state;
}
} }
} // namespace v8::internal } // namespace v8::internal
......
...@@ -18,18 +18,12 @@ void ICUtility::Clear(Isolate* isolate, Address address, ...@@ -18,18 +18,12 @@ void ICUtility::Clear(Isolate* isolate, Address address,
// static // static
template <class Nexus>
void ICUtility::Clear(Isolate* isolate, Code::Kind kind, Code* host, void ICUtility::Clear(Isolate* isolate, Code::Kind kind, Code* host,
Nexus* nexus) { TypeFeedbackVector* vector, FeedbackVectorICSlot slot) {
IC::Clear<Nexus>(isolate, kind, host, nexus); IC::Clear(isolate, kind, host, vector, slot);
} }
// Force instantiation of template instances for vector-based IC clearing.
template void ICUtility::Clear<CallICNexus>(Isolate*, Code::Kind, Code*,
CallICNexus*);
CallICState::CallICState(ExtraICState extra_ic_state) CallICState::CallICState(ExtraICState extra_ic_state)
: argc_(ArgcBits::decode(extra_ic_state)), : argc_(ArgcBits::decode(extra_ic_state)),
call_type_(CallTypeBits::decode(extra_ic_state)) {} call_type_(CallTypeBits::decode(extra_ic_state)) {}
......
...@@ -20,9 +20,8 @@ class ICUtility : public AllStatic { ...@@ -20,9 +20,8 @@ class ICUtility : public AllStatic {
static void Clear(Isolate* isolate, Address address, static void Clear(Isolate* isolate, Address address,
ConstantPoolArray* constant_pool); ConstantPoolArray* constant_pool);
// Clear a vector-based inline cache to initial state. // Clear a vector-based inline cache to initial state.
template <class Nexus>
static void Clear(Isolate* isolate, Code::Kind kind, Code* host, static void Clear(Isolate* isolate, Code::Kind kind, Code* host,
Nexus* nexus); TypeFeedbackVector* vector, FeedbackVectorICSlot slot);
}; };
......
...@@ -89,8 +89,8 @@ const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) { ...@@ -89,8 +89,8 @@ const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
void IC::TraceIC(const char* type, Handle<Object> name) { void IC::TraceIC(const char* type, Handle<Object> name) {
if (FLAG_trace_ic) { if (FLAG_trace_ic) {
State new_state = Code* new_target = raw_target();
UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state(); State new_state = new_target->ic_state();
TraceIC(type, name, state(), new_state); TraceIC(type, name, state(), new_state);
} }
} }
...@@ -134,16 +134,12 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state, ...@@ -134,16 +134,12 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
} }
} }
#define TRACE_IC(type, name) TraceIC(type, name) #define TRACE_IC(type, name) TraceIC(type, name)
#define TRACE_VECTOR_IC(type, name, old_state, new_state) \
TraceIC(type, name, old_state, new_state)
IC::IC(FrameDepth depth, Isolate* isolate)
IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus, : isolate_(isolate), target_set_(false), target_maps_set_(false) {
bool for_queries_only)
: isolate_(isolate),
target_set_(false),
target_maps_set_(false),
nexus_(nexus) {
// To improve the performance of the (much used) IC code, we unfold a few // To improve the performance of the (much used) IC code, we unfold a few
// levels of the stack frame iteration code. This yields a ~35% speedup when // levels of the stack frame iteration code. This yields a ~35% speedup when
// running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag. // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
...@@ -182,10 +178,8 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus, ...@@ -182,10 +178,8 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus,
} }
pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address); pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
target_ = handle(raw_target(), isolate); target_ = handle(raw_target(), isolate);
state_ = target_->ic_state();
kind_ = target_->kind(); kind_ = target_->kind();
state_ = (!for_queries_only && UseVector()) ? nexus->StateFromFeedback()
: target_->ic_state();
old_state_ = state_;
extra_ic_state_ = target_->extra_ic_state(); extra_ic_state_ = target_->extra_ic_state();
} }
...@@ -425,30 +419,6 @@ void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address, ...@@ -425,30 +419,6 @@ void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
} }
// static
void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
TypeFeedbackVector* vector, State old_state,
State new_state) {
if (host->kind() != Code::FUNCTION) return;
if (FLAG_type_info_threshold > 0) {
int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
int generic_delta = 0; // "Generic" here includes megamorphic.
ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
&generic_delta);
vector->change_ic_with_type_info_count(polymorphic_delta);
vector->change_ic_generic_count(generic_delta);
}
TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
info->change_own_type_change_checksum();
host->set_profiler_ticks(0);
isolate->runtime_profiler()->NotifyICChanged();
// TODO(2029): When an optimized function is patched, it would
// be nice to propagate the corresponding type information to its
// unoptimized version for the benefit of later inlining.
}
void IC::PostPatching(Address address, Code* target, Code* old_target) { void IC::PostPatching(Address address, Code* target, Code* old_target) {
// Type vector based ICs update these statistics at a different time because // Type vector based ICs update these statistics at a different time because
// they don't always patch on state change. // they don't always patch on state change.
...@@ -537,21 +507,17 @@ void IC::Clear(Isolate* isolate, Address address, ...@@ -537,21 +507,17 @@ void IC::Clear(Isolate* isolate, Address address,
} }
template <class Nexus> void IC::Clear(Isolate* isolate, Code::Kind kind, Code* host,
void IC::Clear(Isolate* isolate, Code::Kind kind, Code* host, Nexus* nexus) { TypeFeedbackVector* vector, FeedbackVectorICSlot slot) {
switch (kind) { switch (kind) {
case Code::CALL_IC: case Code::CALL_IC:
return CallIC::Clear(isolate, host, nexus); return CallIC::Clear(isolate, host, vector, slot);
default: default:
UNREACHABLE(); UNREACHABLE();
} }
} }
// Force instantiation of template instances for vector-based IC clearing.
template void IC::Clear(Isolate*, Code::Kind, Code*, CallICNexus*);
void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target, void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
ConstantPoolArray* constant_pool) { ConstantPoolArray* constant_pool) {
if (IsCleared(target)) return; if (IsCleared(target)) return;
...@@ -563,15 +529,18 @@ void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target, ...@@ -563,15 +529,18 @@ void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
} }
void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) { void CallIC::Clear(Isolate* isolate, Code* host, TypeFeedbackVector* vector,
FeedbackVectorICSlot slot) {
DCHECK(vector != NULL && !slot.IsInvalid());
Object* feedback = vector->Get(slot);
// Determine our state. // Determine our state.
Object* feedback = nexus->vector()->Get(nexus->slot()); State state = FeedbackToState(isolate, vector, slot);
State state = nexus->StateFromFeedback();
if (state != UNINITIALIZED && !feedback->IsAllocationSite()) { if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
nexus->ConfigureUninitialized(); vector->Set(slot, isolate->heap()->uninitialized_symbol(),
SKIP_WRITE_BARRIER);
// The change in state must be processed. // The change in state must be processed.
OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, UNINITIALIZED); OnTypeFeedbackChanged(isolate, host, vector, state, UNINITIALIZED);
} }
} }
...@@ -1977,8 +1946,34 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm, ...@@ -1977,8 +1946,34 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
} }
// static
void CallIC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
TypeFeedbackVector* vector, State old_state,
State new_state) {
if (host->kind() != Code::FUNCTION) return;
if (FLAG_type_info_threshold > 0) {
int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
int generic_delta = 0; // "Generic" here includes megamorphic.
ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
&generic_delta);
vector->change_ic_with_type_info_count(polymorphic_delta);
vector->change_ic_generic_count(generic_delta);
}
TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
info->change_own_type_change_checksum();
host->set_profiler_ticks(0);
isolate->runtime_profiler()->NotifyICChanged();
// TODO(2029): When an optimized function is patched, it would
// be nice to propagate the corresponding type information to its
// unoptimized version for the benefit of later inlining.
}
bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function, bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
const CallICState& callic_state) { Handle<TypeFeedbackVector> vector,
FeedbackVectorICSlot slot,
const CallICState& state) {
DCHECK(FLAG_use_ic && function->IsJSFunction()); DCHECK(FLAG_use_ic && function->IsJSFunction());
// Are we the array function? // Are we the array function?
...@@ -1986,33 +1981,42 @@ bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function, ...@@ -1986,33 +1981,42 @@ bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
Handle<JSFunction>(isolate()->native_context()->array_function()); Handle<JSFunction>(isolate()->native_context()->array_function());
if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) { if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) {
// Alter the slot. // Alter the slot.
CallICNexus* nexus = casted_nexus<CallICNexus>(); IC::State old_state = FeedbackToState(isolate(), *vector, slot);
nexus->ConfigureMonomorphicArray(); Object* feedback = vector->Get(slot);
if (!feedback->IsAllocationSite()) {
Handle<AllocationSite> new_site =
isolate()->factory()->NewAllocationSite();
vector->Set(slot, *new_site);
}
CallIC_ArrayStub stub(isolate(), callic_state); CallIC_ArrayStub stub(isolate(), state);
set_target(*stub.GetCode()); set_target(*stub.GetCode());
Handle<String> name; Handle<String> name;
if (array_function->shared()->name()->IsString()) { if (array_function->shared()->name()->IsString()) {
name = Handle<String>(String::cast(array_function->shared()->name()), name = Handle<String>(String::cast(array_function->shared()->name()),
isolate()); isolate());
} }
TRACE_IC("CallIC", name);
OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(), IC::State new_state = FeedbackToState(isolate(), *vector, slot);
MONOMORPHIC); OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state);
TRACE_VECTOR_IC("CallIC (custom handler)", name, old_state, new_state);
return true; return true;
} }
return false; return false;
} }
void CallIC::PatchMegamorphic(Handle<Object> function) { void CallIC::PatchMegamorphic(Handle<Object> function,
CallICState callic_state(target()->extra_ic_state()); Handle<TypeFeedbackVector> vector,
FeedbackVectorICSlot slot) {
CallICState state(target()->extra_ic_state());
IC::State old_state = FeedbackToState(isolate(), *vector, slot);
// We are going generic. // We are going generic.
CallICNexus* nexus = casted_nexus<CallICNexus>(); vector->Set(slot, *TypeFeedbackVector::MegamorphicSentinel(isolate()),
nexus->ConfigureGeneric(); SKIP_WRITE_BARRIER);
CallICStub stub(isolate(), callic_state); CallICStub stub(isolate(), state);
Handle<Code> code = stub.GetCode(); Handle<Code> code = stub.GetCode();
set_target(*code); set_target(*code);
...@@ -2022,24 +2026,27 @@ void CallIC::PatchMegamorphic(Handle<Object> function) { ...@@ -2022,24 +2026,27 @@ void CallIC::PatchMegamorphic(Handle<Object> function) {
name = handle(js_function->shared()->name(), isolate()); name = handle(js_function->shared()->name(), isolate());
} }
TRACE_IC("CallIC", name); IC::State new_state = FeedbackToState(isolate(), *vector, slot);
OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(), OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state);
GENERIC); TRACE_VECTOR_IC("CallIC", name, old_state, new_state);
} }
void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function) { void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function,
CallICState callic_state(target()->extra_ic_state()); Handle<TypeFeedbackVector> vector,
FeedbackVectorICSlot slot) {
CallICState state(target()->extra_ic_state());
IC::State old_state = FeedbackToState(isolate(), *vector, slot);
Handle<Object> name = isolate()->factory()->empty_string(); Handle<Object> name = isolate()->factory()->empty_string();
CallICNexus* nexus = casted_nexus<CallICNexus>(); Object* feedback = vector->Get(slot);
Object* feedback = nexus->GetFeedback();
// Hand-coded MISS handling is easier if CallIC slots don't contain smis. // Hand-coded MISS handling is easier if CallIC slots don't contain smis.
DCHECK(!feedback->IsSmi()); DCHECK(!feedback->IsSmi());
if (feedback->IsJSFunction() || !function->IsJSFunction()) { if (feedback->IsJSFunction() || !function->IsJSFunction()) {
// We are going generic. // We are going generic.
nexus->ConfigureGeneric(); vector->Set(slot, *TypeFeedbackVector::MegamorphicSentinel(isolate()),
SKIP_WRITE_BARRIER);
} else { } else {
// The feedback is either uninitialized or an allocation site. // The feedback is either uninitialized or an allocation site.
// It might be an allocation site because if we re-compile the full code // It might be an allocation site because if we re-compile the full code
...@@ -2051,11 +2058,12 @@ void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function) { ...@@ -2051,11 +2058,12 @@ void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function) {
feedback->IsAllocationSite()); feedback->IsAllocationSite());
// Do we want to install a custom handler? // Do we want to install a custom handler?
if (FLAG_use_ic && DoCustomHandler(receiver, function, callic_state)) { if (FLAG_use_ic &&
DoCustomHandler(receiver, function, vector, slot, state)) {
return; return;
} }
nexus->ConfigureMonomorphic(Handle<JSFunction>::cast(function)); vector->Set(slot, *function);
} }
if (function->IsJSFunction()) { if (function->IsJSFunction()) {
...@@ -2063,9 +2071,9 @@ void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function) { ...@@ -2063,9 +2071,9 @@ void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function) {
name = handle(js_function->shared()->name(), isolate()); name = handle(js_function->shared()->name(), isolate());
} }
IC::State new_state = nexus->StateFromFeedback(); IC::State new_state = FeedbackToState(isolate(), *vector, slot);
OnTypeFeedbackChanged(isolate(), get_host(), *vector(), state(), new_state); OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state);
TRACE_IC("CallIC", name); TRACE_VECTOR_IC("CallIC", name, old_state, new_state);
} }
...@@ -2081,14 +2089,13 @@ RUNTIME_FUNCTION(CallIC_Miss) { ...@@ -2081,14 +2089,13 @@ RUNTIME_FUNCTION(CallIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate); TimerEventScope<TimerEventIcMiss> timer(isolate);
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 4); DCHECK(args.length() == 4);
CallIC ic(isolate);
Handle<Object> receiver = args.at<Object>(0); Handle<Object> receiver = args.at<Object>(0);
Handle<Object> function = args.at<Object>(1); Handle<Object> function = args.at<Object>(1);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2); Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
Handle<Smi> slot = args.at<Smi>(3); Handle<Smi> slot = args.at<Smi>(3);
FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value()); FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
CallICNexus nexus(vector, vector_slot); ic.HandleMiss(receiver, function, vector, vector_slot);
CallIC ic(isolate, &nexus);
ic.HandleMiss(receiver, function);
return *function; return *function;
} }
...@@ -2097,14 +2104,13 @@ RUNTIME_FUNCTION(CallIC_Customization_Miss) { ...@@ -2097,14 +2104,13 @@ RUNTIME_FUNCTION(CallIC_Customization_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate); TimerEventScope<TimerEventIcMiss> timer(isolate);
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 4); DCHECK(args.length() == 4);
// A miss on a custom call ic always results in going megamorphic.
CallIC ic(isolate);
Handle<Object> function = args.at<Object>(1); Handle<Object> function = args.at<Object>(1);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2); Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
Handle<Smi> slot = args.at<Smi>(3); Handle<Smi> slot = args.at<Smi>(3);
FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value()); FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
CallICNexus nexus(vector, vector_slot); ic.PatchMegamorphic(function, vector, vector_slot);
// A miss on a custom call ic always results in going megamorphic.
CallIC ic(isolate, &nexus);
ic.PatchMegamorphic(function);
return *function; return *function;
} }
......
...@@ -59,8 +59,7 @@ class IC { ...@@ -59,8 +59,7 @@ class IC {
// Construct the IC structure with the given number of extra // Construct the IC structure with the given number of extra
// JavaScript frames on the stack. // JavaScript frames on the stack.
IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL, IC(FrameDepth depth, Isolate* isolate);
bool for_queries_only = false);
virtual ~IC() {} virtual ~IC() {}
State state() const { return state_; } State state() const { return state_; }
...@@ -72,7 +71,6 @@ class IC { ...@@ -72,7 +71,6 @@ class IC {
bool IsNameCompatibleWithPrototypeFailure(Handle<Object> name); bool IsNameCompatibleWithPrototypeFailure(Handle<Object> name);
void MarkPrototypeFailure(Handle<Object> name) { void MarkPrototypeFailure(Handle<Object> name) {
DCHECK(IsNameCompatibleWithPrototypeFailure(name)); DCHECK(IsNameCompatibleWithPrototypeFailure(name));
old_state_ = state_;
state_ = PROTOTYPE_FAILURE; state_ = PROTOTYPE_FAILURE;
} }
...@@ -89,9 +87,8 @@ class IC { ...@@ -89,9 +87,8 @@ class IC {
ConstantPoolArray* constant_pool); ConstantPoolArray* constant_pool);
// Clear the vector-based inline cache to initial state. // Clear the vector-based inline cache to initial state.
template <class Nexus>
static void Clear(Isolate* isolate, Code::Kind kind, Code* host, static void Clear(Isolate* isolate, Code::Kind kind, Code* host,
Nexus* nexus); TypeFeedbackVector* vector, FeedbackVectorICSlot slot);
#ifdef DEBUG #ifdef DEBUG
bool IsLoadStub() const { bool IsLoadStub() const {
...@@ -120,11 +117,6 @@ class IC { ...@@ -120,11 +117,6 @@ class IC {
return state == UNINITIALIZED || state == PREMONOMORPHIC; return state == UNINITIALIZED || state == PREMONOMORPHIC;
} }
static bool IsCleared(FeedbackNexus* nexus) {
InlineCacheState state = nexus->StateFromFeedback();
return state == UNINITIALIZED || state == PREMONOMORPHIC;
}
// Utility functions to convert maps to types and back. There are two special // Utility functions to convert maps to types and back. There are two special
// cases: // cases:
// - The heap_number_map is used as a marker which includes heap numbers as // - The heap_number_map is used as a marker which includes heap numbers as
...@@ -157,15 +149,6 @@ class IC { ...@@ -157,15 +149,6 @@ class IC {
inline void set_target(Code* code); inline void set_target(Code* code);
bool is_target_set() { return target_set_; } bool is_target_set() { return target_set_; }
bool UseVector() const {
bool use = (FLAG_vector_ics &&
(kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC)) ||
kind() == Code::CALL_IC;
// If we are supposed to use the nexus, verify the nexus is non-null.
DCHECK(!use || nexus_ != NULL);
return use;
}
char TransitionMarkFromState(IC::State state); char TransitionMarkFromState(IC::State state);
void TraceIC(const char* type, Handle<Object> name); void TraceIC(const char* type, Handle<Object> name);
void TraceIC(const char* type, Handle<Object> name, State old_state, void TraceIC(const char* type, Handle<Object> name, State old_state,
...@@ -183,10 +166,6 @@ class IC { ...@@ -183,10 +166,6 @@ class IC {
static void OnTypeFeedbackChanged(Isolate* isolate, Address address, static void OnTypeFeedbackChanged(Isolate* isolate, Address address,
State old_state, State new_state, State old_state, State new_state,
bool target_remains_ic_stub); bool target_remains_ic_stub);
// As a vector-based IC, type feedback must be updated differently.
static void OnTypeFeedbackChanged(Isolate* isolate, Code* host,
TypeFeedbackVector* vector, State old_state,
State new_state);
static void PostPatching(Address address, Code* target, Code* old_target); static void PostPatching(Address address, Code* target, Code* old_target);
// Compute the handler either by compiling or by retrieving a cached version. // Compute the handler either by compiling or by retrieving a cached version.
...@@ -250,20 +229,6 @@ class IC { ...@@ -250,20 +229,6 @@ class IC {
inline void UpdateTarget(); inline void UpdateTarget();
Handle<TypeFeedbackVector> vector() const { return nexus()->vector_handle(); }
FeedbackVectorICSlot slot() const { return nexus()->slot(); }
State saved_state() const {
return state() == PROTOTYPE_FAILURE ? old_state_ : state();
}
template <class NexusClass>
NexusClass* casted_nexus() {
return static_cast<NexusClass*>(nexus_);
}
FeedbackNexus* nexus() const { return nexus_; }
inline Code* get_host();
private: private:
inline Code* raw_target() const; inline Code* raw_target() const;
inline ConstantPoolArray* constant_pool() const; inline ConstantPoolArray* constant_pool() const;
...@@ -298,7 +263,6 @@ class IC { ...@@ -298,7 +263,6 @@ class IC {
// The original code target that missed. // The original code target that missed.
Handle<Code> target_; Handle<Code> target_;
bool target_set_; bool target_set_;
State old_state_; // For saving if we marked as prototype failure.
State state_; State state_;
Code::Kind kind_; Code::Kind kind_;
Handle<HeapType> receiver_type_; Handle<HeapType> receiver_type_;
...@@ -308,8 +272,6 @@ class IC { ...@@ -308,8 +272,6 @@ class IC {
MapHandleList target_maps_; MapHandleList target_maps_;
bool target_maps_set_; bool target_maps_set_;
FeedbackNexus* nexus_;
DISALLOW_IMPLICIT_CONSTRUCTORS(IC); DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
}; };
...@@ -333,24 +295,38 @@ class IC_Utility { ...@@ -333,24 +295,38 @@ class IC_Utility {
class CallIC : public IC { class CallIC : public IC {
public: public:
CallIC(Isolate* isolate, CallICNexus* nexus) explicit CallIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
: IC(EXTRA_CALL_FRAME, isolate, nexus) {
DCHECK(nexus != NULL);
}
void PatchMegamorphic(Handle<Object> function); void PatchMegamorphic(Handle<Object> function,
Handle<TypeFeedbackVector> vector,
FeedbackVectorICSlot slot);
void HandleMiss(Handle<Object> receiver, Handle<Object> function); void HandleMiss(Handle<Object> receiver, Handle<Object> function,
Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot);
// Returns true if a custom handler was installed. // Returns true if a custom handler was installed.
bool DoCustomHandler(Handle<Object> receiver, Handle<Object> function, bool DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
const CallICState& callic_state); Handle<TypeFeedbackVector> vector,
FeedbackVectorICSlot slot, const CallICState& state);
// Code generator routines. // Code generator routines.
static Handle<Code> initialize_stub(Isolate* isolate, int argc, static Handle<Code> initialize_stub(Isolate* isolate, int argc,
CallICState::CallType call_type); CallICState::CallType call_type);
static void Clear(Isolate* isolate, Code* host, CallICNexus* nexus); static void Clear(Isolate* isolate, Code* host, TypeFeedbackVector* vector,
FeedbackVectorICSlot slot);
private:
static inline IC::State FeedbackToState(Isolate* isolate,
TypeFeedbackVector* vector,
FeedbackVectorICSlot slot);
inline Code* get_host();
// As a vector-based IC, type feedback must be updated differently.
static void OnTypeFeedbackChanged(Isolate* isolate, Code* host,
TypeFeedbackVector* vector, State old_state,
State new_state);
}; };
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#include "src/v8.h" #include "src/v8.h"
#include "src/ic/ic.h"
#include "src/ic/ic-state.h" #include "src/ic/ic-state.h"
#include "src/objects.h" #include "src/objects.h"
#include "src/type-feedback-vector-inl.h" #include "src/type-feedback-vector-inl.h"
...@@ -152,142 +151,9 @@ void TypeFeedbackVector::ClearSlots(SharedFunctionInfo* shared) { ...@@ -152,142 +151,9 @@ void TypeFeedbackVector::ClearSlots(SharedFunctionInfo* shared) {
FeedbackVectorICSlot slot(i); FeedbackVectorICSlot slot(i);
Object* obj = Get(slot); Object* obj = Get(slot);
if (obj != uninitialized_sentinel) { if (obj != uninitialized_sentinel) {
// TODO(mvstanton): To make this code work with --vector-ics, ICUtility::Clear(isolate, Code::CALL_IC, host, this, slot);
// additional Nexus types must be created.
DCHECK(!FLAG_vector_ics);
DCHECK(GetKind(slot) == Code::CALL_IC);
CallICNexus nexus(this, slot);
ICUtility::Clear(isolate, Code::CALL_IC, host, &nexus);
} }
} }
} }
Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
Isolate* isolate = GetIsolate();
Handle<Object> feedback = handle(GetFeedback(), isolate);
if (!feedback->IsFixedArray() ||
FixedArray::cast(*feedback)->length() != length) {
Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
SetFeedback(*array);
return array;
}
return Handle<FixedArray>::cast(feedback);
}
void FeedbackNexus::InstallHandlers(int start_index, TypeHandleList* types,
CodeHandleList* handlers) {
Isolate* isolate = GetIsolate();
FixedArray* array = FixedArray::cast(GetFeedback());
int receiver_count = types->length();
for (int current = 0; current < receiver_count; ++current) {
Handle<HeapType> type = types->at(current);
Handle<Map> map = IC::TypeToMap(*type, isolate);
array->set(start_index + (current * 2), *map);
array->set(start_index + (current * 2 + 1), *handlers->at(current));
}
}
InlineCacheState CallICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate();
InlineCacheState state = UNINITIALIZED;
Object* feedback = GetFeedback();
if (feedback == *vector()->MegamorphicSentinel(isolate)) {
state = GENERIC;
} else if (feedback->IsAllocationSite() || feedback->IsJSFunction()) {
state = MONOMORPHIC;
} else {
CHECK(feedback == *vector()->UninitializedSentinel(isolate));
}
return state;
}
void CallICNexus::ConfigureGeneric() {
SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
}
void CallICNexus::ConfigureMonomorphicArray() {
Object* feedback = GetFeedback();
if (!feedback->IsAllocationSite()) {
Handle<AllocationSite> new_site =
GetIsolate()->factory()->NewAllocationSite();
SetFeedback(*new_site);
}
}
void CallICNexus::ConfigureUninitialized() {
SetFeedback(*vector()->UninitializedSentinel(GetIsolate()),
SKIP_WRITE_BARRIER);
}
void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
SetFeedback(*function);
}
int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
if (feedback->IsFixedArray()) {
FixedArray* array = FixedArray::cast(feedback);
// The array should be of the form [<optional name>], then
// [map, handler, map, handler, ... ]
DCHECK(array->length() >= (2 + start_index));
for (int i = start_index; i < array->length(); i += 2) {
Map* map = Map::cast(array->get(i));
maps->Add(handle(map, isolate));
}
return (array->length() - start_index) / 2;
}
return 0;
}
MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index,
Handle<Map> map) const {
Object* feedback = GetFeedback();
if (feedback->IsFixedArray()) {
FixedArray* array = FixedArray::cast(feedback);
for (int i = start_index; i < array->length(); i += 2) {
Map* array_map = Map::cast(array->get(i));
if (array_map == *map) {
Code* code = Code::cast(array->get(i + 1));
DCHECK(code->kind() == Code::HANDLER);
return handle(code);
}
}
}
return MaybeHandle<Code>();
}
bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
int length) const {
Object* feedback = GetFeedback();
int count = 0;
if (feedback->IsFixedArray()) {
FixedArray* array = FixedArray::cast(feedback);
// The array should be of the form [<optional name>], then
// [map, handler, map, handler, ... ]
DCHECK(array->length() >= (2 + start_index));
for (int i = start_index; i < array->length(); i += 2) {
Code* code = Code::cast(array->get(i + 1));
DCHECK(code->kind() == Code::HANDLER);
code_list->Add(handle(code));
count++;
}
}
return count == length;
}
} }
} // namespace v8::internal } // namespace v8::internal
...@@ -173,105 +173,6 @@ class TypeFeedbackVector : public FixedArray { ...@@ -173,105 +173,6 @@ class TypeFeedbackVector : public FixedArray {
DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackVector); DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackVector);
}; };
// A FeedbackNexus is the combination of a TypeFeedbackVector and a slot.
// Derived classes customize the update and retrieval of feedback.
class FeedbackNexus {
public:
FeedbackNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
: vector_handle_(vector), use_handle_(true), slot_(slot) {}
FeedbackNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot)
: vector_(vector), use_handle_(false), slot_(slot) {}
virtual ~FeedbackNexus() {}
Handle<TypeFeedbackVector> vector_handle() const {
DCHECK(use_handle_);
return vector_handle_;
}
TypeFeedbackVector* vector() const {
return use_handle_ ? *vector_handle_ : vector_;
}
FeedbackVectorICSlot slot() const { return slot_; }
InlineCacheState ic_state() const { return StateFromFeedback(); }
Map* FindFirstMap() const {
MapHandleList maps;
ExtractMaps(&maps);
if (maps.length() > 0) return *maps.at(0);
return NULL;
}
virtual InlineCacheState StateFromFeedback() const = 0;
virtual int ExtractMaps(MapHandleList* maps) const = 0;
virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const = 0;
virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const {
return length == 0;
}
virtual Name* FindFirstName() const { return NULL; }
Object* GetFeedback() const { return vector()->Get(slot()); }
protected:
Isolate* GetIsolate() const { return vector()->GetIsolate(); }
void SetFeedback(Object* feedback,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
vector()->Set(slot(), feedback, mode);
}
Handle<FixedArray> EnsureArrayOfSize(int length);
void InstallHandlers(int start_index, TypeHandleList* types,
CodeHandleList* handlers);
int ExtractMaps(int start_index, MapHandleList* maps) const;
MaybeHandle<Code> FindHandlerForMap(int start_index, Handle<Map> map) const;
bool FindHandlers(int start_index, CodeHandleList* code_list,
int length) const;
private:
// The reason for the union is that we can use handles during IC miss,
// but not during GC when we clear ICs. If you have a handle to the
// vector that is better because more operations can be done, like
// allocation.
union {
Handle<TypeFeedbackVector> vector_handle_;
TypeFeedbackVector* vector_;
};
bool use_handle_;
FeedbackVectorICSlot slot_;
};
class CallICNexus : public FeedbackNexus {
public:
CallICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->GetKind(slot) == Code::CALL_IC);
}
CallICNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->GetKind(slot) == Code::CALL_IC);
}
void ConfigureUninitialized();
void ConfigureGeneric();
void ConfigureMonomorphicArray();
void ConfigureMonomorphic(Handle<JSFunction> function);
virtual InlineCacheState StateFromFeedback() const OVERRIDE;
virtual int ExtractMaps(MapHandleList* maps) const OVERRIDE {
// CallICs don't record map feedback.
return 0;
}
virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE {
return MaybeHandle<Code>();
}
virtual bool FindHandlers(CodeHandleList* code_list,
int length = -1) const OVERRIDE {
return length == 0;
}
};
} }
} // namespace v8::internal } // namespace v8::internal
......
...@@ -86,13 +86,12 @@ TEST(VectorICMetadata) { ...@@ -86,13 +86,12 @@ TEST(VectorICMetadata) {
// Set metadata. // Set metadata.
for (int i = 0; i < 30; i++) { for (int i = 0; i < 30; i++) {
Code::Kind kind; Code::Kind kind;
if (i % 3 == 0) { if (i % 3 == 0)
kind = Code::CALL_IC; kind = Code::CALL_IC;
} else if (i % 3 == 1) { else if (i % 3 == 1)
kind = Code::LOAD_IC; kind = Code::LOAD_IC;
} else { else
kind = Code::KEYED_LOAD_IC; kind = Code::KEYED_LOAD_IC;
}
vector->SetKind(FeedbackVectorICSlot(i), kind); vector->SetKind(FeedbackVectorICSlot(i), kind);
} }
...@@ -198,45 +197,4 @@ TEST(VectorICProfilerStatistics) { ...@@ -198,45 +197,4 @@ TEST(VectorICProfilerStatistics) {
CHECK( CHECK(
feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite()); feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
} }
TEST(VectorCallICStates) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
// Make sure function f has a call that uses a type feedback slot.
CompileRun(
"function foo() { return 17; }"
"function f(a) { a(); } f(foo);");
Handle<JSFunction> f = v8::Utils::OpenHandle(
*v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
// There should be one IC.
Handle<TypeFeedbackVector> feedback_vector =
Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
FeedbackVectorICSlot slot(FLAG_vector_ics ? 1 : 0);
CallICNexus nexus(feedback_vector, slot);
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
// CallIC doesn't return map feedback.
CHECK_EQ(NULL, nexus.FindFirstMap());
CompileRun("f(function() { return 16; })");
CHECK_EQ(GENERIC, nexus.StateFromFeedback());
// After a collection, state should be reset to UNINITIALIZED.
heap->CollectAllGarbage(i::Heap::kNoGCFlags);
CHECK_EQ(UNINITIALIZED, nexus.StateFromFeedback());
// Array is special. It will remain monomorphic across gcs and it contains an
// AllocationSite.
CompileRun("f(Array)");
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot))->IsAllocationSite());
heap->CollectAllGarbage(i::Heap::kNoGCFlags);
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment