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, ...@@ -49,6 +49,10 @@ Callable CodeFactory::LoadGlobalICInOptimizedCode(Isolate* isolate,
// static // static
Callable CodeFactory::KeyedLoadIC(Isolate* isolate) { Callable CodeFactory::KeyedLoadIC(Isolate* isolate) {
if (FLAG_tf_load_ic_stub) {
KeyedLoadICTrampolineTFStub stub(isolate);
return Callable(stub.GetCode(), LoadDescriptor(isolate));
}
KeyedLoadICTrampolineStub stub(isolate); KeyedLoadICTrampolineStub stub(isolate);
return Callable(stub.GetCode(), LoadDescriptor(isolate)); return Callable(stub.GetCode(), LoadDescriptor(isolate));
} }
...@@ -56,11 +60,15 @@ Callable CodeFactory::KeyedLoadIC(Isolate* isolate) { ...@@ -56,11 +60,15 @@ Callable CodeFactory::KeyedLoadIC(Isolate* isolate) {
// static // static
Callable CodeFactory::KeyedLoadICInOptimizedCode(Isolate* isolate) { Callable CodeFactory::KeyedLoadICInOptimizedCode(Isolate* isolate) {
auto code = auto code = KeyedLoadIC::initialize_stub_in_optimized_code(isolate);
KeyedLoadIC::initialize_stub_in_optimized_code(isolate, kNoExtraICState);
return Callable(code, LoadWithVectorDescriptor(isolate)); return Callable(code, LoadWithVectorDescriptor(isolate));
} }
// static
Callable CodeFactory::KeyedLoadIC_Megamorphic(Isolate* isolate) {
return Callable(isolate->builtins()->KeyedLoadIC_Megamorphic(),
LoadWithVectorDescriptor(isolate));
}
// static // static
Callable CodeFactory::CallIC(Isolate* isolate, int argc, Callable CodeFactory::CallIC(Isolate* isolate, int argc,
......
...@@ -39,6 +39,7 @@ class CodeFactory final { ...@@ -39,6 +39,7 @@ class CodeFactory final {
TypeofMode typeof_mode); TypeofMode typeof_mode);
static Callable KeyedLoadIC(Isolate* isolate); static Callable KeyedLoadIC(Isolate* isolate);
static Callable KeyedLoadICInOptimizedCode(Isolate* isolate); static Callable KeyedLoadICInOptimizedCode(Isolate* isolate);
static Callable KeyedLoadIC_Megamorphic(Isolate* isolate);
static Callable CallIC(Isolate* isolate, int argc, static Callable CallIC(Isolate* isolate, int argc,
ConvertReceiverMode mode = ConvertReceiverMode::kAny, ConvertReceiverMode mode = ConvertReceiverMode::kAny,
TailCallMode tail_call_mode = TailCallMode::kDisallow); TailCallMode tail_call_mode = TailCallMode::kDisallow);
......
...@@ -2416,7 +2416,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map, ...@@ -2416,7 +2416,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Node* elements = LoadElements(object); Node* elements = LoadElements(object);
Node* length = LoadFixedArrayBaseLength(elements); 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* element = LoadFixedArrayElement(elements, index);
Node* the_hole = TheHoleConstant(); Node* the_hole = TheHoleConstant();
...@@ -2427,7 +2427,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map, ...@@ -2427,7 +2427,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Node* elements = LoadElements(object); Node* elements = LoadElements(object);
Node* length = LoadFixedArrayBaseLength(elements); Node* length = LoadFixedArrayBaseLength(elements);
GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found); GotoUnless(Uint32LessThan(index, SmiToWord32(length)), if_not_found);
if (kPointerSize == kDoubleSize) { if (kPointerSize == kDoubleSize) {
Node* element = Node* element =
...@@ -2456,7 +2456,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map, ...@@ -2456,7 +2456,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Assert(Int32LessThan(LoadInstanceType(string), Assert(Int32LessThan(LoadInstanceType(string),
Int32Constant(FIRST_NONSTRING_TYPE))); Int32Constant(FIRST_NONSTRING_TYPE)));
Node* length = LoadStringLength(string); Node* length = LoadStringLength(string);
GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found); GotoIf(Uint32LessThan(index, SmiToWord32(length)), if_found);
Goto(&if_isobjectorsmi); Goto(&if_isobjectorsmi);
} }
Bind(&if_isslowstringwrapper); Bind(&if_isslowstringwrapper);
...@@ -2466,7 +2466,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map, ...@@ -2466,7 +2466,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map,
Assert(Int32LessThan(LoadInstanceType(string), Assert(Int32LessThan(LoadInstanceType(string),
Int32Constant(FIRST_NONSTRING_TYPE))); Int32Constant(FIRST_NONSTRING_TYPE)));
Node* length = LoadStringLength(string); Node* length = LoadStringLength(string);
GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found); GotoIf(Uint32LessThan(index, SmiToWord32(length)), if_found);
Goto(&if_isdictionary); Goto(&if_isdictionary);
} }
} }
...@@ -2977,6 +2977,71 @@ void CodeStubAssembler::TryProbeStubCache( ...@@ -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) { void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
Variable var_handler(this, MachineRepresentation::kTagged); Variable var_handler(this, MachineRepresentation::kTagged);
// TODO(ishell): defer blocks when it works. // TODO(ishell): defer blocks when it works.
...@@ -2991,66 +3056,7 @@ void CodeStubAssembler::LoadIC(const LoadICParameters* p) { ...@@ -2991,66 +3056,7 @@ void CodeStubAssembler::LoadIC(const LoadICParameters* p) {
&var_handler, &try_polymorphic); &var_handler, &try_polymorphic);
Bind(&if_handler); Bind(&if_handler);
{ {
Comment("LoadIC_if_handler"); HandleLoadICHandlerCase(p, var_handler.value(), &miss);
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));
} }
Bind(&try_polymorphic); Bind(&try_polymorphic);
...@@ -3081,6 +3087,68 @@ void CodeStubAssembler::LoadIC(const LoadICParameters* p) { ...@@ -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) { void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) {
Label try_handler(this), miss(this); Label try_handler(this), miss(this);
Node* weak_cell = Node* weak_cell =
......
...@@ -449,6 +449,9 @@ class CodeStubAssembler : public compiler::CodeAssembler { ...@@ -449,6 +449,9 @@ class CodeStubAssembler : public compiler::CodeAssembler {
Variable* var_handler, Label* if_miss, Variable* var_handler, Label* if_miss,
int unroll_count); int unroll_count);
void HandleLoadICHandlerCase(const LoadICParameters* p,
compiler::Node* handler, Label* miss);
compiler::Node* StubCachePrimaryOffset(compiler::Node* name, compiler::Node* StubCachePrimaryOffset(compiler::Node* name,
compiler::Node* map); compiler::Node* map);
...@@ -471,6 +474,7 @@ class CodeStubAssembler : public compiler::CodeAssembler { ...@@ -471,6 +474,7 @@ class CodeStubAssembler : public compiler::CodeAssembler {
void LoadIC(const LoadICParameters* p); void LoadIC(const LoadICParameters* p);
void LoadGlobalIC(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. // Get the enumerable length from |map| and return the result as a Smi.
compiler::Node* EnumLength(compiler::Node* map); compiler::Node* EnumLength(compiler::Node* map);
......
...@@ -469,6 +469,33 @@ void LoadGlobalICStub::GenerateAssembly(CodeStubAssembler* assembler) const { ...@@ -469,6 +469,33 @@ void LoadGlobalICStub::GenerateAssembly(CodeStubAssembler* assembler) const {
assembler->LoadGlobalIC(&p); 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( void AllocateHeapNumberStub::GenerateAssembly(
CodeStubAssembler* assembler) const { CodeStubAssembler* assembler) const {
typedef compiler::Node Node; typedef compiler::Node Node;
......
...@@ -140,6 +140,8 @@ namespace internal { ...@@ -140,6 +140,8 @@ namespace internal {
V(GetProperty) \ V(GetProperty) \
V(LoadICTrampolineTF) \ V(LoadICTrampolineTF) \
V(LoadICTF) \ V(LoadICTF) \
V(KeyedLoadICTrampolineTF) \
V(KeyedLoadICTF) \
/* IC Handler stubs */ \ /* IC Handler stubs */ \
V(KeyedLoadSloppyArguments) \ V(KeyedLoadSloppyArguments) \
V(KeyedStoreSloppyArguments) \ V(KeyedStoreSloppyArguments) \
...@@ -2350,6 +2352,18 @@ class KeyedLoadICTrampolineStub : public LoadICTrampolineStub { ...@@ -2350,6 +2352,18 @@ class KeyedLoadICTrampolineStub : public LoadICTrampolineStub {
DEFINE_PLATFORM_CODE_STUB(KeyedLoadICTrampoline, 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 { class StoreICTrampolineStub : public PlatformCodeStub {
public: public:
StoreICTrampolineStub(Isolate* isolate, const StoreICState& state) StoreICTrampolineStub(Isolate* isolate, const StoreICState& state)
...@@ -2468,6 +2482,17 @@ class KeyedLoadICStub : public PlatformCodeStub { ...@@ -2468,6 +2482,17 @@ class KeyedLoadICStub : public PlatformCodeStub {
void GenerateImpl(MacroAssembler* masm, bool in_frame); 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 { class StoreICStub : public PlatformCodeStub {
public: public:
StoreICStub(Isolate* isolate, const StoreICState& state) StoreICStub(Isolate* isolate, const StoreICState& state)
......
...@@ -653,6 +653,14 @@ Node* CodeAssembler::TailCallStub(Callable const& callable, Node* context, ...@@ -653,6 +653,14 @@ Node* CodeAssembler::TailCallStub(Callable const& callable, Node* context,
result_size); 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* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
Node* target, Node* context, Node* arg1, Node* target, Node* context, Node* arg1,
size_t result_size) { size_t result_size) {
......
...@@ -383,6 +383,9 @@ class CodeAssembler { ...@@ -383,6 +383,9 @@ class CodeAssembler {
Node* arg2, size_t result_size = 1); Node* arg2, size_t result_size = 1);
Node* TailCallStub(Callable const& callable, Node* context, Node* arg1, Node* TailCallStub(Callable const& callable, Node* context, Node* arg1,
Node* arg2, Node* arg3, size_t result_size = 1); 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* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
Node* context, Node* arg1, size_t result_size = 1); Node* context, Node* arg1, size_t result_size = 1);
Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target, Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
......
...@@ -705,7 +705,7 @@ class RuntimeCallTimer { ...@@ -705,7 +705,7 @@ class RuntimeCallTimer {
V(KeyedLoadIC_KeyedLoadSloppyArgumentsStub) \ V(KeyedLoadIC_KeyedLoadSloppyArgumentsStub) \
V(KeyedLoadIC_LoadFastElementStub) \ V(KeyedLoadIC_LoadFastElementStub) \
V(KeyedLoadIC_LoadDictionaryElementStub) \ V(KeyedLoadIC_LoadDictionaryElementStub) \
V(KeyedLoadIC_PolymorphicElement) \ V(KeyedLoadIC_SlowStub) \
V(KeyedStoreIC_KeyedStoreSloppyArgumentsStub) \ V(KeyedStoreIC_KeyedStoreSloppyArgumentsStub) \
V(KeyedStoreIC_StoreFastElementStub) \ V(KeyedStoreIC_StoreFastElementStub) \
V(KeyedStoreIC_StoreElementStub) \ V(KeyedStoreIC_StoreElementStub) \
......
...@@ -86,18 +86,18 @@ inline int FieldIndex::GetLoadByFieldIndex() const { ...@@ -86,18 +86,18 @@ inline int FieldIndex::GetLoadByFieldIndex() const {
// Takes an offset as computed by GetLoadByFieldOffset and reconstructs a // Takes an offset as computed by GetLoadByFieldOffset and reconstructs a
// FieldIndex object from it. // FieldIndex object from it.
// static
inline FieldIndex FieldIndex::ForLoadByFieldOffset(Map* map, int offset) { inline FieldIndex FieldIndex::ForLoadByFieldOffset(Map* map, int offset) {
bool is_double = offset & 1; DCHECK(offset & 1); // Property marker (as opposed to element).
int field_index = (offset >> 1) / kPointerSize; bool is_inobject = FieldOffsetIsInobject::decode(offset);
int is_inobject = true; bool is_double = FieldOffsetIsDouble::decode(offset);
int field_index = FieldOffsetOffset::decode(offset) >> kPointerSizeLog2;
int first_inobject_offset = 0; int first_inobject_offset = 0;
if (field_index < 0) { if (is_inobject) {
field_index = -field_index;
is_inobject = false;
first_inobject_offset = FixedArray::kHeaderSize;
} else {
first_inobject_offset = first_inobject_offset =
map->IsJSObjectMap() ? map->GetInObjectPropertyOffset(0) : 0; map->IsJSObjectMap() ? map->GetInObjectPropertyOffset(0) : 0;
} else {
first_inobject_offset = FixedArray::kHeaderSize;
} }
int inobject_properties = int inobject_properties =
map->IsJSObjectMap() ? map->GetInObjectProperties() : 0; map->IsJSObjectMap() ? map->GetInObjectProperties() : 0;
...@@ -108,17 +108,13 @@ inline FieldIndex FieldIndex::ForLoadByFieldOffset(Map* map, int offset) { ...@@ -108,17 +108,13 @@ inline FieldIndex FieldIndex::ForLoadByFieldOffset(Map* map, int offset) {
} }
// Returns the offset format consumed by TurboFan stubs: // Returns the offset format consumed by TurboFan stubs:
// In-object: zero-based from object start, // (offset << 3) | (is_double << 2) | (is_inobject << 1) | is_property
// out-of-object: zero-based from FixedArray start. // Where |offset| is relative to object start or FixedArray start, respectively.
inline int FieldIndex::GetLoadByFieldOffset() const { inline int FieldIndex::GetLoadByFieldOffset() const {
// For efficiency, stubs consume an offset that is optimized for quick return FieldOffsetIsInobject::encode(is_inobject()) |
// access. If the property is in-object, the offset is positive. FieldOffsetIsDouble::encode(is_double()) |
// If it's out-of-object, the encoded offset is -raw_offset. FieldOffsetOffset::encode(index() << kPointerSizeLog2) |
// In either case, the offset itself is shifted up by one bit, the lower-most 1; // Property marker (as opposed to element).
// 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) { inline FieldIndex FieldIndex::ForDescriptor(Map* map, int descriptor_index) {
......
...@@ -76,6 +76,13 @@ class FieldIndex final { ...@@ -76,6 +76,13 @@ class FieldIndex final {
(IsInObjectBits::kMask | IsDoubleBits::kMask | IndexBits::kMask); (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: private:
FieldIndex(bool is_inobject, int local_index, bool is_double, FieldIndex(bool is_inobject, int local_index, bool is_double,
int inobject_properties, int first_inobject_property_offset, int inobject_properties, int first_inobject_property_offset,
......
...@@ -1030,6 +1030,7 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { ...@@ -1030,6 +1030,7 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
__ Move(LoadDescriptor::SlotRegister(), __ Move(LoadDescriptor::SlotRegister(),
SmiFromSlot(prop->PropertyFeedbackSlot())); SmiFromSlot(prop->PropertyFeedbackSlot()));
CallIC(ic); CallIC(ic);
if (FLAG_tf_load_ic_stub) RestoreContext();
} }
void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) {
......
...@@ -576,44 +576,50 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback( ...@@ -576,44 +576,50 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
#undef __ #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( void ElementHandlerCompiler::CompileElementHandlers(
MapHandleList* receiver_maps, List<Handle<Object>>* handlers) { MapHandleList* receiver_maps, List<Handle<Object>>* handlers) {
for (int i = 0; i < receiver_maps->length(); ++i) { for (int i = 0; i < receiver_maps->length(); ++i) {
Handle<Map> receiver_map = receiver_maps->at(i); handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate()));
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);
} }
} }
} // namespace internal } // namespace internal
......
...@@ -279,6 +279,8 @@ class ElementHandlerCompiler : public PropertyHandlerCompiler { ...@@ -279,6 +279,8 @@ class ElementHandlerCompiler : public PropertyHandlerCompiler {
virtual ~ElementHandlerCompiler() {} virtual ~ElementHandlerCompiler() {}
static Handle<Code> GetKeyedLoadHandler(Handle<Map> receiver_map,
Isolate* isolate);
void CompileElementHandlers(MapHandleList* receiver_maps, void CompileElementHandlers(MapHandleList* receiver_maps,
List<Handle<Object>>* handlers); List<Handle<Object>>* handlers);
......
...@@ -10,42 +10,6 @@ ...@@ -10,42 +10,6 @@
namespace v8 { namespace v8 {
namespace internal { 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<Code> PropertyICCompiler::ComputeKeyedStoreMonomorphicHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) { Handle<Map> receiver_map, KeyedAccessStoreMode store_mode) {
Isolate* isolate = receiver_map->GetIsolate(); Isolate* isolate = receiver_map->GetIsolate();
......
...@@ -14,9 +14,6 @@ namespace internal { ...@@ -14,9 +14,6 @@ namespace internal {
class PropertyICCompiler : public PropertyAccessCompiler { class PropertyICCompiler : public PropertyAccessCompiler {
public: public:
// Keyed // Keyed
static Handle<Code> ComputeKeyedLoadMonomorphicHandler(
Handle<Map> receiver_map, ExtraICState extra_ic_state);
static Handle<Code> ComputeKeyedStoreMonomorphicHandler( static Handle<Code> ComputeKeyedStoreMonomorphicHandler(
Handle<Map> receiver_map, KeyedAccessStoreMode store_mode); Handle<Map> receiver_map, KeyedAccessStoreMode store_mode);
static void ComputeKeyedStorePolymorphicHandlers( static void ComputeKeyedStorePolymorphicHandlers(
......
...@@ -552,7 +552,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map, ...@@ -552,7 +552,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
nexus->ConfigureHandlerMode(Handle<Code>::cast(handler)); nexus->ConfigureHandlerMode(Handle<Code>::cast(handler));
} else if (kind() == Code::KEYED_LOAD_IC) { } else if (kind() == Code::KEYED_LOAD_IC) {
KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>(); KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
nexus->ConfigureMonomorphic(name, map, Handle<Code>::cast(handler)); nexus->ConfigureMonomorphic(name, map, handler);
} else if (kind() == Code::STORE_IC) { } else if (kind() == Code::STORE_IC) {
StoreICNexus* nexus = casted_nexus<StoreICNexus>(); StoreICNexus* nexus = casted_nexus<StoreICNexus>();
nexus->ConfigureMonomorphic(map, Handle<Code>::cast(handler)); nexus->ConfigureMonomorphic(map, Handle<Code>::cast(handler));
...@@ -781,7 +781,8 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) { ...@@ -781,7 +781,8 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
} }
void IC::PatchCache(Handle<Name> name, Handle<Object> code) { 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()) { switch (state()) {
case UNINITIALIZED: case UNINITIALIZED:
case PREMONOMORPHIC: case PREMONOMORPHIC:
...@@ -828,9 +829,10 @@ Handle<Code> LoadGlobalIC::initialize_stub_in_optimized_code( ...@@ -828,9 +829,10 @@ Handle<Code> LoadGlobalIC::initialize_stub_in_optimized_code(
return LoadGlobalICStub(isolate, LoadGlobalICState(extra_state)).GetCode(); return LoadGlobalICStub(isolate, LoadGlobalICState(extra_state)).GetCode();
} }
Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code( Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(Isolate* isolate) {
Isolate* isolate, ExtraICState extra_state) { if (FLAG_tf_load_ic_stub) {
// TODO(ishell): remove extra_ic_state return KeyedLoadICTFStub(isolate).GetCode();
}
return KeyedLoadICStub(isolate).GetCode(); return KeyedLoadICStub(isolate).GetCode();
} }
...@@ -850,10 +852,9 @@ Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate, ...@@ -850,10 +852,9 @@ Handle<Code> KeyedStoreIC::ChooseMegamorphicStub(Isolate* isolate,
} }
Handle<Object> LoadIC::SimpleFieldLoad(FieldIndex index) { 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()); return handle(Smi::FromInt(index.GetLoadByFieldOffset()), isolate());
} }
DCHECK(kind() == Code::KEYED_LOAD_IC || !FLAG_tf_load_ic_stub);
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub);
LoadFieldStub stub(isolate(), index); LoadFieldStub stub(isolate(), index);
return stub.GetCode(); return stub.GetCode();
...@@ -1354,8 +1355,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) { ...@@ -1354,8 +1355,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
if (target_receiver_maps.length() == 0) { if (target_receiver_maps.length() == 0) {
Handle<Code> handler = Handle<Code> handler =
PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
receiver_map, extra_ic_state());
return ConfigureVectorState(Handle<Name>(), receiver_map, handler); return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
} }
...@@ -1384,8 +1384,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) { ...@@ -1384,8 +1384,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
target_receiver_maps.at(0)->elements_kind(), target_receiver_maps.at(0)->elements_kind(),
Handle<JSObject>::cast(receiver)->GetElementsKind())) { Handle<JSObject>::cast(receiver)->GetElementsKind())) {
Handle<Code> handler = Handle<Code> handler =
PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
receiver_map, extra_ic_state());
return ConfigureVectorState(Handle<Name>(), receiver_map, handler); return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
} }
...@@ -1408,7 +1407,6 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) { ...@@ -1408,7 +1407,6 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
} }
List<Handle<Object>> handlers(target_receiver_maps.length()); List<Handle<Object>> handlers(target_receiver_maps.length());
TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_PolymorphicElement);
ElementHandlerCompiler compiler(isolate()); ElementHandlerCompiler compiler(isolate());
compiler.CompileElementHandlers(&target_receiver_maps, &handlers); compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers); ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
......
...@@ -355,8 +355,7 @@ class KeyedLoadIC : public LoadIC { ...@@ -355,8 +355,7 @@ class KeyedLoadIC : public LoadIC {
static void GenerateRuntimeGetProperty(MacroAssembler* masm); static void GenerateRuntimeGetProperty(MacroAssembler* masm);
static void GenerateMegamorphic(MacroAssembler* masm); static void GenerateMegamorphic(MacroAssembler* masm);
static Handle<Code> initialize_stub_in_optimized_code( static Handle<Code> initialize_stub_in_optimized_code(Isolate* isolate);
Isolate* isolate, ExtraICState extra_state);
static Handle<Code> ChooseMegamorphicStub(Isolate* isolate, static Handle<Code> ChooseMegamorphicStub(Isolate* isolate,
ExtraICState extra_state); ExtraICState extra_state);
......
...@@ -688,7 +688,7 @@ void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Code> handler) { ...@@ -688,7 +688,7 @@ void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Code> handler) {
void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name, void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
Handle<Map> receiver_map, Handle<Map> receiver_map,
Handle<Code> handler) { Handle<Object> handler) {
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
if (name.is_null()) { if (name.is_null()) {
SetFeedback(*cell); SetFeedback(*cell);
......
...@@ -557,7 +557,7 @@ class KeyedLoadICNexus : public FeedbackNexus { ...@@ -557,7 +557,7 @@ class KeyedLoadICNexus : public FeedbackNexus {
// name can be a null handle for element loads. // name can be a null handle for element loads.
void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map, void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
Handle<Code> handler); Handle<Object> handler);
// name can be null. // name can be null.
void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps, void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
List<Handle<Object>>* handlers); 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