Revision: 24952
Author: [email protected]
Date: Tue Oct 28 16:05:08 2014 UTC
Log: 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.
[email protected]
Review URL: https://codereview.chromium.org/683933002
https://code.google.com/p/v8/source/detail?r=24952
Modified:
/branches/bleeding_edge/src/ic/ic-inl.h
/branches/bleeding_edge/src/ic/ic-state.cc
/branches/bleeding_edge/src/ic/ic-state.h
/branches/bleeding_edge/src/ic/ic.cc
/branches/bleeding_edge/src/ic/ic.h
/branches/bleeding_edge/src/type-feedback-vector.cc
/branches/bleeding_edge/src/type-feedback-vector.h
/branches/bleeding_edge/test/cctest/test-feedback-vector.cc
=======================================
--- /branches/bleeding_edge/src/ic/ic-inl.h Tue Oct 28 15:07:38 2014 UTC
+++ /branches/bleeding_edge/src/ic/ic-inl.h Tue Oct 28 16:05:08 2014 UTC
@@ -208,30 +208,12 @@
}
-inline Code* CallIC::get_host() {
+inline Code* IC::get_host() {
return isolate()
->inner_pointer_to_code_cache()
->GetCacheEntry(address())
->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
=======================================
--- /branches/bleeding_edge/src/ic/ic-state.cc Tue Oct 28 15:07:38 2014 UTC
+++ /branches/bleeding_edge/src/ic/ic-state.cc Tue Oct 28 16:05:08 2014 UTC
@@ -18,10 +18,16 @@
// static
+template <class Nexus>
void ICUtility::Clear(Isolate* isolate, Code::Kind kind, Code* host,
- TypeFeedbackVector* vector, FeedbackVectorICSlot
slot) {
- IC::Clear(isolate, kind, host, vector, slot);
+ Nexus* nexus) {
+ 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)
=======================================
--- /branches/bleeding_edge/src/ic/ic-state.h Tue Oct 28 15:07:38 2014 UTC
+++ /branches/bleeding_edge/src/ic/ic-state.h Tue Oct 28 16:05:08 2014 UTC
@@ -20,8 +20,9 @@
static void Clear(Isolate* isolate, Address address,
ConstantPoolArray* constant_pool);
// Clear a vector-based inline cache to initial state.
+ template <class Nexus>
static void Clear(Isolate* isolate, Code::Kind kind, Code* host,
- TypeFeedbackVector* vector, FeedbackVectorICSlot slot);
+ Nexus* nexus);
};
=======================================
--- /branches/bleeding_edge/src/ic/ic.cc Tue Oct 28 15:07:38 2014 UTC
+++ /branches/bleeding_edge/src/ic/ic.cc Tue Oct 28 16:05:08 2014 UTC
@@ -89,8 +89,8 @@
void IC::TraceIC(const char* type, Handle<Object> name) {
if (FLAG_trace_ic) {
- Code* new_target = raw_target();
- State new_state = new_target->ic_state();
+ State new_state =
+ UseVector() ? nexus()->StateFromFeedback() :
raw_target()->ic_state();
TraceIC(type, name, state(), new_state);
}
}
@@ -133,13 +133,17 @@
PrintF("]\n");
}
}
+
#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)
- : 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
// 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.
@@ -178,8 +182,10 @@
}
pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
target_ = handle(raw_target(), isolate);
- state_ = target_->ic_state();
kind_ = target_->kind();
+ state_ = (!for_queries_only && UseVector()) ? nexus->StateFromFeedback()
+ : target_->ic_state();
+ old_state_ = state_;
extra_ic_state_ = target_->extra_ic_state();
}
@@ -417,6 +423,30 @@
// be nice to propagate the corresponding type information to its
// unoptimized version for the benefit of later inlining.
}
+
+
+// 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) {
@@ -507,15 +537,19 @@
}
-void IC::Clear(Isolate* isolate, Code::Kind kind, Code* host,
- TypeFeedbackVector* vector, FeedbackVectorICSlot slot) {
+template <class Nexus>
+void IC::Clear(Isolate* isolate, Code::Kind kind, Code* host, Nexus*
nexus) {
switch (kind) {
case Code::CALL_IC:
- return CallIC::Clear(isolate, host, vector, slot);
+ return CallIC::Clear(isolate, host, nexus);
default:
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,
@@ -529,18 +563,15 @@
}
-void CallIC::Clear(Isolate* isolate, Code* host, TypeFeedbackVector*
vector,
- FeedbackVectorICSlot slot) {
- DCHECK(vector != NULL && !slot.IsInvalid());
- Object* feedback = vector->Get(slot);
+void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
// 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()) {
- vector->Set(slot, isolate->heap()->uninitialized_symbol(),
- SKIP_WRITE_BARRIER);
+ nexus->ConfigureUninitialized();
// The change in state must be processed.
- OnTypeFeedbackChanged(isolate, host, vector, state, UNINITIALIZED);
+ OnTypeFeedbackChanged(isolate, host, nexus->vector(), state,
UNINITIALIZED);
}
}
@@ -1944,36 +1975,10 @@
StrictMode strict_mode) {
PropertyICCompiler::GenerateRuntimeSetProperty(masm, strict_mode);
}
-
-
-// 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,
- Handle<TypeFeedbackVector> vector,
- FeedbackVectorICSlot slot,
- const CallICState& state) {
+ const CallICState& callic_state) {
DCHECK(FLAG_use_ic && function->IsJSFunction());
// Are we the array function?
@@ -1981,42 +1986,33 @@
Handle<JSFunction>(isolate()->native_context()->array_function());
if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) {
// Alter the slot.
- IC::State old_state = FeedbackToState(isolate(), *vector, slot);
- Object* feedback = vector->Get(slot);
- if (!feedback->IsAllocationSite()) {
- Handle<AllocationSite> new_site =
- isolate()->factory()->NewAllocationSite();
- vector->Set(slot, *new_site);
- }
+ CallICNexus* nexus = casted_nexus<CallICNexus>();
+ nexus->ConfigureMonomorphicArray();
- CallIC_ArrayStub stub(isolate(), state);
+ CallIC_ArrayStub stub(isolate(), callic_state);
set_target(*stub.GetCode());
Handle<String> name;
if (array_function->shared()->name()->IsString()) {
name = Handle<String>(String::cast(array_function->shared()->name()),
isolate());
}
-
- IC::State new_state = FeedbackToState(isolate(), *vector, slot);
- OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state,
new_state);
- TRACE_VECTOR_IC("CallIC (custom handler)", name, old_state, new_state);
+ TRACE_IC("CallIC", name);
+ OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
+ MONOMORPHIC);
return true;
}
return false;
}
-void CallIC::PatchMegamorphic(Handle<Object> function,
- Handle<TypeFeedbackVector> vector,
- FeedbackVectorICSlot slot) {
- CallICState state(target()->extra_ic_state());
- IC::State old_state = FeedbackToState(isolate(), *vector, slot);
+void CallIC::PatchMegamorphic(Handle<Object> function) {
+ CallICState callic_state(target()->extra_ic_state());
// We are going generic.
- vector->Set(slot, *TypeFeedbackVector::MegamorphicSentinel(isolate()),
- SKIP_WRITE_BARRIER);
+ CallICNexus* nexus = casted_nexus<CallICNexus>();
+ nexus->ConfigureGeneric();
- CallICStub stub(isolate(), state);
+ CallICStub stub(isolate(), callic_state);
Handle<Code> code = stub.GetCode();
set_target(*code);
@@ -2026,27 +2022,24 @@
name = handle(js_function->shared()->name(), isolate());
}
- IC::State new_state = FeedbackToState(isolate(), *vector, slot);
- OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state,
new_state);
- TRACE_VECTOR_IC("CallIC", name, old_state, new_state);
+ TRACE_IC("CallIC", name);
+ OnTypeFeedbackChanged(isolate(), get_host(), nexus->vector(), state(),
+ GENERIC);
}
-void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function,
- Handle<TypeFeedbackVector> vector,
- FeedbackVectorICSlot slot) {
- CallICState state(target()->extra_ic_state());
- IC::State old_state = FeedbackToState(isolate(), *vector, slot);
+void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function) {
+ CallICState callic_state(target()->extra_ic_state());
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.
DCHECK(!feedback->IsSmi());
if (feedback->IsJSFunction() || !function->IsJSFunction()) {
// We are going generic.
- vector->Set(slot, *TypeFeedbackVector::MegamorphicSentinel(isolate()),
- SKIP_WRITE_BARRIER);
+ nexus->ConfigureGeneric();
} else {
// The feedback is either uninitialized or an allocation site.
// It might be an allocation site because if we re-compile the full
code
@@ -2058,12 +2051,11 @@
feedback->IsAllocationSite());
// Do we want to install a custom handler?
- if (FLAG_use_ic &&
- DoCustomHandler(receiver, function, vector, slot, state)) {
+ if (FLAG_use_ic && DoCustomHandler(receiver, function, callic_state)) {
return;
}
- vector->Set(slot, *function);
+ nexus->ConfigureMonomorphic(Handle<JSFunction>::cast(function));
}
if (function->IsJSFunction()) {
@@ -2071,9 +2063,9 @@
name = handle(js_function->shared()->name(), isolate());
}
- IC::State new_state = FeedbackToState(isolate(), *vector, slot);
- OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state,
new_state);
- TRACE_VECTOR_IC("CallIC", name, old_state, new_state);
+ IC::State new_state = nexus->StateFromFeedback();
+ OnTypeFeedbackChanged(isolate(), get_host(), *vector(), state(),
new_state);
+ TRACE_IC("CallIC", name);
}
@@ -2089,13 +2081,14 @@
TimerEventScope<TimerEventIcMiss> timer(isolate);
HandleScope scope(isolate);
DCHECK(args.length() == 4);
- CallIC ic(isolate);
Handle<Object> receiver = args.at<Object>(0);
Handle<Object> function = args.at<Object>(1);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
Handle<Smi> slot = args.at<Smi>(3);
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;
}
@@ -2104,13 +2097,14 @@
TimerEventScope<TimerEventIcMiss> timer(isolate);
HandleScope scope(isolate);
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<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
Handle<Smi> slot = args.at<Smi>(3);
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;
}
=======================================
--- /branches/bleeding_edge/src/ic/ic.h Tue Oct 28 15:07:38 2014 UTC
+++ /branches/bleeding_edge/src/ic/ic.h Tue Oct 28 16:05:08 2014 UTC
@@ -59,7 +59,8 @@
// Construct the IC structure with the given number of extra
// 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() {}
State state() const { return state_; }
@@ -71,6 +72,7 @@
bool IsNameCompatibleWithPrototypeFailure(Handle<Object> name);
void MarkPrototypeFailure(Handle<Object> name) {
DCHECK(IsNameCompatibleWithPrototypeFailure(name));
+ old_state_ = state_;
state_ = PROTOTYPE_FAILURE;
}
@@ -87,8 +89,9 @@
ConstantPoolArray* constant_pool);
// Clear the vector-based inline cache to initial state.
+ template <class Nexus>
static void Clear(Isolate* isolate, Code::Kind kind, Code* host,
- TypeFeedbackVector* vector, FeedbackVectorICSlot slot);
+ Nexus* nexus);
#ifdef DEBUG
bool IsLoadStub() const {
@@ -116,6 +119,11 @@
InlineCacheState state = code->ic_state();
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
// cases:
@@ -148,6 +156,15 @@
// Set the call-site target.
inline void set_target(Code* code);
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);
void TraceIC(const char* type, Handle<Object> name);
@@ -166,6 +183,10 @@
static void OnTypeFeedbackChanged(Isolate* isolate, Address address,
State old_state, State new_state,
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);
// Compute the handler either by compiling or by retrieving a cached
version.
@@ -229,6 +250,20 @@
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:
inline Code* raw_target() const;
inline ConstantPoolArray* constant_pool() const;
@@ -263,6 +298,7 @@
// The original code target that missed.
Handle<Code> target_;
bool target_set_;
+ State old_state_; // For saving if we marked as prototype failure.
State state_;
Code::Kind kind_;
Handle<HeapType> receiver_type_;
@@ -272,6 +308,8 @@
MapHandleList target_maps_;
bool target_maps_set_;
+ FeedbackNexus* nexus_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
};
@@ -295,38 +333,24 @@
class CallIC : public IC {
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,
- Handle<TypeFeedbackVector> vector,
- FeedbackVectorICSlot slot);
+ void PatchMegamorphic(Handle<Object> function);
- void HandleMiss(Handle<Object> receiver, Handle<Object> function,
- Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot
slot);
+ void HandleMiss(Handle<Object> receiver, Handle<Object> function);
// Returns true if a custom handler was installed.
bool DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
- Handle<TypeFeedbackVector> vector,
- FeedbackVectorICSlot slot, const CallICState&
state);
+ const CallICState& callic_state);
// Code generator routines.
static Handle<Code> initialize_stub(Isolate* isolate, int argc,
CallICState::CallType call_type);
- 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);
+ static void Clear(Isolate* isolate, Code* host, CallICNexus* nexus);
};
=======================================
--- /branches/bleeding_edge/src/type-feedback-vector.cc Tue Oct 28 15:07:38
2014 UTC
+++ /branches/bleeding_edge/src/type-feedback-vector.cc Tue Oct 28 16:05:08
2014 UTC
@@ -4,6 +4,7 @@
#include "src/v8.h"
+#include "src/ic/ic.h"
#include "src/ic/ic-state.h"
#include "src/objects.h"
#include "src/type-feedback-vector-inl.h"
@@ -151,9 +152,142 @@
FeedbackVectorICSlot slot(i);
Object* obj = Get(slot);
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
=======================================
--- /branches/bleeding_edge/src/type-feedback-vector.h Tue Oct 28 15:07:38
2014 UTC
+++ /branches/bleeding_edge/src/type-feedback-vector.h Tue Oct 28 16:05:08
2014 UTC
@@ -173,6 +173,102 @@
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), vector_(NULL), slot_(slot) {}
+ FeedbackNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot)
+ : vector_(vector), slot_(slot) {}
+ virtual ~FeedbackNexus() {}
+
+ Handle<TypeFeedbackVector> vector_handle() const {
+ DCHECK(vector_ == NULL);
+ return vector_handle_;
+ }
+ TypeFeedbackVector* vector() const {
+ return vector_handle_.is_null() ? vector_ : *vector_handle_;
+ }
+ 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 having a vector handle and a raw pointer is that we
can and
+ // should 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.
+ Handle<TypeFeedbackVector> vector_handle_;
+ TypeFeedbackVector* vector_;
+ 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
=======================================
--- /branches/bleeding_edge/test/cctest/test-feedback-vector.cc Tue Oct 28
15:07:38 2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-feedback-vector.cc Tue Oct 28
16:05:08 2014 UTC
@@ -86,12 +86,13 @@
// Set metadata.
for (int i = 0; i < 30; i++) {
Code::Kind kind;
- if (i % 3 == 0)
+ if (i % 3 == 0) {
kind = Code::CALL_IC;
- else if (i % 3 == 1)
+ } else if (i % 3 == 1) {
kind = Code::LOAD_IC;
- else
+ } else {
kind = Code::KEYED_LOAD_IC;
+ }
vector->SetKind(FeedbackVectorICSlot(i), kind);
}
@@ -197,4 +198,45 @@
CHECK(
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());
+}
}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.