[LoadIC] Handle simple field loads in the dispatcher
No compiled handlers required! Instead, the type feedback vector contains a Smi encoding the field index. Review-Url: https://codereview.chromium.org/2133233002 Cr-Commit-Position: refs/heads/master@{#37803}
This commit is contained in:
parent
7e1d1fc708
commit
9c59539f27
@ -2143,8 +2143,7 @@ void CodeStubAssembler::LoadPropertyFromFastObject(Node* object, Node* map,
|
||||
Bind(&rebox_double);
|
||||
{
|
||||
Comment("rebox_double");
|
||||
Node* heap_number = AllocateHeapNumber();
|
||||
StoreHeapNumberValue(heap_number, var_double_value.value());
|
||||
Node* heap_number = AllocateHeapNumberWithValue(var_double_value.value());
|
||||
var_value->Bind(heap_number);
|
||||
Goto(&done);
|
||||
}
|
||||
@ -2940,14 +2939,69 @@ void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
|
||||
&var_handler, &try_polymorphic);
|
||||
Bind(&if_handler);
|
||||
{
|
||||
Comment("LoadIC_if_handler");
|
||||
Label call_handler(this);
|
||||
Node* handler = var_handler.value();
|
||||
GotoUnless(WordIsSmi(handler), &call_handler);
|
||||
|
||||
// |handler| is a Smi. It encodes a field index as obtained by
|
||||
// FieldIndex.GetLoadByFieldOffset().
|
||||
{
|
||||
Label inobject_double(this), out_of_object(this),
|
||||
out_of_object_double(this);
|
||||
Variable var_double_value(this, MachineRepresentation::kFloat64);
|
||||
Label rebox_double(this, &var_double_value);
|
||||
|
||||
Node* handler_word = SmiToWord32(handler);
|
||||
// handler == (offset << 1) | is_double.
|
||||
Node* double_bit = Word32And(handler_word, Int32Constant(1));
|
||||
Node* offset = Word32Sar(handler_word, Int32Constant(1));
|
||||
|
||||
// Negative index -> out of object.
|
||||
GotoIf(Int32LessThan(offset, Int32Constant(0)), &out_of_object);
|
||||
|
||||
Node* offset_ptr = ChangeInt32ToIntPtr(offset);
|
||||
GotoUnless(Word32Equal(double_bit, Int32Constant(0)), &inobject_double);
|
||||
Return(LoadObjectField(p->receiver, offset_ptr));
|
||||
|
||||
Bind(&inobject_double);
|
||||
if (FLAG_unbox_double_fields) {
|
||||
var_double_value.Bind(
|
||||
LoadObjectField(p->receiver, offset_ptr, MachineType::Float64()));
|
||||
} else {
|
||||
Node* mutable_heap_number = LoadObjectField(p->receiver, offset_ptr);
|
||||
var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
|
||||
}
|
||||
Goto(&rebox_double);
|
||||
|
||||
Bind(&out_of_object);
|
||||
// |offset| == -actual_offset
|
||||
offset_ptr = ChangeInt32ToIntPtr(Int32Sub(Int32Constant(0), offset));
|
||||
Node* properties = LoadProperties(p->receiver);
|
||||
Node* value = LoadObjectField(properties, offset_ptr);
|
||||
GotoUnless(Word32Equal(double_bit, Int32Constant(0)),
|
||||
&out_of_object_double);
|
||||
Return(value);
|
||||
|
||||
Bind(&out_of_object_double);
|
||||
var_double_value.Bind(LoadHeapNumberValue(value));
|
||||
Goto(&rebox_double);
|
||||
|
||||
Bind(&rebox_double);
|
||||
Return(AllocateHeapNumberWithValue(var_double_value.value()));
|
||||
}
|
||||
|
||||
// |handler| is a heap object. Must be code, call it.
|
||||
Bind(&call_handler);
|
||||
LoadWithVectorDescriptor descriptor(isolate());
|
||||
TailCallStub(descriptor, var_handler.value(), p->context, p->receiver,
|
||||
p->name, p->slot, p->vector);
|
||||
TailCallStub(descriptor, handler, p->context, p->receiver, p->name, p->slot,
|
||||
p->vector);
|
||||
}
|
||||
|
||||
Bind(&try_polymorphic);
|
||||
{
|
||||
// Check polymorphic case.
|
||||
Comment("LoadIC_try_polymorphic");
|
||||
GotoUnless(
|
||||
WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
|
||||
&try_megamorphic);
|
||||
|
@ -39,8 +39,7 @@ inline FieldIndex FieldIndex::ForPropertyIndex(Map* map,
|
||||
is_double, inobject_properties, first_inobject_offset);
|
||||
}
|
||||
|
||||
|
||||
// Takes an index as computed by GetLoadFieldByIndex and reconstructs a
|
||||
// Takes an index as computed by GetLoadByFieldIndex and reconstructs a
|
||||
// FieldIndex object from it.
|
||||
inline FieldIndex FieldIndex::ForLoadByFieldIndex(Map* map, int orig_index) {
|
||||
int field_index = orig_index;
|
||||
@ -85,6 +84,42 @@ inline int FieldIndex::GetLoadByFieldIndex() const {
|
||||
return is_double() ? (result | 1) : result;
|
||||
}
|
||||
|
||||
// Takes an offset as computed by GetLoadByFieldOffset and reconstructs a
|
||||
// FieldIndex object from it.
|
||||
inline FieldIndex FieldIndex::ForLoadByFieldOffset(Map* map, int offset) {
|
||||
bool is_double = offset & 1;
|
||||
int field_index = (offset >> 1) / kPointerSize;
|
||||
int is_inobject = true;
|
||||
int first_inobject_offset = 0;
|
||||
if (field_index < 0) {
|
||||
field_index = -field_index;
|
||||
is_inobject = false;
|
||||
first_inobject_offset = FixedArray::kHeaderSize;
|
||||
} else {
|
||||
first_inobject_offset =
|
||||
map->IsJSObjectMap() ? map->GetInObjectPropertyOffset(0) : 0;
|
||||
}
|
||||
int inobject_properties =
|
||||
map->IsJSObjectMap() ? map->GetInObjectProperties() : 0;
|
||||
FieldIndex result(is_inobject, field_index, is_double, inobject_properties,
|
||||
first_inobject_offset);
|
||||
DCHECK(result.GetLoadByFieldOffset() == offset);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns the offset format consumed by TurboFan stubs:
|
||||
// In-object: zero-based from object start,
|
||||
// out-of-object: zero-based from FixedArray start.
|
||||
inline int FieldIndex::GetLoadByFieldOffset() const {
|
||||
// For efficiency, stubs consume an offset that is optimized for quick
|
||||
// access. If the property is in-object, the offset is positive.
|
||||
// If it's out-of-object, the encoded offset is -raw_offset.
|
||||
// In either case, the offset itself is shifted up by one bit, the lower-most
|
||||
// bit signifying if the field is a mutable double box (1) or not (0).
|
||||
int result = index() << kPointerSizeLog2;
|
||||
if (!is_inobject()) result = -result;
|
||||
return (result << 1) | (is_double() ? 1 : 0);
|
||||
}
|
||||
|
||||
inline FieldIndex FieldIndex::ForDescriptor(Map* map, int descriptor_index) {
|
||||
PropertyDetails details =
|
||||
|
@ -27,10 +27,12 @@ class FieldIndex final {
|
||||
static FieldIndex ForInObjectOffset(int offset, Map* map = NULL);
|
||||
static FieldIndex ForDescriptor(Map* map, int descriptor_index);
|
||||
static FieldIndex ForLoadByFieldIndex(Map* map, int index);
|
||||
static FieldIndex ForLoadByFieldOffset(Map* map, int index);
|
||||
static FieldIndex ForKeyedLookupCacheIndex(Map* map, int index);
|
||||
static FieldIndex FromFieldAccessStubKey(int key);
|
||||
|
||||
int GetLoadByFieldIndex() const;
|
||||
int GetLoadByFieldOffset() const;
|
||||
|
||||
bool is_inobject() const {
|
||||
return IsInObjectBits::decode(bit_field_);
|
||||
|
@ -173,6 +173,7 @@ void FullCodeGenerator::PrepareForBailout(Expression* node,
|
||||
void FullCodeGenerator::CallLoadIC(TypeFeedbackId id) {
|
||||
Handle<Code> ic = CodeFactory::LoadIC(isolate()).code();
|
||||
CallIC(ic, id);
|
||||
if (FLAG_tf_load_ic_stub) RestoreContext();
|
||||
}
|
||||
|
||||
void FullCodeGenerator::CallLoadGlobalIC(TypeofMode typeof_mode,
|
||||
|
@ -577,7 +577,7 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
|
||||
#undef __
|
||||
|
||||
void ElementHandlerCompiler::CompileElementHandlers(
|
||||
MapHandleList* receiver_maps, CodeHandleList* handlers) {
|
||||
MapHandleList* receiver_maps, List<Handle<Object>>* handlers) {
|
||||
for (int i = 0; i < receiver_maps->length(); ++i) {
|
||||
Handle<Map> receiver_map = receiver_maps->at(i);
|
||||
Handle<Code> cached_stub;
|
||||
|
@ -280,7 +280,7 @@ class ElementHandlerCompiler : public PropertyHandlerCompiler {
|
||||
virtual ~ElementHandlerCompiler() {}
|
||||
|
||||
void CompileElementHandlers(MapHandleList* receiver_maps,
|
||||
CodeHandleList* handlers);
|
||||
List<Handle<Object>>* handlers);
|
||||
|
||||
static void GenerateStoreSlow(MacroAssembler* masm);
|
||||
};
|
||||
|
88
src/ic/ic.cc
88
src/ic/ic.cc
@ -541,35 +541,33 @@ void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
|
||||
OnTypeFeedbackChanged(isolate(), get_host());
|
||||
}
|
||||
|
||||
|
||||
void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
|
||||
Handle<Code> handler) {
|
||||
Handle<Object> handler) {
|
||||
DCHECK(UseVector());
|
||||
if (kind() == Code::LOAD_IC) {
|
||||
LoadICNexus* nexus = casted_nexus<LoadICNexus>();
|
||||
nexus->ConfigureMonomorphic(map, handler);
|
||||
} else if (kind() == Code::LOAD_GLOBAL_IC) {
|
||||
LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
|
||||
nexus->ConfigureHandlerMode(handler);
|
||||
nexus->ConfigureHandlerMode(Handle<Code>::cast(handler));
|
||||
} else if (kind() == Code::KEYED_LOAD_IC) {
|
||||
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
|
||||
nexus->ConfigureMonomorphic(name, map, handler);
|
||||
nexus->ConfigureMonomorphic(name, map, Handle<Code>::cast(handler));
|
||||
} else if (kind() == Code::STORE_IC) {
|
||||
StoreICNexus* nexus = casted_nexus<StoreICNexus>();
|
||||
nexus->ConfigureMonomorphic(map, handler);
|
||||
nexus->ConfigureMonomorphic(map, Handle<Code>::cast(handler));
|
||||
} else {
|
||||
DCHECK(kind() == Code::KEYED_STORE_IC);
|
||||
KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
|
||||
nexus->ConfigureMonomorphic(name, map, handler);
|
||||
nexus->ConfigureMonomorphic(name, map, Handle<Code>::cast(handler));
|
||||
}
|
||||
|
||||
vector_set_ = true;
|
||||
OnTypeFeedbackChanged(isolate(), get_host());
|
||||
}
|
||||
|
||||
|
||||
void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
|
||||
CodeHandleList* handlers) {
|
||||
List<Handle<Object>>* handlers) {
|
||||
DCHECK(UseVector());
|
||||
if (kind() == Code::LOAD_IC) {
|
||||
LoadICNexus* nexus = casted_nexus<LoadICNexus>();
|
||||
@ -686,13 +684,15 @@ static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
|
||||
if (!code->is_handler()) return false;
|
||||
bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code) {
|
||||
DCHECK(code->IsSmi() || code->IsCode());
|
||||
if (!code->IsSmi() && !Code::cast(*code)->is_handler()) {
|
||||
return false;
|
||||
}
|
||||
if (is_keyed() && state() != RECOMPUTE_HANDLER) return false;
|
||||
Handle<Map> map = receiver_map();
|
||||
MapHandleList maps;
|
||||
CodeHandleList handlers;
|
||||
List<Handle<Object>> handlers;
|
||||
|
||||
TargetMaps(&maps);
|
||||
int number_of_maps = maps.length();
|
||||
@ -747,16 +747,16 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
|
||||
DCHECK(handler->is_handler());
|
||||
void IC::UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name) {
|
||||
DCHECK(handler->IsSmi() ||
|
||||
(handler->IsCode() && Handle<Code>::cast(handler)->is_handler()));
|
||||
ConfigureVectorState(name, receiver_map(), handler);
|
||||
}
|
||||
|
||||
|
||||
void IC::CopyICToMegamorphicCache(Handle<Name> name) {
|
||||
MapHandleList maps;
|
||||
CodeHandleList handlers;
|
||||
List<Handle<Object>> handlers;
|
||||
TargetMaps(&maps);
|
||||
if (!nexus()->FindHandlers(&handlers, maps.length())) return;
|
||||
for (int i = 0; i < maps.length(); i++) {
|
||||
@ -780,8 +780,8 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
|
||||
return transitioned_map == target_map;
|
||||
}
|
||||
|
||||
|
||||
void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
|
||||
void IC::PatchCache(Handle<Name> name, Handle<Object> code) {
|
||||
DCHECK(code->IsCode() || (kind() == Code::LOAD_IC && code->IsSmi()));
|
||||
switch (state()) {
|
||||
case UNINITIALIZED:
|
||||
case PREMONOMORPHIC:
|
||||
@ -849,8 +849,11 @@ Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate,
|
||||
: isolate->builtins()->KeyedStoreIC_Megamorphic();
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
|
||||
Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) {
|
||||
if (kind() == Code::LOAD_IC && FLAG_tf_load_ic_stub) {
|
||||
return handle(Smi::FromInt(index.GetLoadByFieldOffset()), isolate());
|
||||
}
|
||||
DCHECK(kind() == Code::KEYED_LOAD_IC || !FLAG_tf_load_ic_stub);
|
||||
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub);
|
||||
LoadFieldStub stub(isolate(), index);
|
||||
return stub.GetCode();
|
||||
@ -905,7 +908,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
|
||||
return;
|
||||
}
|
||||
|
||||
Handle<Code> code;
|
||||
Handle<Object> code;
|
||||
if (lookup->state() == LookupIterator::JSPROXY ||
|
||||
lookup->state() == LookupIterator::ACCESS_CHECK) {
|
||||
code = slow_stub();
|
||||
@ -980,15 +983,31 @@ StubCache* IC::stub_cache() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
|
||||
stub_cache()->Set(name, map, code);
|
||||
void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* code) {
|
||||
if (code->IsSmi()) {
|
||||
// TODO(jkummerow): Support Smis in the code cache.
|
||||
Handle<Map> map_handle(map, isolate());
|
||||
Handle<Name> name_handle(name, isolate());
|
||||
FieldIndex index =
|
||||
FieldIndex::ForLoadByFieldOffset(map, Smi::cast(code)->value());
|
||||
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub);
|
||||
LoadFieldStub stub(isolate(), index);
|
||||
Code* handler = *stub.GetCode();
|
||||
stub_cache()->Set(*name_handle, *map_handle, handler);
|
||||
return;
|
||||
}
|
||||
DCHECK(code->IsCode());
|
||||
stub_cache()->Set(name, map, Code::cast(code));
|
||||
}
|
||||
|
||||
|
||||
Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
|
||||
Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
|
||||
Handle<Object> value) {
|
||||
// Try to find a globally shared handler stub.
|
||||
Handle<Code> code = GetMapIndependentHandler(lookup);
|
||||
if (!code.is_null()) return code;
|
||||
Handle<Object> handler_or_index = GetMapIndependentHandler(lookup);
|
||||
if (!handler_or_index.is_null()) {
|
||||
DCHECK(handler_or_index->IsCode() || handler_or_index->IsSmi());
|
||||
return handler_or_index;
|
||||
}
|
||||
|
||||
// Otherwise check the map's handler cache for a map-specific handler, and
|
||||
// compile one if the cache comes up empty.
|
||||
@ -1007,12 +1026,12 @@ Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
|
||||
stub_holder_map = receiver_map();
|
||||
}
|
||||
|
||||
code = PropertyHandlerCompiler::Find(lookup->name(), stub_holder_map, kind(),
|
||||
flag);
|
||||
Handle<Code> code = PropertyHandlerCompiler::Find(
|
||||
lookup->name(), stub_holder_map, kind(), flag);
|
||||
// Use the cached value if it exists, and if it is different from the
|
||||
// handler that just missed.
|
||||
if (!code.is_null()) {
|
||||
Handle<Code> handler;
|
||||
Handle<Object> handler;
|
||||
if (maybe_handler_.ToHandle(&handler)) {
|
||||
if (!handler.is_identical_to(code)) {
|
||||
TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
|
||||
@ -1045,7 +1064,7 @@ Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
|
||||
return code;
|
||||
}
|
||||
|
||||
Handle<Code> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
Handle<Object> receiver = lookup->GetReceiver();
|
||||
if (receiver->IsString() &&
|
||||
Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
|
||||
@ -1389,7 +1408,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
|
||||
return;
|
||||
}
|
||||
|
||||
CodeHandleList handlers(target_receiver_maps.length());
|
||||
List<Handle<Object>> handlers(target_receiver_maps.length());
|
||||
TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_PolymorphicElement);
|
||||
ElementHandlerCompiler compiler(isolate());
|
||||
compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
|
||||
@ -1606,7 +1625,8 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
|
||||
if (!use_ic) {
|
||||
TRACE_GENERIC_IC(isolate(), "StoreIC", "LookupForWrite said 'false'");
|
||||
}
|
||||
Handle<Code> code = use_ic ? ComputeHandler(lookup, value) : slow_stub();
|
||||
Handle<Code> code =
|
||||
use_ic ? Handle<Code>::cast(ComputeHandler(lookup, value)) : slow_stub();
|
||||
|
||||
PatchCache(lookup->name(), code);
|
||||
TRACE_IC("StoreIC", lookup->name());
|
||||
@ -1628,7 +1648,7 @@ static Handle<Code> PropertyCellStoreHandler(
|
||||
return code;
|
||||
}
|
||||
|
||||
Handle<Code> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
|
||||
|
||||
// This is currently guaranteed by checks in StoreIC::Store.
|
||||
|
26
src/ic/ic.h
26
src/ic/ic.h
@ -107,10 +107,10 @@ class IC {
|
||||
void ConfigureVectorState(IC::State new_state, Handle<Object> key);
|
||||
// Configure the vector for MONOMORPHIC.
|
||||
void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
|
||||
Handle<Code> handler);
|
||||
Handle<Object> handler);
|
||||
// Configure the vector for POLYMORPHIC.
|
||||
void ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
|
||||
CodeHandleList* handlers);
|
||||
List<Handle<Object>>* handlers);
|
||||
// Configure the vector for POLYMORPHIC with transitions (only for element
|
||||
// keyed stores).
|
||||
void ConfigureVectorState(MapHandleList* maps,
|
||||
@ -136,9 +136,9 @@ class IC {
|
||||
static void PostPatching(Address address, Code* target, Code* old_target);
|
||||
|
||||
// Compute the handler either by compiling or by retrieving a cached version.
|
||||
Handle<Code> ComputeHandler(LookupIterator* lookup,
|
||||
Handle<Object> value = Handle<Code>::null());
|
||||
virtual Handle<Code> GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
Handle<Object> ComputeHandler(LookupIterator* lookup,
|
||||
Handle<Object> value = Handle<Code>::null());
|
||||
virtual Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
UNREACHABLE();
|
||||
return Handle<Code>::null();
|
||||
}
|
||||
@ -149,15 +149,15 @@ class IC {
|
||||
return Handle<Code>::null();
|
||||
}
|
||||
|
||||
void UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name);
|
||||
bool UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code);
|
||||
void UpdateMegamorphicCache(Map* map, Name* name, Code* code);
|
||||
void UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name);
|
||||
bool UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code);
|
||||
void UpdateMegamorphicCache(Map* map, Name* name, Object* code);
|
||||
|
||||
StubCache* stub_cache();
|
||||
|
||||
void CopyICToMegamorphicCache(Handle<Name> name);
|
||||
bool IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map);
|
||||
void PatchCache(Handle<Name> name, Handle<Code> code);
|
||||
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;
|
||||
@ -239,7 +239,7 @@ class IC {
|
||||
State state_;
|
||||
Code::Kind kind_;
|
||||
Handle<Map> receiver_map_;
|
||||
MaybeHandle<Code> maybe_handler_;
|
||||
MaybeHandle<Object> maybe_handler_;
|
||||
|
||||
ExtraICState extra_ic_state_;
|
||||
MapHandleList target_maps_;
|
||||
@ -305,13 +305,13 @@ class LoadIC : public IC {
|
||||
// lookup result.
|
||||
void UpdateCaches(LookupIterator* lookup);
|
||||
|
||||
Handle<Code> GetMapIndependentHandler(LookupIterator* lookup) override;
|
||||
Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
|
||||
|
||||
Handle<Code> CompileHandler(LookupIterator* lookup, Handle<Object> unused,
|
||||
CacheHolderFlag cache_holder) override;
|
||||
|
||||
private:
|
||||
Handle<Code> SimpleFieldLoad(FieldIndex index);
|
||||
Handle<Object> SimpleFieldLoad(FieldIndex index);
|
||||
|
||||
friend class IC;
|
||||
};
|
||||
@ -418,7 +418,7 @@ class StoreIC : public IC {
|
||||
// lookup result.
|
||||
void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
|
||||
JSReceiver::StoreFromKeyed store_mode);
|
||||
Handle<Code> GetMapIndependentHandler(LookupIterator* lookup) override;
|
||||
Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
|
||||
Handle<Code> CompileHandler(LookupIterator* lookup, Handle<Object> value,
|
||||
CacheHolderFlag cache_holder) override;
|
||||
|
||||
|
@ -427,10 +427,9 @@ Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
|
||||
return Handle<FixedArray>::cast(feedback_extra);
|
||||
}
|
||||
|
||||
|
||||
void FeedbackNexus::InstallHandlers(Handle<FixedArray> array,
|
||||
MapHandleList* maps,
|
||||
CodeHandleList* handlers) {
|
||||
List<Handle<Object>>* handlers) {
|
||||
int receiver_count = maps->length();
|
||||
for (int current = 0; current < receiver_count; ++current) {
|
||||
Handle<Map> map = maps->at(current);
|
||||
@ -656,9 +655,8 @@ void CallICNexus::ConfigureMegamorphic(int call_count) {
|
||||
SetFeedbackExtra(Smi::FromInt(call_count), SKIP_WRITE_BARRIER);
|
||||
}
|
||||
|
||||
|
||||
void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
|
||||
Handle<Code> handler) {
|
||||
Handle<Object> handler) {
|
||||
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
|
||||
SetFeedback(*cell);
|
||||
SetFeedbackExtra(*handler);
|
||||
@ -722,9 +720,8 @@ void KeyedStoreICNexus::ConfigureMonomorphic(Handle<Name> name,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
|
||||
CodeHandleList* handlers) {
|
||||
List<Handle<Object>>* handlers) {
|
||||
Isolate* isolate = GetIsolate();
|
||||
int receiver_count = maps->length();
|
||||
Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
|
||||
@ -735,7 +732,7 @@ void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
|
||||
|
||||
void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
|
||||
MapHandleList* maps,
|
||||
CodeHandleList* handlers) {
|
||||
List<Handle<Object>>* handlers) {
|
||||
int receiver_count = maps->length();
|
||||
DCHECK(receiver_count > 1);
|
||||
Handle<FixedArray> array;
|
||||
@ -751,9 +748,8 @@ void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
|
||||
InstallHandlers(array, maps, handlers);
|
||||
}
|
||||
|
||||
|
||||
void StoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
|
||||
CodeHandleList* handlers) {
|
||||
List<Handle<Object>>* handlers) {
|
||||
Isolate* isolate = GetIsolate();
|
||||
int receiver_count = maps->length();
|
||||
Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
|
||||
@ -762,10 +758,9 @@ void StoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
|
||||
SKIP_WRITE_BARRIER);
|
||||
}
|
||||
|
||||
|
||||
void KeyedStoreICNexus::ConfigurePolymorphic(Handle<Name> name,
|
||||
MapHandleList* maps,
|
||||
CodeHandleList* handlers) {
|
||||
List<Handle<Object>>* handlers) {
|
||||
int receiver_count = maps->length();
|
||||
DCHECK(receiver_count > 1);
|
||||
Handle<FixedArray> array;
|
||||
@ -807,6 +802,30 @@ void KeyedStoreICNexus::ConfigurePolymorphic(MapHandleList* maps,
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
int GetStepSize(FixedArray* array, Isolate* isolate) {
|
||||
// The array should be of the form
|
||||
// [map, handler, map, handler, ...]
|
||||
// or
|
||||
// [map, map, handler, map, map, handler, ...]
|
||||
// where "map" is either a WeakCell or |undefined|,
|
||||
// and "handler" is either a Code object or a Smi.
|
||||
DCHECK(array->length() >= 2);
|
||||
Object* second = array->get(1);
|
||||
if (second->IsWeakCell() || second->IsUndefined(isolate)) return 3;
|
||||
DCHECK(second->IsCode() || second->IsSmi());
|
||||
return 2;
|
||||
}
|
||||
|
||||
#ifdef DEBUG // Only used by DCHECKs below.
|
||||
bool IsHandler(Object* object) {
|
||||
return object->IsSmi() ||
|
||||
(object->IsCode() && Code::cast(object)->is_handler());
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
|
||||
Isolate* isolate = GetIsolate();
|
||||
@ -818,12 +837,7 @@ int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
|
||||
feedback = GetFeedbackExtra();
|
||||
}
|
||||
FixedArray* array = FixedArray::cast(feedback);
|
||||
// The array should be of the form
|
||||
// [map, handler, map, handler, ...]
|
||||
// or
|
||||
// [map, map, handler, map, map, handler, ...]
|
||||
DCHECK(array->length() >= 2);
|
||||
int increment = array->get(1)->IsCode() ? 2 : 3;
|
||||
int increment = GetStepSize(array, isolate);
|
||||
for (int i = 0; i < array->length(); i += increment) {
|
||||
DCHECK(array->get(i)->IsWeakCell());
|
||||
WeakCell* cell = WeakCell::cast(array->get(i));
|
||||
@ -846,26 +860,25 @@ int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
|
||||
MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
|
||||
Object* feedback = GetFeedback();
|
||||
Isolate* isolate = GetIsolate();
|
||||
bool is_named_feedback = IsPropertyNameFeedback(feedback);
|
||||
if (feedback->IsFixedArray() || is_named_feedback) {
|
||||
if (is_named_feedback) {
|
||||
feedback = GetFeedbackExtra();
|
||||
}
|
||||
FixedArray* array = FixedArray::cast(feedback);
|
||||
DCHECK(array->length() >= 2);
|
||||
int increment = array->get(1)->IsCode() ? 2 : 3;
|
||||
int increment = GetStepSize(array, isolate);
|
||||
for (int i = 0; i < array->length(); i += increment) {
|
||||
DCHECK(array->get(i)->IsWeakCell());
|
||||
WeakCell* cell = WeakCell::cast(array->get(i));
|
||||
if (!cell->cleared()) {
|
||||
Map* array_map = Map::cast(cell->value());
|
||||
if (array_map == *map) {
|
||||
Code* code = Code::cast(array->get(i + increment - 1));
|
||||
DCHECK(code->kind() == Code::HANDLER);
|
||||
return handle(code);
|
||||
Object* code = array->get(i + increment - 1);
|
||||
DCHECK(IsHandler(code));
|
||||
return handle(code, isolate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -874,9 +887,9 @@ MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
|
||||
if (!cell->cleared()) {
|
||||
Map* cell_map = Map::cast(cell->value());
|
||||
if (cell_map == *map) {
|
||||
Code* code = Code::cast(GetFeedbackExtra());
|
||||
DCHECK(code->kind() == Code::HANDLER);
|
||||
return handle(code);
|
||||
Object* code = GetFeedbackExtra();
|
||||
DCHECK(IsHandler(code));
|
||||
return handle(code, isolate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -884,9 +897,10 @@ MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
|
||||
return MaybeHandle<Code>();
|
||||
}
|
||||
|
||||
|
||||
bool FeedbackNexus::FindHandlers(CodeHandleList* code_list, int length) const {
|
||||
bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list,
|
||||
int length) const {
|
||||
Object* feedback = GetFeedback();
|
||||
Isolate* isolate = GetIsolate();
|
||||
int count = 0;
|
||||
bool is_named_feedback = IsPropertyNameFeedback(feedback);
|
||||
if (feedback->IsFixedArray() || is_named_feedback) {
|
||||
@ -894,29 +908,24 @@ bool FeedbackNexus::FindHandlers(CodeHandleList* code_list, int length) const {
|
||||
feedback = GetFeedbackExtra();
|
||||
}
|
||||
FixedArray* array = FixedArray::cast(feedback);
|
||||
// The array should be of the form
|
||||
// [map, handler, map, handler, ...]
|
||||
// or
|
||||
// [map, map, handler, map, map, handler, ...]
|
||||
// Be sure to skip handlers whose maps have been cleared.
|
||||
DCHECK(array->length() >= 2);
|
||||
int increment = array->get(1)->IsCode() ? 2 : 3;
|
||||
int increment = GetStepSize(array, isolate);
|
||||
for (int i = 0; i < array->length(); i += increment) {
|
||||
DCHECK(array->get(i)->IsWeakCell());
|
||||
WeakCell* cell = WeakCell::cast(array->get(i));
|
||||
// Be sure to skip handlers whose maps have been cleared.
|
||||
if (!cell->cleared()) {
|
||||
Code* code = Code::cast(array->get(i + increment - 1));
|
||||
DCHECK(code->kind() == Code::HANDLER);
|
||||
code_list->Add(handle(code));
|
||||
Object* code = array->get(i + increment - 1);
|
||||
DCHECK(IsHandler(code));
|
||||
code_list->Add(handle(code, isolate));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
} else if (feedback->IsWeakCell()) {
|
||||
WeakCell* cell = WeakCell::cast(feedback);
|
||||
if (!cell->cleared()) {
|
||||
Code* code = Code::cast(GetFeedbackExtra());
|
||||
DCHECK(code->kind() == Code::HANDLER);
|
||||
code_list->Add(handle(code));
|
||||
Object* code = GetFeedbackExtra();
|
||||
DCHECK(IsHandler(code));
|
||||
code_list->Add(handle(code, isolate));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@ -966,7 +975,7 @@ void KeyedStoreICNexus::Clear(Code* host) {
|
||||
KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
|
||||
KeyedAccessStoreMode mode = STANDARD_STORE;
|
||||
MapHandleList maps;
|
||||
CodeHandleList handlers;
|
||||
List<Handle<Object>> handlers;
|
||||
|
||||
if (GetKeyType() == PROPERTY) return mode;
|
||||
|
||||
@ -974,7 +983,7 @@ KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
|
||||
FindHandlers(&handlers, maps.length());
|
||||
for (int i = 0; i < handlers.length(); i++) {
|
||||
// The first handler that isn't the slow handler will have the bits we need.
|
||||
Handle<Code> handler = handlers.at(i);
|
||||
Handle<Code> handler = Handle<Code>::cast(handlers.at(i));
|
||||
CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key());
|
||||
uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key());
|
||||
CHECK(major_key == CodeStub::KeyedStoreSloppyArguments ||
|
||||
|
@ -412,8 +412,9 @@ class FeedbackNexus {
|
||||
|
||||
virtual InlineCacheState StateFromFeedback() const = 0;
|
||||
virtual int ExtractMaps(MapHandleList* maps) const;
|
||||
virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const;
|
||||
virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const;
|
||||
virtual MaybeHandle<Object> FindHandlerForMap(Handle<Map> map) const;
|
||||
virtual bool FindHandlers(List<Handle<Object>>* code_list,
|
||||
int length = -1) const;
|
||||
virtual Name* FindFirstName() const { return NULL; }
|
||||
|
||||
virtual void ConfigureUninitialized();
|
||||
@ -434,7 +435,7 @@ class FeedbackNexus {
|
||||
Handle<FixedArray> EnsureArrayOfSize(int length);
|
||||
Handle<FixedArray> EnsureExtraArrayOfSize(int length);
|
||||
void InstallHandlers(Handle<FixedArray> array, MapHandleList* maps,
|
||||
CodeHandleList* handlers);
|
||||
List<Handle<Object>>* handlers);
|
||||
|
||||
private:
|
||||
// The reason for having a vector handle and a raw pointer is that we can and
|
||||
@ -471,10 +472,11 @@ class CallICNexus final : public FeedbackNexus {
|
||||
// CallICs don't record map feedback.
|
||||
return 0;
|
||||
}
|
||||
MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const final {
|
||||
MaybeHandle<Object> FindHandlerForMap(Handle<Map> map) const final {
|
||||
return MaybeHandle<Code>();
|
||||
}
|
||||
bool FindHandlers(CodeHandleList* code_list, int length = -1) const final {
|
||||
bool FindHandlers(List<Handle<Object>>* code_list,
|
||||
int length = -1) const final {
|
||||
return length == 0;
|
||||
}
|
||||
|
||||
@ -499,9 +501,10 @@ class LoadICNexus : public FeedbackNexus {
|
||||
|
||||
void Clear(Code* host);
|
||||
|
||||
void ConfigureMonomorphic(Handle<Map> receiver_map, Handle<Code> handler);
|
||||
void ConfigureMonomorphic(Handle<Map> receiver_map, Handle<Object> handler);
|
||||
|
||||
void ConfigurePolymorphic(MapHandleList* maps, CodeHandleList* handlers);
|
||||
void ConfigurePolymorphic(MapHandleList* maps,
|
||||
List<Handle<Object>>* handlers);
|
||||
|
||||
InlineCacheState StateFromFeedback() const override;
|
||||
};
|
||||
@ -521,10 +524,11 @@ class LoadGlobalICNexus : public FeedbackNexus {
|
||||
// LoadGlobalICs don't record map feedback.
|
||||
return 0;
|
||||
}
|
||||
MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const final {
|
||||
MaybeHandle<Object> FindHandlerForMap(Handle<Map> map) const final {
|
||||
return MaybeHandle<Code>();
|
||||
}
|
||||
bool FindHandlers(CodeHandleList* code_list, int length = -1) const final {
|
||||
bool FindHandlers(List<Handle<Object>>* code_list,
|
||||
int length = -1) const final {
|
||||
return length == 0;
|
||||
}
|
||||
|
||||
@ -556,7 +560,7 @@ class KeyedLoadICNexus : public FeedbackNexus {
|
||||
Handle<Code> handler);
|
||||
// name can be null.
|
||||
void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
|
||||
CodeHandleList* handlers);
|
||||
List<Handle<Object>>* handlers);
|
||||
|
||||
void ConfigureMegamorphicKeyed(IcCheckType property_type);
|
||||
|
||||
@ -585,7 +589,8 @@ class StoreICNexus : public FeedbackNexus {
|
||||
|
||||
void ConfigureMonomorphic(Handle<Map> receiver_map, Handle<Code> handler);
|
||||
|
||||
void ConfigurePolymorphic(MapHandleList* maps, CodeHandleList* handlers);
|
||||
void ConfigurePolymorphic(MapHandleList* maps,
|
||||
List<Handle<Object>>* handlers);
|
||||
|
||||
InlineCacheState StateFromFeedback() const override;
|
||||
};
|
||||
@ -613,7 +618,7 @@ class KeyedStoreICNexus : public FeedbackNexus {
|
||||
Handle<Code> handler);
|
||||
// name can be null.
|
||||
void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
|
||||
CodeHandleList* handlers);
|
||||
List<Handle<Object>>* handlers);
|
||||
void ConfigurePolymorphic(MapHandleList* maps,
|
||||
MapHandleList* transitioned_maps,
|
||||
CodeHandleList* handlers);
|
||||
|
Loading…
Reference in New Issue
Block a user