Commit 9a6ee8d6 authored by jkummerow's avatar jkummerow Committed by Commit bot

[KeyedLoadIC] Support Smi "handlers" for simple field loads

This ports 9c59539f / r37803 to KeyedLoadICs.

Review-Url: https://codereview.chromium.org/2182103002
Cr-Commit-Position: refs/heads/master@{#38070}
parent ec416574
......@@ -49,6 +49,10 @@ Callable CodeFactory::LoadGlobalICInOptimizedCode(Isolate* isolate,
// static
Callable CodeFactory::KeyedLoadIC(Isolate* isolate) {
if (FLAG_tf_load_ic_stub) {
KeyedLoadICTrampolineTFStub stub(isolate);
return Callable(stub.GetCode(), LoadDescriptor(isolate));
}
KeyedLoadICTrampolineStub stub(isolate);
return Callable(stub.GetCode(), LoadDescriptor(isolate));
}
......@@ -56,11 +60,15 @@ Callable CodeFactory::KeyedLoadIC(Isolate* isolate) {
// static
Callable CodeFactory::KeyedLoadICInOptimizedCode(Isolate* isolate) {
auto code =
KeyedLoadIC::initialize_stub_in_optimized_code(isolate, kNoExtraICState);
auto code = KeyedLoadIC::initialize_stub_in_optimized_code(isolate);
return Callable(code, LoadWithVectorDescriptor(isolate));
}
// static
Callable CodeFactory::KeyedLoadIC_Megamorphic(Isolate* isolate) {
return Callable(isolate->builtins()->KeyedLoadIC_Megamorphic(),
LoadWithVectorDescriptor(isolate));
}
// static
Callable CodeFactory::CallIC(Isolate* isolate, int argc,
......
......@@ -39,6 +39,7 @@ class CodeFactory final {
TypeofMode typeof_mode);
static Callable KeyedLoadIC(Isolate* isolate);
static Callable KeyedLoadICInOptimizedCode(Isolate* isolate);
static Callable KeyedLoadIC_Megamorphic(Isolate* isolate);
static Callable CallIC(Isolate* isolate, int argc,
ConvertReceiverMode mode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow);
......
......@@ -2416,7 +2416,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Node* elements = LoadElements(object);
Node* length = LoadFixedArrayBaseLength(elements);
GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found);
GotoUnless(Uint32LessThan(index, SmiToWord32(length)), if_not_found);
Node* element = LoadFixedArrayElement(elements, index);
Node* the_hole = TheHoleConstant();
......@@ -2427,7 +2427,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Node* elements = LoadElements(object);
Node* length = LoadFixedArrayBaseLength(elements);
GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found);
GotoUnless(Uint32LessThan(index, SmiToWord32(length)), if_not_found);
if (kPointerSize == kDoubleSize) {
Node* element =
......@@ -2456,7 +2456,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Assert(Int32LessThan(LoadInstanceType(string),
Int32Constant(FIRST_NONSTRING_TYPE)));
Node* length = LoadStringLength(string);
GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found);
GotoIf(Uint32LessThan(index, SmiToWord32(length)), if_found);
Goto(&if_isobjectorsmi);
}
Bind(&if_isslowstringwrapper);
......@@ -2466,7 +2466,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Assert(Int32LessThan(LoadInstanceType(string),
Int32Constant(FIRST_NONSTRING_TYPE)));
Node* length = LoadStringLength(string);
GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found);
GotoIf(Uint32LessThan(index, SmiToWord32(length)), if_found);
Goto(&if_isdictionary);
}
}
......@@ -2977,6 +2977,71 @@ void CodeStubAssembler::TryProbeStubCache(
}
}
void CodeStubAssembler::HandleLoadICHandlerCase(const LoadICParameters* p,
Node* handler, Label* miss) {
Comment("have_handler");
Label call_handler(this);
GotoUnless(WordIsSmi(handler), &call_handler);
// |handler| is a Smi. It encodes a field index as obtained by
// FieldIndex.GetLoadByFieldOffset().
// TODO(jkummerow): For KeyedLoadICs, extend this scheme to encode
// fast *element* loads.
{
Variable var_double_value(this, MachineRepresentation::kFloat64);
Label rebox_double(this, &var_double_value);
Node* handler_word = SmiUntag(handler);
// |handler_word| is a field index as obtained by
// FieldIndex.GetLoadByFieldOffset():
Label inobject_double(this), out_of_object(this),
out_of_object_double(this);
Node* inobject_bit = WordAnd(
handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsInobject::kMask));
Node* double_bit = WordAnd(
handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsDouble::kMask));
Node* offset = WordSar(
handler_word, IntPtrConstant(FieldIndex::FieldOffsetOffset::kShift));
GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object);
GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &inobject_double);
Return(LoadObjectField(p->receiver, offset));
Bind(&inobject_double);
if (FLAG_unbox_double_fields) {
var_double_value.Bind(
LoadObjectField(p->receiver, offset, MachineType::Float64()));
} else {
Node* mutable_heap_number = LoadObjectField(p->receiver, offset);
var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
}
Goto(&rebox_double);
Bind(&out_of_object);
Node* properties = LoadProperties(p->receiver);
Node* value = LoadObjectField(properties, offset);
GotoUnless(WordEqual(double_bit, IntPtrConstant(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);
typedef LoadWithVectorDescriptor Descriptor;
TailCallStub(Descriptor(isolate()), handler, p->context,
Arg(Descriptor::kReceiver, p->receiver),
Arg(Descriptor::kName, p->name),
Arg(Descriptor::kSlot, p->slot),
Arg(Descriptor::kVector, p->vector));
}
void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
Variable var_handler(this, MachineRepresentation::kTagged);
// TODO(ishell): defer blocks when it works.
......@@ -2991,66 +3056,7 @@ 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);
typedef LoadWithVectorDescriptor Descriptor;
TailCallStub(Descriptor(isolate()), var_handler.value(), p->context,
Arg(Descriptor::kReceiver, p->receiver),
Arg(Descriptor::kName, p->name),
Arg(Descriptor::kSlot, p->slot),
Arg(Descriptor::kVector, p->vector));
HandleLoadICHandlerCase(p, var_handler.value(), &miss);
}
Bind(&try_polymorphic);
......@@ -3081,6 +3087,68 @@ void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
}
}
void CodeStubAssembler::KeyedLoadIC(const LoadICParameters* p) {
Variable var_handler(this, MachineRepresentation::kTagged);
// TODO(ishell): defer blocks when it works.
Label if_handler(this, &var_handler), try_polymorphic(this),
try_megamorphic(this /*, Label::kDeferred*/),
try_polymorphic_name(this /*, Label::kDeferred*/),
miss(this /*, Label::kDeferred*/);
Node* receiver_map = LoadReceiverMap(p->receiver);
// Check monomorphic case.
Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
Bind(&if_handler);
{
HandleLoadICHandlerCase(p, var_handler.value(), &miss);
}
Bind(&try_polymorphic);
{
// Check polymorphic case.
Comment("KeyedLoadIC_try_polymorphic");
GotoUnless(
WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
&try_megamorphic);
HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler,
&miss, 2);
}
Bind(&try_megamorphic);
{
// Check megamorphic case.
Comment("KeyedLoadIC_try_megamorphic");
GotoUnless(
WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
&try_polymorphic_name);
// TODO(jkummerow): Inline this? Or some of it?
TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context,
p->receiver, p->name, p->slot, p->vector);
}
Bind(&try_polymorphic_name);
{
// We might have a name in feedback, and a fixed array in the next slot.
Comment("KeyedLoadIC_try_polymorphic_name");
GotoUnless(WordEqual(feedback, p->name), &miss);
// If the name comparison succeeded, we know we have a fixed array with
// at least one map/handler pair.
Node* offset = ElementOffsetFromIndex(
p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
HandlePolymorphicCase(p, receiver_map, array, &if_handler, &var_handler,
&miss, 1);
}
Bind(&miss);
{
Comment("KeyedLoadIC_miss");
TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
p->name, p->slot, p->vector);
}
}
void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) {
Label try_handler(this), miss(this);
Node* weak_cell =
......
......@@ -449,6 +449,9 @@ class CodeStubAssembler : public compiler::CodeAssembler {
Variable* var_handler, Label* if_miss,
int unroll_count);
void HandleLoadICHandlerCase(const LoadICParameters* p,
compiler::Node* handler, Label* miss);
compiler::Node* StubCachePrimaryOffset(compiler::Node* name,
compiler::Node* map);
......@@ -471,6 +474,7 @@ class CodeStubAssembler : public compiler::CodeAssembler {
void LoadIC(const LoadICParameters* p);
void LoadGlobalIC(const LoadICParameters* p);
void KeyedLoadIC(const LoadICParameters* p);
// Get the enumerable length from |map| and return the result as a Smi.
compiler::Node* EnumLength(compiler::Node* map);
......
......@@ -469,6 +469,33 @@ void LoadGlobalICStub::GenerateAssembly(CodeStubAssembler* assembler) const {
assembler->LoadGlobalIC(&p);
}
void KeyedLoadICTrampolineTFStub::GenerateAssembly(
CodeStubAssembler* assembler) const {
typedef compiler::Node Node;
Node* receiver = assembler->Parameter(Descriptor::kReceiver);
Node* name = assembler->Parameter(Descriptor::kName);
Node* slot = assembler->Parameter(Descriptor::kSlot);
Node* context = assembler->Parameter(Descriptor::kContext);
Node* vector = assembler->LoadTypeFeedbackVectorForStub();
CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
assembler->KeyedLoadIC(&p);
}
void KeyedLoadICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const {
typedef compiler::Node Node;
Node* receiver = assembler->Parameter(Descriptor::kReceiver);
Node* name = assembler->Parameter(Descriptor::kName);
Node* slot = assembler->Parameter(Descriptor::kSlot);
Node* vector = assembler->Parameter(Descriptor::kVector);
Node* context = assembler->Parameter(Descriptor::kContext);
CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
assembler->KeyedLoadIC(&p);
}
void AllocateHeapNumberStub::GenerateAssembly(
CodeStubAssembler* assembler) const {
typedef compiler::Node Node;
......
......@@ -140,6 +140,8 @@ namespace internal {
V(GetProperty) \
V(LoadICTrampolineTF) \
V(LoadICTF) \
V(KeyedLoadICTrampolineTF) \
V(KeyedLoadICTF) \
/* IC Handler stubs */ \
V(KeyedLoadSloppyArguments) \
V(KeyedStoreSloppyArguments) \
......@@ -2350,6 +2352,18 @@ class KeyedLoadICTrampolineStub : public LoadICTrampolineStub {
DEFINE_PLATFORM_CODE_STUB(KeyedLoadICTrampoline, LoadICTrampolineStub);
};
class KeyedLoadICTrampolineTFStub : public LoadICTrampolineTFStub {
public:
explicit KeyedLoadICTrampolineTFStub(Isolate* isolate)
: LoadICTrampolineTFStub(isolate) {}
void GenerateAssembly(CodeStubAssembler* assembler) const override;
Code::Kind GetCodeKind() const override { return Code::KEYED_LOAD_IC; }
DEFINE_CODE_STUB(KeyedLoadICTrampolineTF, LoadICTrampolineTFStub);
};
class StoreICTrampolineStub : public PlatformCodeStub {
public:
StoreICTrampolineStub(Isolate* isolate, const StoreICState& state)
......@@ -2468,6 +2482,17 @@ class KeyedLoadICStub : public PlatformCodeStub {
void GenerateImpl(MacroAssembler* masm, bool in_frame);
};
class KeyedLoadICTFStub : public LoadICTFStub {
public:
explicit KeyedLoadICTFStub(Isolate* isolate) : LoadICTFStub(isolate) {}
void GenerateAssembly(CodeStubAssembler* assembler) const override;
Code::Kind GetCodeKind() const override { return Code::KEYED_LOAD_IC; }
DEFINE_CODE_STUB(KeyedLoadICTF, LoadICTFStub);
};
class StoreICStub : public PlatformCodeStub {
public:
StoreICStub(Isolate* isolate, const StoreICState& state)
......
......@@ -653,6 +653,14 @@ Node* CodeAssembler::TailCallStub(Callable const& callable, Node* context,
result_size);
}
Node* CodeAssembler::TailCallStub(Callable const& callable, Node* context,
Node* arg1, Node* arg2, Node* arg3,
Node* arg4, size_t result_size) {
Node* target = HeapConstant(callable.code());
return TailCallStub(callable.descriptor(), target, context, arg1, arg2, arg3,
arg4, result_size);
}
Node* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
Node* target, Node* context, Node* arg1,
size_t result_size) {
......
......@@ -383,6 +383,9 @@ class CodeAssembler {
Node* arg2, size_t result_size = 1);
Node* TailCallStub(Callable const& callable, Node* context, Node* arg1,
Node* arg2, Node* arg3, size_t result_size = 1);
Node* TailCallStub(Callable const& callable, Node* context, Node* arg1,
Node* arg2, Node* arg3, Node* arg4,
size_t result_size = 1);
Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
Node* context, Node* arg1, size_t result_size = 1);
Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
......
......@@ -705,7 +705,7 @@ class RuntimeCallTimer {
V(KeyedLoadIC_KeyedLoadSloppyArgumentsStub) \
V(KeyedLoadIC_LoadFastElementStub) \
V(KeyedLoadIC_LoadDictionaryElementStub) \
V(KeyedLoadIC_PolymorphicElement) \
V(KeyedLoadIC_SlowStub) \
V(KeyedStoreIC_KeyedStoreSloppyArgumentsStub) \
V(KeyedStoreIC_StoreFastElementStub) \
V(KeyedStoreIC_StoreElementStub) \
......
......@@ -86,18 +86,18 @@ inline int FieldIndex::GetLoadByFieldIndex() const {
// Takes an offset as computed by GetLoadByFieldOffset and reconstructs a
// FieldIndex object from it.
// static
inline FieldIndex FieldIndex::ForLoadByFieldOffset(Map* map, int offset) {
bool is_double = offset & 1;
int field_index = (offset >> 1) / kPointerSize;
int is_inobject = true;
DCHECK(offset & 1); // Property marker (as opposed to element).
bool is_inobject = FieldOffsetIsInobject::decode(offset);
bool is_double = FieldOffsetIsDouble::decode(offset);
int field_index = FieldOffsetOffset::decode(offset) >> kPointerSizeLog2;
int first_inobject_offset = 0;
if (field_index < 0) {
field_index = -field_index;
is_inobject = false;
first_inobject_offset = FixedArray::kHeaderSize;
} else {
if (is_inobject) {
first_inobject_offset =
map->IsJSObjectMap() ? map->GetInObjectPropertyOffset(0) : 0;
} else {
first_inobject_offset = FixedArray::kHeaderSize;
}
int inobject_properties =
map->IsJSObjectMap() ? map->GetInObjectProperties() : 0;
......@@ -108,17 +108,13 @@ inline FieldIndex FieldIndex::ForLoadByFieldOffset(Map* map, int offset) {
}
// Returns the offset format consumed by TurboFan stubs:
// In-object: zero-based from object start,
// out-of-object: zero-based from FixedArray start.
// (offset << 3) | (is_double << 2) | (is_inobject << 1) | is_property
// Where |offset| is relative to object start or FixedArray start, respectively.
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);
return FieldOffsetIsInobject::encode(is_inobject()) |
FieldOffsetIsDouble::encode(is_double()) |
FieldOffsetOffset::encode(index() << kPointerSizeLog2) |
1; // Property marker (as opposed to element).
}
inline FieldIndex FieldIndex::ForDescriptor(Map* map, int descriptor_index) {
......
......@@ -76,6 +76,13 @@ class FieldIndex final {
(IsInObjectBits::kMask | IsDoubleBits::kMask | IndexBits::kMask);
}
// For GetLoadByFieldOffset.
class FieldOffsetIsInobject : public BitField<bool, 1, 1> {};
class FieldOffsetIsDouble : public BitField<bool, 2, 1> {};
class FieldOffsetOffset : public BitField<int, 3, 27> {};
// Make sure we don't overflow into the sign bit.
STATIC_ASSERT(FieldOffsetOffset::kNext <= kSmiValueSize - 1);
private:
FieldIndex(bool is_inobject, int local_index, bool is_double,
int inobject_properties, int first_inobject_property_offset,
......
......@@ -1030,6 +1030,7 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
__ Move(LoadDescriptor::SlotRegister(),
SmiFromSlot(prop->PropertyFeedbackSlot()));
CallIC(ic);
if (FLAG_tf_load_ic_stub) RestoreContext();
}
void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
......
......@@ -576,44 +576,50 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
#undef __
// static
Handle<Code> ElementHandlerCompiler::GetKeyedLoadHandler(
Handle<Map> receiver_map, Isolate* isolate) {
if (receiver_map->has_indexed_interceptor() &&
!receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(isolate) &&
!receiver_map->GetIndexedInterceptor()->non_masking()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedInterceptorStub);
return LoadIndexedInterceptorStub(isolate).GetCode();
}
if (receiver_map->IsStringMap()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub);
return LoadIndexedStringStub(isolate).GetCode();
}
InstanceType instance_type = receiver_map->instance_type();
if (instance_type < FIRST_JS_RECEIVER_TYPE) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_SlowStub);
return isolate->builtins()->KeyedLoadIC_Slow();
}
ElementsKind elements_kind = receiver_map->elements_kind();
if (IsSloppyArgumentsElements(elements_kind)) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
return KeyedLoadSloppyArgumentsStub(isolate).GetCode();
}
if (elements_kind == DICTIONARY_ELEMENTS) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadDictionaryElementStub);
return LoadDictionaryElementStub(isolate).GetCode();
}
DCHECK(IsFastElementsKind(elements_kind) ||
IsFixedTypedArrayElementsKind(elements_kind));
bool is_js_array = instance_type == JS_ARRAY_TYPE;
bool convert_hole_to_undefined =
is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
*receiver_map == isolate->get_initial_js_array_map(elements_kind);
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadFastElementStub);
return LoadFastElementStub(isolate, is_js_array, elements_kind,
convert_hole_to_undefined)
.GetCode();
}
void ElementHandlerCompiler::CompileElementHandlers(
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;
if (receiver_map->IsStringMap()) {
cached_stub = LoadIndexedStringStub(isolate()).GetCode();
} else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
cached_stub = isolate()->builtins()->KeyedLoadIC_Slow();
} else {
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
ElementsKind elements_kind = receiver_map->elements_kind();
// No need to check for an elements-free prototype chain here, the
// generated stub code needs to check that dynamically anyway.
bool convert_hole_to_undefined =
(is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
*receiver_map == isolate()->get_initial_js_array_map(elements_kind));
if (receiver_map->has_indexed_interceptor() &&
!receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
isolate()) &&
!receiver_map->GetIndexedInterceptor()->non_masking()) {
cached_stub = LoadIndexedInterceptorStub(isolate()).GetCode();
} else if (IsSloppyArgumentsElements(elements_kind)) {
cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
} else if (IsFastElementsKind(elements_kind) ||
IsFixedTypedArrayElementsKind(elements_kind)) {
cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind,
convert_hole_to_undefined).GetCode();
} else {
DCHECK(elements_kind == DICTIONARY_ELEMENTS);
cached_stub = LoadDictionaryElementStub(isolate()).GetCode();
}
}
handlers->Add(cached_stub);
handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate()));
}
}
} // namespace internal
......
......@@ -279,6 +279,8 @@ class ElementHandlerCompiler : public PropertyHandlerCompiler {
virtual ~ElementHandlerCompiler() {}
static Handle<Code> GetKeyedLoadHandler(Handle<Map> receiver_map,
Isolate* isolate);
void CompileElementHandlers(MapHandleList* receiver_maps,
List<Handle<Object>>* handlers);
......
......@@ -10,42 +10,6 @@
namespace v8 {
namespace internal {
Handle<Code> PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
Handle<Map> receiver_map, ExtraICState extra_ic_state) {
// TODO(ishell): remove extra_ic_state
Isolate* isolate = receiver_map->GetIsolate();
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
ElementsKind elements_kind = receiver_map->elements_kind();
// No need to check for an elements-free prototype chain here, the generated
// stub code needs to check that dynamically anyway.
bool convert_hole_to_undefined =
is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
*receiver_map == isolate->get_initial_js_array_map(elements_kind);
Handle<Code> stub;
if (receiver_map->has_indexed_interceptor()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedInterceptorStub);
stub = LoadIndexedInterceptorStub(isolate).GetCode();
} else if (receiver_map->IsStringMap()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub);
stub = LoadIndexedStringStub(isolate).GetCode();
} else if (receiver_map->has_sloppy_arguments_elements()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode();
} else if (receiver_map->has_fast_elements() ||
receiver_map->has_fixed_typed_array_elements()) {
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadFastElementStub);
stub = LoadFastElementStub(isolate, is_js_array, elements_kind,
convert_hole_to_undefined).GetCode();
} else {
DCHECK(receiver_map->has_dictionary_elements());
TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadDictionaryElementStub);
stub = LoadDictionaryElementStub(isolate).GetCode();
}
return stub;
}
Handle<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
Isolate* isolate = receiver_map->GetIsolate();
......
......@@ -14,9 +14,6 @@ namespace internal {
class PropertyICCompiler : public PropertyAccessCompiler {
public:
// Keyed
static Handle<Code> ComputeKeyedLoadMonomorphicHandler(
Handle<Map> receiver_map, ExtraICState extra_ic_state);
static Handle<Code> ComputeKeyedStoreMonomorphicHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode);
static void ComputeKeyedStorePolymorphicHandlers(
......
......@@ -552,7 +552,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
nexus->ConfigureHandlerMode(Handle<Code>::cast(handler));
} else if (kind() == Code::KEYED_LOAD_IC) {
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
nexus->ConfigureMonomorphic(name, map, Handle<Code>::cast(handler));
nexus->ConfigureMonomorphic(name, map, handler);
} else if (kind() == Code::STORE_IC) {
StoreICNexus* nexus = casted_nexus<StoreICNexus>();
nexus->ConfigureMonomorphic(map, Handle<Code>::cast(handler));
......@@ -781,7 +781,8 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
}
void IC::PatchCache(Handle<Name> name, Handle<Object> code) {
DCHECK(code->IsCode() || (kind() == Code::LOAD_IC && code->IsSmi()));
DCHECK(code->IsCode() || (code->IsSmi() && (kind() == Code::LOAD_IC ||
kind() == Code::KEYED_LOAD_IC)));
switch (state()) {
case UNINITIALIZED:
case PREMONOMORPHIC:
......@@ -828,9 +829,10 @@ Handle<Code> LoadGlobalIC::initialize_stub_in_optimized_code(
return LoadGlobalICStub(isolate, LoadGlobalICState(extra_state)).GetCode();
}
Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(
Isolate* isolate, ExtraICState extra_state) {
// TODO(ishell): remove extra_ic_state
Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(Isolate* isolate) {
if (FLAG_tf_load_ic_stub) {
return KeyedLoadICTFStub(isolate).GetCode();
}
return KeyedLoadICStub(isolate).GetCode();
}
......@@ -850,10 +852,9 @@ Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate,
}
Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) {
if (kind() == Code::LOAD_IC && FLAG_tf_load_ic_stub) {
if (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();
......@@ -1354,8 +1355,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
if (target_receiver_maps.length() == 0) {
Handle<Code> handler =
PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
receiver_map, extra_ic_state());
ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
}
......@@ -1384,8 +1384,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
target_receiver_maps.at(0)->elements_kind(),
Handle<JSObject>::cast(receiver)->GetElementsKind())) {
Handle<Code> handler =
PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(
receiver_map, extra_ic_state());
ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
}
......@@ -1408,7 +1407,6 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
}
List<Handle<Object>> handlers(target_receiver_maps.length());
TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_PolymorphicElement);
ElementHandlerCompiler compiler(isolate());
compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
......
......@@ -355,8 +355,7 @@ class KeyedLoadIC : public LoadIC {
static void GenerateRuntimeGetProperty(MacroAssembler* masm);
static void GenerateMegamorphic(MacroAssembler* masm);
static Handle<Code> initialize_stub_in_optimized_code(
Isolate* isolate, ExtraICState extra_state);
static Handle<Code> initialize_stub_in_optimized_code(Isolate* isolate);
static Handle<Code> ChooseMegamorphicStub(Isolate* isolate,
ExtraICState extra_state);
......
......@@ -688,7 +688,7 @@ void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Code> handler) {
void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
Handle<Map> receiver_map,
Handle<Code> handler) {
Handle<Object> handler) {
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
if (name.is_null()) {
SetFeedback(*cell);
......
......@@ -557,7 +557,7 @@ class KeyedLoadICNexus : public FeedbackNexus {
// name can be a null handle for element loads.
void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
Handle<Code> handler);
Handle<Object> handler);
// name can be null.
void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
List<Handle<Object>>* handlers);
......
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