Commit 45adc5f8 authored by ishell@chromium.org's avatar ishell@chromium.org Committed by Commit Bot

[ic] Use FeedbackSlotKind instead of Code::Kind in IC class and friends.

Now we can inline vector-based IC dispatchers to bytecode handlers.

BUG=v8:5917

Change-Id: Ie81750f252a730240097e514e69b348f410a48b7
Reviewed-on: https://chromium-review.googlesource.com/439265Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43028}
parent 72bad21c
......@@ -51,6 +51,7 @@ int FeedbackMetadata::GetSlotSize(FeedbackSlotKind kind) {
case FeedbackSlotKind::GENERAL:
case FeedbackSlotKind::INTERPRETER_COMPARE_IC:
case FeedbackSlotKind::INTERPRETER_BINARYOP_IC:
case FeedbackSlotKind::TO_BOOLEAN_IC:
case FeedbackSlotKind::LITERAL:
case FeedbackSlotKind::CREATE_CLOSURE:
return 1;
......@@ -225,6 +226,7 @@ void FeedbackVector::ComputeCounts(int* with_type_info, int* generic,
}
break;
}
case FeedbackSlotKind::TO_BOOLEAN_IC:
case FeedbackSlotKind::CREATE_CLOSURE:
case FeedbackSlotKind::GENERAL:
case FeedbackSlotKind::LITERAL:
......
......@@ -139,6 +139,8 @@ const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
return "INTERPRETER_BINARYOP_IC";
case FeedbackSlotKind::INTERPRETER_COMPARE_IC:
return "INTERPRETER_COMPARE_IC";
case FeedbackSlotKind::TO_BOOLEAN_IC:
return "TO_BOOLEAN_IC";
case FeedbackSlotKind::STORE_DATA_PROPERTY_IN_LITERAL_IC:
return "STORE_DATA_PROPERTY_IN_LITERAL_IC";
case FeedbackSlotKind::CREATE_CLOSURE:
......@@ -191,6 +193,7 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
break;
case FeedbackSlotKind::INTERPRETER_COMPARE_IC:
case FeedbackSlotKind::INTERPRETER_BINARYOP_IC:
case FeedbackSlotKind::TO_BOOLEAN_IC:
array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
break;
case FeedbackSlotKind::CREATE_CLOSURE: {
......@@ -327,6 +330,7 @@ void FeedbackVector::ClearSlotsImpl(SharedFunctionInfo* shared,
nexus.Clear(shared->code());
break;
}
case FeedbackSlotKind::TO_BOOLEAN_IC:
case FeedbackSlotKind::INVALID:
case FeedbackSlotKind::KINDS_NUMBER:
UNREACHABLE();
......
......@@ -33,6 +33,7 @@ enum class FeedbackSlotKind {
KEYED_STORE_STRICT_IC,
INTERPRETER_BINARYOP_IC,
INTERPRETER_COMPARE_IC,
TO_BOOLEAN_IC,
STORE_DATA_PROPERTY_IN_LITERAL_IC,
CREATE_CLOSURE,
LITERAL,
......
......@@ -45,7 +45,10 @@ Code* IC::GetTargetAtAddress(Address address, Address constant_pool) {
// Convert target address to the code object. Code::GetCodeFromTargetAddress
// is safe for use during GC where the map might be marked.
Code* result = Code::GetCodeFromTargetAddress(target);
DCHECK(result->is_inline_cache_stub());
// The result can be an IC dispatcher (for vector-based ICs), an IC handler
// (for old-style patching ICs) or CEntryStub (for IC dispatchers inlined to
// bytecode handlers).
DCHECK(result->is_inline_cache_stub() || result->is_stub());
return result;
}
......
......@@ -143,7 +143,7 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
}
const char* modifier = "";
if (kind() == Code::KEYED_STORE_IC) {
if (IsKeyedStoreIC()) {
KeyedAccessStoreMode mode =
casted_nexus<KeyedStoreICNexus>()->GetKeyedAccessStoreMode();
modifier = GetTransitionMarkModifier(mode);
......@@ -196,10 +196,10 @@ void IC::TraceIC(const char* type, Handle<Object> name, State old_state,
#define TRACE_IC(type, name) TraceIC(type, name)
IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
: isolate_(isolate),
vector_set_(false),
kind_(FeedbackSlotKind::INVALID),
target_maps_set_(false),
nexus_(nexus) {
// To improve the performance of the (much used) IC code, we unfold a few
......@@ -247,11 +247,29 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
constant_pool_address_ = constant_pool;
}
pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
if (nexus) {
kind_ = nexus->kind();
DCHECK(UseVector());
state_ = nexus->StateFromFeedback();
extra_ic_state_ = kNoExtraICState;
} else {
Code* target = this->target();
kind_ = target->kind();
state_ = UseVector() ? nexus->StateFromFeedback() : StateFromCode(target);
old_state_ = state_;
Code::Kind kind = target->kind();
if (kind == Code::BINARY_OP_IC) {
kind_ = FeedbackSlotKind::INTERPRETER_BINARYOP_IC;
} else if (kind == Code::COMPARE_IC) {
kind_ = FeedbackSlotKind::INTERPRETER_COMPARE_IC;
} else if (kind == Code::TO_BOOLEAN_IC) {
kind_ = FeedbackSlotKind::TO_BOOLEAN_IC;
} else {
UNREACHABLE();
kind_ = FeedbackSlotKind::INVALID;
}
DCHECK(!UseVector());
state_ = StateFromCode(target);
extra_ic_state_ = target->extra_ic_state();
}
old_state_ = state_;
}
// The ICs that don't pass slot and vector through the stack have to
......@@ -350,7 +368,7 @@ bool IC::ShouldRecomputeHandler(Handle<String> name) {
// This is a contextual access, always just update the handler and stay
// monomorphic.
if (kind() == Code::LOAD_GLOBAL_IC) return true;
if (IsLoadGlobalIC()) return true;
// The current map wasn't handled yet. There's no reason to stay monomorphic,
// *unless* we're moving from a deprecated map to its replacement, or
......@@ -462,6 +480,7 @@ void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) {
void IC::PostPatching(Address address, Code* target, Code* old_target) {
// Type vector based ICs update these statistics at a different time because
// they don't always patch on state change.
// TODO(ishell): DCHECK
if (ICUseVector(target->kind())) return;
DCHECK(old_target->is_inline_cache_stub());
......@@ -583,13 +602,13 @@ void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
if (new_state == PREMONOMORPHIC) {
nexus()->ConfigurePremonomorphic();
} else if (new_state == MEGAMORPHIC) {
if (kind() == Code::LOAD_IC || kind() == Code::STORE_IC) {
if (IsLoadIC() || IsStoreIC()) {
nexus()->ConfigureMegamorphic();
} else if (kind() == Code::KEYED_LOAD_IC) {
} else if (IsKeyedLoadIC()) {
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
} else {
DCHECK(kind() == Code::KEYED_STORE_IC);
DCHECK(IsKeyedStoreIC());
KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
}
......@@ -604,20 +623,20 @@ void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
Handle<Object> handler) {
DCHECK(UseVector());
if (kind() == Code::LOAD_IC) {
if (IsLoadIC()) {
LoadICNexus* nexus = casted_nexus<LoadICNexus>();
nexus->ConfigureMonomorphic(map, handler);
} else if (kind() == Code::LOAD_GLOBAL_IC) {
} else if (IsLoadGlobalIC()) {
LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
nexus->ConfigureHandlerMode(handler);
} else if (kind() == Code::KEYED_LOAD_IC) {
} else if (IsKeyedLoadIC()) {
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
nexus->ConfigureMonomorphic(name, map, handler);
} else if (kind() == Code::STORE_IC) {
} else if (IsStoreIC()) {
StoreICNexus* nexus = casted_nexus<StoreICNexus>();
nexus->ConfigureMonomorphic(map, handler);
} else {
DCHECK(kind() == Code::KEYED_STORE_IC);
DCHECK(IsKeyedStoreIC());
KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
nexus->ConfigureMonomorphic(name, map, handler);
}
......@@ -629,17 +648,17 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
List<Handle<Object>>* handlers) {
DCHECK(UseVector());
if (kind() == Code::LOAD_IC) {
if (IsLoadIC()) {
LoadICNexus* nexus = casted_nexus<LoadICNexus>();
nexus->ConfigurePolymorphic(maps, handlers);
} else if (kind() == Code::KEYED_LOAD_IC) {
} else if (IsKeyedLoadIC()) {
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
nexus->ConfigurePolymorphic(name, maps, handlers);
} else if (kind() == Code::STORE_IC) {
} else if (IsStoreIC()) {
StoreICNexus* nexus = casted_nexus<StoreICNexus>();
nexus->ConfigurePolymorphic(maps, handlers);
} else {
DCHECK(kind() == Code::KEYED_STORE_IC);
DCHECK(IsKeyedStoreIC());
KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
nexus->ConfigurePolymorphic(name, maps, handlers);
}
......@@ -652,7 +671,7 @@ void IC::ConfigureVectorState(MapHandleList* maps,
MapHandleList* transitioned_maps,
List<Handle<Object>>* handlers) {
DCHECK(UseVector());
DCHECK(kind() == Code::KEYED_STORE_IC);
DCHECK(IsKeyedStoreIC());
KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers);
......@@ -843,12 +862,8 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
DCHECK(IsHandler(*handler));
// Currently only LoadIC and KeyedLoadIC support non-code handlers.
DCHECK_IMPLIES(!handler->IsCode(), kind() == Code::LOAD_IC ||
kind() == Code::LOAD_GLOBAL_IC ||
kind() == Code::KEYED_LOAD_IC ||
kind() == Code::STORE_IC ||
kind() == Code::KEYED_STORE_IC);
// Currently only load and store ICs support non-code handlers.
DCHECK_IMPLIES(!handler->IsCode(), IsAnyLoad() || IsAnyStore());
switch (state()) {
case UNINITIALIZED:
case PREMONOMORPHIC:
......@@ -856,7 +871,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
break;
case RECOMPUTE_HANDLER:
case MONOMORPHIC:
if (kind() == Code::LOAD_GLOBAL_IC) {
if (IsLoadGlobalIC()) {
UpdateMonomorphicIC(handler, name);
break;
}
......@@ -1101,7 +1116,7 @@ bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) {
void LoadIC::UpdateCaches(LookupIterator* lookup) {
if (state() == UNINITIALIZED && kind() != Code::LOAD_GLOBAL_IC) {
if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
// This is the first time we execute this inline cache. Set the target to
// the pre monomorphic stub to delay setting the monomorphic state.
TRACE_HANDLER_STATS(isolate(), LoadIC_Premonomorphic);
......@@ -1115,15 +1130,14 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
lookup->state() == LookupIterator::ACCESS_CHECK) {
code = slow_stub();
} else if (!lookup->IsFound()) {
if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC) {
if (IsLoadIC() || IsLoadGlobalIC()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
code = LoadNonExistent(receiver_map(), lookup->name());
} else {
code = slow_stub();
}
} else {
if (kind() == Code::LOAD_GLOBAL_IC &&
lookup->state() == LookupIterator::DATA &&
if (IsLoadGlobalIC() && lookup->state() == LookupIterator::DATA &&
lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
// Now update the cell in the feedback vector.
......@@ -1156,20 +1170,12 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
}
StubCache* IC::stub_cache() {
switch (kind()) {
case Code::LOAD_IC:
case Code::KEYED_LOAD_IC:
if (IsAnyLoad()) {
return isolate()->load_stub_cache();
case Code::STORE_IC:
case Code::KEYED_STORE_IC:
} else {
DCHECK(IsAnyStore());
return isolate()->store_stub_cache();
default:
break;
}
UNREACHABLE();
return nullptr;
}
void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) {
......@@ -1179,8 +1185,7 @@ void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) {
void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
if (!FLAG_runtime_call_stats) return;
if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC ||
kind() == Code::KEYED_LOAD_IC) {
if (IsAnyLoad()) {
switch (lookup->state()) {
case LookupIterator::ACCESS_CHECK:
TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_AccessCheck);
......@@ -1207,7 +1212,7 @@ void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Transition);
break;
}
} else if (kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC) {
} else if (IsAnyStore()) {
switch (lookup->state()) {
case LookupIterator::ACCESS_CHECK:
TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_AccessCheck);
......@@ -1254,19 +1259,18 @@ Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
CacheHolderFlag flag;
Handle<Map> stub_holder_map;
if (kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC ||
kind() == Code::KEYED_LOAD_IC) {
if (IsAnyLoad()) {
stub_holder_map = IC::GetHandlerCacheHolder(
receiver_map(), receiver_is_holder, isolate(), &flag);
} else {
DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
DCHECK(IsAnyStore());
// Store handlers cannot be cached on prototypes.
flag = kCacheOnReceiver;
stub_holder_map = receiver_map();
}
Handle<Object> handler = PropertyHandlerCompiler::Find(
lookup->name(), stub_holder_map, kind(), flag);
lookup->name(), stub_holder_map, handler_kind(), flag);
// Use the cached value if it exists, and if it is different from the
// handler that just missed.
if (!handler.is_null()) {
......@@ -1384,7 +1388,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
return smi_handler;
}
if (kind() != Code::LOAD_GLOBAL_IC) {
if (!IsLoadGlobalIC()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
......@@ -1398,7 +1402,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
case LookupIterator::DATA: {
DCHECK_EQ(kData, lookup->property_details().kind());
if (lookup->is_dictionary_holder()) {
if (kind() != Code::LOAD_IC && kind() != Code::LOAD_GLOBAL_IC) {
if (!IsLoadIC() && !IsLoadGlobalIC()) { // IsKeyedLoadIC()?
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub();
}
......@@ -1542,7 +1546,7 @@ Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup,
case LookupIterator::DATA: {
DCHECK(lookup->is_dictionary_holder());
DCHECK(kind() == Code::LOAD_IC || kind() == Code::LOAD_GLOBAL_IC);
DCHECK(IsLoadIC() || IsLoadGlobalIC());
DCHECK(holder->IsJSGlobalObject());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
......
......@@ -45,15 +45,10 @@ class IC {
// Clear the inline cache to initial state.
static void Clear(Isolate* isolate, Address address, Address constant_pool);
#ifdef DEBUG
bool IsLoadStub() const {
return kind_ == Code::LOAD_IC || kind_ == Code::LOAD_GLOBAL_IC ||
kind_ == Code::KEYED_LOAD_IC;
bool IsAnyLoad() const {
return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
}
bool IsStoreStub() const {
return kind_ == Code::STORE_IC || kind_ == Code::KEYED_STORE_IC;
}
#endif
bool IsAnyStore() const { return IsStoreIC() || IsKeyedStoreIC(); }
static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map,
bool receiver_is_holder,
......@@ -73,6 +68,11 @@ class IC {
kind == Code::KEYED_LOAD_IC || kind == Code::STORE_IC ||
kind == Code::KEYED_STORE_IC;
}
static bool ICUseVector(FeedbackSlotKind kind) {
return IsLoadICKind(kind) || IsLoadGlobalICKind(kind) ||
IsKeyedLoadICKind(kind) || IsStoreICKind(kind) ||
IsKeyedStoreICKind(kind);
}
// The ICs that don't pass slot and vector through the stack have to
// save/restore them in the dispatcher.
......@@ -164,15 +164,17 @@ class IC {
void CopyICToMegamorphicCache(Handle<Name> name);
bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
void PatchCache(Handle<Name> name, Handle<Object> code);
Code::Kind kind() const { return kind_; }
bool is_keyed() const {
return kind_ == Code::KEYED_LOAD_IC || kind_ == Code::KEYED_STORE_IC;
}
FeedbackSlotKind kind() const { return kind_; }
bool IsLoadIC() const { return IsLoadICKind(kind_); }
bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
bool IsStoreIC() const { return IsStoreICKind(kind_); }
bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
bool is_keyed() const { return IsKeyedLoadIC() || IsKeyedStoreIC(); }
Code::Kind handler_kind() const {
if (kind_ == Code::KEYED_LOAD_IC) return Code::LOAD_IC;
DCHECK(kind_ == Code::LOAD_IC || kind_ == Code::STORE_IC ||
kind_ == Code::KEYED_STORE_IC);
return kind_;
if (IsAnyLoad()) return Code::LOAD_IC;
DCHECK(IsAnyStore());
return Code::STORE_IC;
}
bool ShouldRecomputeHandler(Handle<String> name);
......@@ -243,7 +245,7 @@ class IC {
bool vector_set_;
State old_state_; // For saving if we marked as prototype failure.
State state_;
Code::Kind kind_;
FeedbackSlotKind kind_;
Handle<Map> receiver_map_;
MaybeHandle<Object> maybe_handler_;
......@@ -273,7 +275,7 @@ class LoadIC : public IC {
LoadIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
: IC(depth, isolate, nexus) {
DCHECK(nexus != NULL);
DCHECK(IsLoadStub());
DCHECK(IsAnyLoad());
}
static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
......@@ -281,8 +283,7 @@ class LoadIC : public IC {
}
bool ShouldThrowReferenceError() const {
return UseVector() && ShouldThrowReferenceError(
nexus()->vector()->GetKind(nexus()->slot()));
return ShouldThrowReferenceError(kind());
}
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
......@@ -363,7 +364,7 @@ class StoreIC : public IC {
public:
StoreIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
: IC(depth, isolate, nexus) {
DCHECK(IsStoreStub());
DCHECK(IsAnyStore());
}
LanguageMode language_mode() const {
......
......@@ -4982,7 +4982,8 @@ bool Code::IsCodeStubOrIC() {
}
ExtraICState Code::extra_ic_state() {
DCHECK(is_inline_cache_stub() || is_debug_stub());
DCHECK(is_binary_op_stub() || is_compare_ic_stub() ||
is_to_boolean_ic_stub() || is_debug_stub());
return ExtractExtraICStateFromFlags(flags());
}
......@@ -5279,6 +5280,7 @@ bool Code::is_debug_stub() {
return false;
}
bool Code::is_handler() { return kind() == HANDLER; }
bool Code::is_stub() { return kind() == STUB; }
bool Code::is_binary_op_stub() { return kind() == BINARY_OP_IC; }
bool Code::is_compare_ic_stub() { return kind() == COMPARE_IC; }
bool Code::is_to_boolean_ic_stub() { return kind() == TO_BOOLEAN_IC; }
......
......@@ -804,6 +804,7 @@ void FeedbackVector::FeedbackVectorPrint(std::ostream& os) { // NOLINT
case FeedbackSlotKind::LITERAL:
case FeedbackSlotKind::GENERAL:
break;
case FeedbackSlotKind::TO_BOOLEAN_IC:
case FeedbackSlotKind::INVALID:
case FeedbackSlotKind::KINDS_NUMBER:
UNREACHABLE();
......
......@@ -5059,6 +5059,7 @@ class Code: public HeapObject {
inline bool is_inline_cache_stub();
inline bool is_debug_stub();
inline bool is_handler();
inline bool is_stub();
inline bool is_binary_op_stub();
inline bool is_compare_ic_stub();
inline bool is_to_boolean_ic_stub();
......
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