Introduce FeedbackNexus for vector-based ics.
A FeedbackNexus is the combination of a feedback vector, a slot(s) in the vector, along with methods to query and manipulate that information in a type-correct way. A CallIC will have a CallICNexus, a LoadIC a LoadICNexus, etc., reflecting the fact that different types of ICs configure their data in unique ways. This CL limits itself to introducing and using the nexus type only for CallICs. A follow-up will use them for Load and KeyedLoadICs for the case when the --vector-ics flag is turned on. The notion of a Nexus is also embedded at the lowest level of the IC class. This makes sense because more ICs should become vector-based in the future. This CL is based on https://codereview.chromium.org/679073002/ which should land first. BUG= R=ishell@chromium.org Review URL: https://codereview.chromium.org/680883004 Cr-Commit-Position: refs/heads/master@{#24945} git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24945 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a5ffbf3c46
commit
27ad136bdb
@ -208,30 +208,12 @@ Handle<Map> IC::GetICCacheHolder(HeapType* type, Isolate* isolate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline Code* CallIC::get_host() {
|
inline Code* IC::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,12 +18,18 @@ 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,
|
||||||
TypeFeedbackVector* vector, FeedbackVectorICSlot slot) {
|
Nexus* nexus) {
|
||||||
IC::Clear(isolate, kind, host, vector, slot);
|
IC::Clear<Nexus>(isolate, kind, host, nexus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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,8 +20,9 @@ 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,
|
||||||
TypeFeedbackVector* vector, FeedbackVectorICSlot slot);
|
Nexus* nexus);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
170
src/ic/ic.cc
170
src/ic/ic.cc
@ -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) {
|
||||||
Code* new_target = raw_target();
|
State new_state =
|
||||||
State new_state = new_target->ic_state();
|
UseVector() ? nexus()->StateFromFeedback() : raw_target()->ic_state();
|
||||||
TraceIC(type, name, state(), new_state);
|
TraceIC(type, name, state(), new_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,12 +134,16 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#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)
|
#define TRACE_IC(type, name) TraceIC(type, name)
|
||||||
: isolate_(isolate), target_set_(false), target_maps_set_(false) {
|
|
||||||
|
|
||||||
|
IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus,
|
||||||
|
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.
|
||||||
@ -178,8 +182,10 @@ IC::IC(FrameDepth depth, Isolate* isolate)
|
|||||||
}
|
}
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,6 +425,30 @@ 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.
|
||||||
@ -507,17 +537,21 @@ void IC::Clear(Isolate* isolate, Address address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IC::Clear(Isolate* isolate, Code::Kind kind, Code* host,
|
template <class Nexus>
|
||||||
TypeFeedbackVector* vector, FeedbackVectorICSlot slot) {
|
void IC::Clear(Isolate* isolate, Code::Kind kind, Code* host, Nexus* nexus) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case Code::CALL_IC:
|
case Code::CALL_IC:
|
||||||
return CallIC::Clear(isolate, host, vector, slot);
|
return CallIC::Clear(isolate, host, nexus);
|
||||||
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;
|
||||||
@ -529,18 +563,15 @@ void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CallIC::Clear(Isolate* isolate, Code* host, TypeFeedbackVector* vector,
|
void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
|
||||||
FeedbackVectorICSlot slot) {
|
|
||||||
DCHECK(vector != NULL && !slot.IsInvalid());
|
|
||||||
Object* feedback = vector->Get(slot);
|
|
||||||
// Determine our state.
|
// Determine our state.
|
||||||
State state = FeedbackToState(isolate, vector, slot);
|
Object* feedback = nexus->vector()->Get(nexus->slot());
|
||||||
|
State state = nexus->StateFromFeedback();
|
||||||
|
|
||||||
if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
|
if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
|
||||||
vector->Set(slot, isolate->heap()->uninitialized_symbol(),
|
nexus->ConfigureUninitialized();
|
||||||
SKIP_WRITE_BARRIER);
|
|
||||||
// The change in state must be processed.
|
// The change in state must be processed.
|
||||||
OnTypeFeedbackChanged(isolate, host, vector, state, UNINITIALIZED);
|
OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, UNINITIALIZED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1946,34 +1977,8 @@ 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,
|
||||||
Handle<TypeFeedbackVector> vector,
|
const CallICState& callic_state) {
|
||||||
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?
|
||||||
@ -1981,42 +1986,33 @@ 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.
|
||||||
IC::State old_state = FeedbackToState(isolate(), *vector, slot);
|
CallICNexus* nexus = casted_nexus<CallICNexus>();
|
||||||
Object* feedback = vector->Get(slot);
|
nexus->ConfigureMonomorphicArray();
|
||||||
if (!feedback->IsAllocationSite()) {
|
|
||||||
Handle<AllocationSite> new_site =
|
|
||||||
isolate()->factory()->NewAllocationSite();
|
|
||||||
vector->Set(slot, *new_site);
|
|
||||||
}
|
|
||||||
|
|
||||||
CallIC_ArrayStub stub(isolate(), state);
|
CallIC_ArrayStub stub(isolate(), callic_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);
|
||||||
IC::State new_state = FeedbackToState(isolate(), *vector, slot);
|
OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
|
||||||
OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state);
|
MONOMORPHIC);
|
||||||
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) {
|
||||||
Handle<TypeFeedbackVector> vector,
|
CallICState callic_state(target()->extra_ic_state());
|
||||||
FeedbackVectorICSlot slot) {
|
|
||||||
CallICState state(target()->extra_ic_state());
|
|
||||||
IC::State old_state = FeedbackToState(isolate(), *vector, slot);
|
|
||||||
|
|
||||||
// We are going generic.
|
// We are going generic.
|
||||||
vector->Set(slot, *TypeFeedbackVector::MegamorphicSentinel(isolate()),
|
CallICNexus* nexus = casted_nexus<CallICNexus>();
|
||||||
SKIP_WRITE_BARRIER);
|
nexus->ConfigureGeneric();
|
||||||
|
|
||||||
CallICStub stub(isolate(), state);
|
CallICStub stub(isolate(), callic_state);
|
||||||
Handle<Code> code = stub.GetCode();
|
Handle<Code> code = stub.GetCode();
|
||||||
set_target(*code);
|
set_target(*code);
|
||||||
|
|
||||||
@ -2026,27 +2022,24 @@ void CallIC::PatchMegamorphic(Handle<Object> function,
|
|||||||
name = handle(js_function->shared()->name(), isolate());
|
name = handle(js_function->shared()->name(), isolate());
|
||||||
}
|
}
|
||||||
|
|
||||||
IC::State new_state = FeedbackToState(isolate(), *vector, slot);
|
TRACE_IC("CallIC", name);
|
||||||
OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state);
|
OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
|
||||||
TRACE_VECTOR_IC("CallIC", name, old_state, new_state);
|
GENERIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function,
|
void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function) {
|
||||||
Handle<TypeFeedbackVector> vector,
|
CallICState callic_state(target()->extra_ic_state());
|
||||||
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();
|
||||||
Object* feedback = vector->Get(slot);
|
CallICNexus* nexus = casted_nexus<CallICNexus>();
|
||||||
|
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.
|
||||||
vector->Set(slot, *TypeFeedbackVector::MegamorphicSentinel(isolate()),
|
nexus->ConfigureGeneric();
|
||||||
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
|
||||||
@ -2058,12 +2051,11 @@ 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 &&
|
if (FLAG_use_ic && DoCustomHandler(receiver, function, callic_state)) {
|
||||||
DoCustomHandler(receiver, function, vector, slot, state)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector->Set(slot, *function);
|
nexus->ConfigureMonomorphic(Handle<JSFunction>::cast(function));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (function->IsJSFunction()) {
|
if (function->IsJSFunction()) {
|
||||||
@ -2071,9 +2063,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 = FeedbackToState(isolate(), *vector, slot);
|
IC::State new_state = nexus->StateFromFeedback();
|
||||||
OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state);
|
OnTypeFeedbackChanged(isolate(), get_host(), *vector(), state(), new_state);
|
||||||
TRACE_VECTOR_IC("CallIC", name, old_state, new_state);
|
TRACE_IC("CallIC", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2089,13 +2081,14 @@ 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());
|
||||||
ic.HandleMiss(receiver, function, vector, vector_slot);
|
CallICNexus nexus(vector, vector_slot);
|
||||||
|
CallIC ic(isolate, &nexus);
|
||||||
|
ic.HandleMiss(receiver, function);
|
||||||
return *function;
|
return *function;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2104,13 +2097,14 @@ 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());
|
||||||
ic.PatchMegamorphic(function, vector, vector_slot);
|
CallICNexus nexus(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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
72
src/ic/ic.h
72
src/ic/ic.h
@ -59,7 +59,8 @@ 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);
|
IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL,
|
||||||
|
bool for_queries_only = false);
|
||||||
virtual ~IC() {}
|
virtual ~IC() {}
|
||||||
|
|
||||||
State state() const { return state_; }
|
State state() const { return state_; }
|
||||||
@ -71,6 +72,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,8 +89,9 @@ 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,
|
||||||
TypeFeedbackVector* vector, FeedbackVectorICSlot slot);
|
Nexus* nexus);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool IsLoadStub() const {
|
bool IsLoadStub() const {
|
||||||
@ -117,6 +120,11 @@ 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
|
||||||
@ -149,6 +157,15 @@ 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,
|
||||||
@ -166,6 +183,10 @@ 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.
|
||||||
@ -229,6 +250,20 @@ 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;
|
||||||
@ -263,6 +298,7 @@ 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_;
|
||||||
@ -272,6 +308,8 @@ 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -295,38 +333,24 @@ class IC_Utility {
|
|||||||
|
|
||||||
class CallIC : public IC {
|
class CallIC : public IC {
|
||||||
public:
|
public:
|
||||||
explicit CallIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
|
CallIC(Isolate* isolate, CallICNexus* nexus)
|
||||||
|
: 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,
|
||||||
Handle<TypeFeedbackVector> vector,
|
const CallICState& callic_state);
|
||||||
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, TypeFeedbackVector* vector,
|
static void Clear(Isolate* isolate, Code* host, CallICNexus* nexus);
|
||||||
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,6 +4,7 @@
|
|||||||
|
|
||||||
#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"
|
||||||
@ -151,9 +152,142 @@ 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) {
|
||||||
ICUtility::Clear(isolate, Code::CALL_IC, host, this, slot);
|
// TODO(mvstanton): To make this code work with --vector-ics,
|
||||||
|
// 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,6 +173,105 @@ 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,12 +86,13 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,4 +198,45 @@ 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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user