Commit 34a1a76d authored by mvstanton's avatar mvstanton Committed by Commit bot

Use platform specific stubs for vector-based Load/KeyedLoad.

A hydrogen code stub is not the best approach because it builds a frame
and doesn't have the technology to discard roots at tail call exits.
Platform-specific stubs provide much better performance at this point.

R=verwaest@chromium.org

BUG=

Review URL: https://codereview.chromium.org/988653003

Cr-Commit-Position: refs/heads/master@{#27235}
parent d74f5c6f
This diff is collapsed.
This diff is collapsed.
......@@ -100,21 +100,6 @@ class CodeStubGraphBuilderBase : public HGraphBuilder {
HValue* shared_info,
HValue* native_context);
// Tail calls handler found at array[map_index + 1].
void TailCallHandler(HValue* receiver, HValue* name, HValue* array,
HValue* map_index, HValue* slot, HValue* vector);
// Tail calls handler_code.
void TailCallHandler(HValue* receiver, HValue* name, HValue* slot,
HValue* vector, HValue* handler_code);
void TailCallMiss(HValue* receiver, HValue* name, HValue* slot,
HValue* vector, bool keyed_load);
// Handle MONOMORPHIC and POLYMORPHIC LoadIC and KeyedLoadIC cases.
void HandleArrayCases(HValue* array, HValue* receiver, HValue* name,
HValue* slot, HValue* vector, bool keyed_load);
private:
HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder);
HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder,
......@@ -2029,211 +2014,6 @@ Handle<Code> KeyedLoadGenericStub::GenerateCode() {
}
void CodeStubGraphBuilderBase::TailCallHandler(HValue* receiver, HValue* name,
HValue* array, HValue* map_index,
HValue* slot, HValue* vector) {
// The handler is at array[map_index + 1]. Compute this with a custom offset
// to HLoadKeyed.
int offset =
GetDefaultHeaderSizeForElementsKind(FAST_ELEMENTS) + kPointerSize;
HValue* handler_code = Add<HLoadKeyed>(
array, map_index, nullptr, FAST_ELEMENTS, NEVER_RETURN_HOLE, offset);
TailCallHandler(receiver, name, slot, vector, handler_code);
}
void CodeStubGraphBuilderBase::TailCallHandler(HValue* receiver, HValue* name,
HValue* slot, HValue* vector,
HValue* handler_code) {
VectorLoadICDescriptor descriptor(isolate());
HValue* op_vals[] = {context(), receiver, name, slot, vector};
Add<HCallWithDescriptor>(handler_code, 0, descriptor,
Vector<HValue*>(op_vals, 5), TAIL_CALL);
// We never return here, it is a tail call.
}
void CodeStubGraphBuilderBase::TailCallMiss(HValue* receiver, HValue* name,
HValue* slot, HValue* vector,
bool keyed_load) {
DCHECK(FLAG_vector_ics);
Add<HTailCallThroughMegamorphicCache>(
receiver, name, slot, vector,
HTailCallThroughMegamorphicCache::ComputeFlags(keyed_load, true));
// We never return here, it is a tail call.
}
void CodeStubGraphBuilderBase::HandleArrayCases(HValue* array, HValue* receiver,
HValue* name, HValue* slot,
HValue* vector,
bool keyed_load) {
HConstant* constant_two = Add<HConstant>(2);
HConstant* constant_three = Add<HConstant>(3);
IfBuilder if_receiver_heap_object(this);
if_receiver_heap_object.IfNot<HIsSmiAndBranch>(receiver);
if_receiver_heap_object.Then();
Push(AddLoadMap(receiver, nullptr));
if_receiver_heap_object.Else();
HConstant* heap_number_map =
Add<HConstant>(isolate()->factory()->heap_number_map());
Push(heap_number_map);
if_receiver_heap_object.End();
HValue* receiver_map = Pop();
HValue* start =
keyed_load ? graph()->GetConstant1() : graph()->GetConstant0();
HValue* weak_cell =
Add<HLoadKeyed>(array, start, nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
// Load the weak cell value. It may be Smi(0), or a map. Compare nonetheless
// against the receiver_map.
HValue* array_map = Add<HLoadNamedField>(weak_cell, nullptr,
HObjectAccess::ForWeakCellValue());
IfBuilder if_correct_map(this);
if_correct_map.If<HCompareObjectEqAndBranch>(receiver_map, array_map);
if_correct_map.Then();
{ TailCallHandler(receiver, name, array, start, slot, vector); }
if_correct_map.Else();
{
// If our array has more elements, the ic is polymorphic. Look for the
// receiver map in the rest of the array.
HValue* length = AddLoadFixedArrayLength(array, nullptr);
LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement,
constant_two);
start = keyed_load ? constant_three : constant_two;
HValue* key = builder.BeginBody(start, length, Token::LT);
{
HValue* weak_cell = Add<HLoadKeyed>(array, key, nullptr, FAST_ELEMENTS,
ALLOW_RETURN_HOLE);
HValue* array_map = Add<HLoadNamedField>(
weak_cell, nullptr, HObjectAccess::ForWeakCellValue());
IfBuilder if_correct_poly_map(this);
if_correct_poly_map.If<HCompareObjectEqAndBranch>(receiver_map,
array_map);
if_correct_poly_map.Then();
{ TailCallHandler(receiver, name, array, key, slot, vector); }
}
builder.EndBody();
}
if_correct_map.End();
}
template <>
HValue* CodeStubGraphBuilder<VectorLoadStub>::BuildCodeStub() {
HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex);
HValue* name = GetParameter(VectorLoadICDescriptor::kNameIndex);
HValue* slot = GetParameter(VectorLoadICDescriptor::kSlotIndex);
HValue* vector = GetParameter(VectorLoadICDescriptor::kVectorIndex);
// If the feedback is an array, then the IC is in the monomorphic or
// polymorphic state.
HValue* feedback =
Add<HLoadKeyed>(vector, slot, nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
IfBuilder array_checker(this);
array_checker.If<HCompareMap>(feedback,
isolate()->factory()->fixed_array_map());
array_checker.Then();
{ HandleArrayCases(feedback, receiver, name, slot, vector, false); }
array_checker.Else();
{
// Is the IC megamorphic?
IfBuilder mega_checker(this);
HConstant* megamorphic_symbol =
Add<HConstant>(isolate()->factory()->megamorphic_symbol());
mega_checker.If<HCompareObjectEqAndBranch>(feedback, megamorphic_symbol);
mega_checker.Then();
{
// Probe the stub cache.
Add<HTailCallThroughMegamorphicCache>(
receiver, name, slot, vector,
HTailCallThroughMegamorphicCache::ComputeFlags(false, false));
}
mega_checker.End();
}
array_checker.End();
TailCallMiss(receiver, name, slot, vector, false);
return graph()->GetConstant0();
}
Handle<Code> VectorLoadStub::GenerateCode() { return DoGenerateCode(this); }
template <>
HValue* CodeStubGraphBuilder<VectorKeyedLoadStub>::BuildCodeStub() {
HValue* receiver = GetParameter(VectorLoadICDescriptor::kReceiverIndex);
HValue* name = GetParameter(VectorLoadICDescriptor::kNameIndex);
HValue* slot = GetParameter(VectorLoadICDescriptor::kSlotIndex);
HValue* vector = GetParameter(VectorLoadICDescriptor::kVectorIndex);
HConstant* zero = graph()->GetConstant0();
// If the feedback is an array, then the IC is in the monomorphic or
// polymorphic state.
HValue* feedback =
Add<HLoadKeyed>(vector, slot, nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE);
IfBuilder array_checker(this);
array_checker.If<HCompareMap>(feedback,
isolate()->factory()->fixed_array_map());
array_checker.Then();
{
// If feedback[0] is 0, then the IC has element handlers and name should be
// a smi. If feedback[0] is a string, verify that it matches name.
HValue* recorded_name = Add<HLoadKeyed>(feedback, zero, nullptr,
FAST_ELEMENTS, ALLOW_RETURN_HOLE);
IfBuilder recorded_name_is_zero(this);
recorded_name_is_zero.If<HCompareObjectEqAndBranch>(recorded_name, zero);
recorded_name_is_zero.Then();
{ Add<HCheckSmi>(name); }
recorded_name_is_zero.Else();
{
IfBuilder strings_match(this);
strings_match.IfNot<HCompareObjectEqAndBranch>(name, recorded_name);
strings_match.Then();
TailCallMiss(receiver, name, slot, vector, true);
strings_match.End();
}
recorded_name_is_zero.End();
HandleArrayCases(feedback, receiver, name, slot, vector, true);
}
array_checker.Else();
{
// Check if the IC is in megamorphic state.
IfBuilder megamorphic_checker(this);
HConstant* megamorphic_symbol =
Add<HConstant>(isolate()->factory()->megamorphic_symbol());
megamorphic_checker.If<HCompareObjectEqAndBranch>(feedback,
megamorphic_symbol);
megamorphic_checker.Then();
{
// Tail-call to the megamorphic KeyedLoadIC, treating it like a handler.
Handle<Code> stub = KeyedLoadIC::ChooseMegamorphicStub(isolate());
HValue* constant_stub = Add<HConstant>(stub);
LoadDescriptor descriptor(isolate());
HValue* op_vals[] = {context(), receiver, name};
Add<HCallWithDescriptor>(constant_stub, 0, descriptor,
Vector<HValue*>(op_vals, 3), TAIL_CALL);
// We never return here, it is a tail call.
}
megamorphic_checker.End();
}
array_checker.End();
TailCallMiss(receiver, name, slot, vector, true);
return zero;
}
Handle<Code> VectorKeyedLoadStub::GenerateCode() {
return DoGenerateCode(this);
}
Handle<Code> MegamorphicLoadStub::GenerateCode() {
return DoGenerateCode(this);
}
......
......@@ -620,26 +620,6 @@ CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor() {
}
static void InitializeVectorLoadStub(Isolate* isolate,
CodeStubDescriptor* descriptor,
Address deoptimization_handler) {
DCHECK(FLAG_vector_ics);
descriptor->Initialize(deoptimization_handler);
}
void VectorLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
InitializeVectorLoadStub(isolate(), descriptor,
FUNCTION_ADDR(LoadIC_MissFromStubFailure));
}
void VectorKeyedLoadStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
InitializeVectorLoadStub(isolate(), descriptor,
FUNCTION_ADDR(KeyedLoadIC_MissFromStubFailure));
}
void MegamorphicLoadStub::InitializeDescriptor(CodeStubDescriptor* d) {}
......
......@@ -85,8 +85,8 @@ namespace internal {
V(StringAdd) \
V(ToBoolean) \
V(TransitionElementsKind) \
V(VectorKeyedLoad) \
V(VectorLoad) \
V(VectorRawKeyedLoad) \
V(VectorRawLoad) \
/* IC Handler stubs */ \
V(LoadConstant) \
V(LoadField) \
......@@ -2062,38 +2062,49 @@ class MegamorphicLoadStub : public HydrogenCodeStub {
};
class VectorLoadStub : public HydrogenCodeStub {
class VectorRawLoadStub : public PlatformCodeStub {
public:
explicit VectorLoadStub(Isolate* isolate, const LoadICState& state)
: HydrogenCodeStub(isolate) {
set_sub_minor_key(state.GetExtraICState());
explicit VectorRawLoadStub(Isolate* isolate, const LoadICState& state)
: PlatformCodeStub(isolate) {
minor_key_ = state.GetExtraICState();
}
Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
void GenerateForTrampoline(MacroAssembler* masm);
InlineCacheState GetICState() const FINAL { return DEFAULT; }
virtual Code::Kind GetCodeKind() const OVERRIDE { return Code::LOAD_IC; }
ExtraICState GetExtraICState() const FINAL {
return static_cast<ExtraICState>(sub_minor_key());
}
virtual InlineCacheState GetICState() const FINAL OVERRIDE { return DEFAULT; }
private:
LoadICState state() const { return LoadICState(GetExtraICState()); }
virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
return static_cast<ExtraICState>(minor_key_);
}
DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorLoadIC);
DEFINE_HYDROGEN_CODE_STUB(VectorLoad, HydrogenCodeStub);
DEFINE_PLATFORM_CODE_STUB(VectorRawLoad, PlatformCodeStub);
protected:
void GenerateImpl(MacroAssembler* masm, bool in_frame);
};
class VectorKeyedLoadStub : public VectorLoadStub {
class VectorRawKeyedLoadStub : public PlatformCodeStub {
public:
explicit VectorKeyedLoadStub(Isolate* isolate)
: VectorLoadStub(isolate, LoadICState(0)) {}
explicit VectorRawKeyedLoadStub(Isolate* isolate)
: PlatformCodeStub(isolate) {}
Code::Kind GetCodeKind() const OVERRIDE { return Code::KEYED_LOAD_IC; }
void GenerateForTrampoline(MacroAssembler* masm);
virtual Code::Kind GetCodeKind() const OVERRIDE {
return Code::KEYED_LOAD_IC;
}
virtual InlineCacheState GetICState() const FINAL OVERRIDE { return DEFAULT; }
DEFINE_CALL_INTERFACE_DESCRIPTOR(VectorLoadIC);
DEFINE_HYDROGEN_CODE_STUB(VectorKeyedLoad, VectorLoadStub);
DEFINE_PLATFORM_CODE_STUB(VectorRawKeyedLoad, PlatformCodeStub);
protected:
void GenerateImpl(MacroAssembler* masm, bool in_frame);
};
......
......@@ -12,6 +12,7 @@
#include "src/codegen.h"
#include "src/ic/handler-compiler.h"
#include "src/ic/ic.h"
#include "src/ic/stub-cache.h"
#include "src/isolate.h"
#include "src/jsregexp.h"
#include "src/regexp-macro-assembler.h"
......@@ -4399,15 +4400,236 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
VectorLoadStub stub(isolate(), state());
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
VectorRawLoadStub stub(isolate(), state());
stub.GenerateForTrampoline(masm);
}
void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
VectorKeyedLoadStub stub(isolate());
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
VectorRawKeyedLoadStub stub(isolate());
stub.GenerateForTrampoline(masm);
}
static void HandleArrayCases(MacroAssembler* masm, Register receiver,
Register key, Register vector, Register slot,
Register feedback, bool is_polymorphic,
Label* miss) {
// feedback initially contains the feedback array
Label next, next_loop, prepare_next;
Label load_smi_map, compare_map;
Label start_polymorphic;
__ push(receiver);
__ push(vector);
Register receiver_map = receiver;
Register cached_map = vector;
// Receiver might not be a heap object.
__ JumpIfSmi(receiver, &load_smi_map);
__ mov(receiver_map, FieldOperand(receiver, 0));
__ bind(&compare_map);
__ mov(cached_map, FieldOperand(feedback, FixedArray::OffsetOfElementAt(0)));
// A named keyed load might have a 2 element array, all other cases can count
// on an array with at least 2 {map, handler} pairs, so they can go right
// into polymorphic array handling.
__ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
__ j(not_equal, is_polymorphic ? &start_polymorphic : &next);
// found, now call handler.
Register handler = feedback;
__ mov(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
__ pop(vector);
__ pop(receiver);
__ lea(handler, FieldOperand(handler, Code::kHeaderSize));
__ jmp(handler);
if (!is_polymorphic) {
__ bind(&next);
__ cmp(FieldOperand(feedback, FixedArray::kLengthOffset),
Immediate(Smi::FromInt(2)));
__ j(not_equal, &start_polymorphic);
__ pop(vector);
__ pop(receiver);
__ jmp(miss);
}
// Polymorphic, we have to loop from 2 to N
__ bind(&start_polymorphic);
__ push(key);
Register counter = key;
__ mov(counter, Immediate(Smi::FromInt(2)));
__ bind(&next_loop);
__ mov(cached_map, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize));
__ cmp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
__ j(not_equal, &prepare_next);
__ mov(handler, FieldOperand(feedback, counter, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ lea(handler, FieldOperand(handler, Code::kHeaderSize));
__ jmp(handler);
__ bind(&prepare_next);
__ add(counter, Immediate(Smi::FromInt(2)));
__ cmp(counter, FieldOperand(feedback, FixedArray::kLengthOffset));
__ j(less, &next_loop);
// We exhausted our array of map handler pairs.
__ pop(key);
__ pop(vector);
__ pop(receiver);
__ jmp(miss);
__ bind(&load_smi_map);
__ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
__ jmp(&compare_map);
}
static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
Register key, Register vector, Register slot,
Register weak_cell, Label* miss) {
// feedback initially contains the feedback array
Label compare_smi_map;
// Move the weak map into the weak_cell register.
Register ic_map = weak_cell;
__ mov(ic_map, FieldOperand(weak_cell, WeakCell::kValueOffset));
// Receiver might not be a heap object.
__ JumpIfSmi(receiver, &compare_smi_map);
__ cmp(ic_map, FieldOperand(receiver, 0));
__ j(not_equal, miss);
Register handler = weak_cell;
__ mov(handler, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ lea(handler, FieldOperand(handler, Code::kHeaderSize));
__ jmp(handler);
// In microbenchmarks, it made sense to unroll this code so that the call to
// the handler is duplicated for a HeapObject receiver and a Smi receiver.
__ bind(&compare_smi_map);
__ CompareRoot(ic_map, Heap::kHeapNumberMapRootIndex);
__ j(not_equal, miss);
__ mov(handler, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ lea(handler, FieldOperand(handler, Code::kHeaderSize));
__ jmp(handler);
}
void VectorRawLoadStub::Generate(MacroAssembler* masm) {
GenerateImpl(masm, false);
}
void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
GenerateImpl(masm, true);
}
void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
Register receiver = VectorLoadICDescriptor::ReceiverRegister(); // edx
Register name = VectorLoadICDescriptor::NameRegister(); // ecx
Register vector = VectorLoadICDescriptor::VectorRegister(); // ebx
Register slot = VectorLoadICDescriptor::SlotRegister(); // eax
Register scratch = edi;
__ mov(scratch, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize));
// Is it a weak cell?
Label try_array;
Label not_array, smi_key, key_okay, miss;
__ CompareRoot(FieldOperand(scratch, 0), Heap::kWeakCellMapRootIndex);
__ j(not_equal, &try_array);
HandleMonomorphicCase(masm, receiver, name, vector, slot, scratch, &miss);
// Is it a fixed array?
__ bind(&try_array);
__ CompareRoot(FieldOperand(scratch, 0), Heap::kFixedArrayMapRootIndex);
__ j(not_equal, &not_array);
HandleArrayCases(masm, receiver, name, vector, slot, scratch, true, &miss);
__ bind(&not_array);
__ CompareRoot(scratch, Heap::kmegamorphic_symbolRootIndex);
__ j(not_equal, &miss);
__ push(slot);
__ push(vector);
Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, Code::LOAD_IC, code_flags, false, receiver, name, vector, scratch);
__ pop(vector);
__ pop(slot);
__ bind(&miss);
LoadIC::GenerateMiss(masm);
}
void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
GenerateImpl(masm, false);
}
void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
GenerateImpl(masm, true);
}
void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
Register receiver = VectorLoadICDescriptor::ReceiverRegister(); // edx
Register key = VectorLoadICDescriptor::NameRegister(); // ecx
Register vector = VectorLoadICDescriptor::VectorRegister(); // ebx
Register slot = VectorLoadICDescriptor::SlotRegister(); // eax
Register feedback = edi;
__ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize));
// Is it a weak cell?
Label try_array;
Label not_array, smi_key, key_okay, miss;
__ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
__ j(not_equal, &try_array);
__ JumpIfNotSmi(key, &miss);
HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, &miss);
__ bind(&try_array);
// Is it a fixed array?
__ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
__ j(not_equal, &not_array);
// We have a polymorphic element handler.
__ JumpIfNotSmi(key, &miss);
Label polymorphic, try_poly_name;
__ bind(&polymorphic);
HandleArrayCases(masm, receiver, key, vector, slot, feedback, true, &miss);
__ bind(&not_array);
// Is it generic?
__ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
__ j(not_equal, &try_poly_name);
Handle<Code> megamorphic_stub =
KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
__ jmp(megamorphic_stub, RelocInfo::CODE_TARGET);
__ bind(&try_poly_name);
// We might have a name in feedback, and a fixed array in the next slot.
__ cmp(key, feedback);
__ j(not_equal, &miss);
// If the name comparison succeeded, we know we have a fixed array with
// at least one map/handler pair.
__ mov(feedback, FieldOperand(vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
HandleArrayCases(masm, receiver, key, vector, slot, feedback, false, &miss);
__ bind(&miss);
KeyedLoadIC::GenerateMiss(masm);
}
......
......@@ -988,7 +988,7 @@ Handle<Code> LoadIC::load_global(Isolate* isolate, Handle<GlobalObject> global,
Handle<Code> LoadIC::initialize_stub_in_optimized_code(
Isolate* isolate, ExtraICState extra_state, State initialization_state) {
if (FLAG_vector_ics) {
return VectorLoadStub(isolate, LoadICState(extra_state)).GetCode();
return VectorRawLoadStub(isolate, LoadICState(extra_state)).GetCode();
}
return PropertyICCompiler::ComputeLoad(isolate, initialization_state,
extra_state);
......@@ -1007,7 +1007,7 @@ Handle<Code> KeyedLoadIC::initialize_stub(Isolate* isolate) {
Handle<Code> KeyedLoadIC::initialize_stub_in_optimized_code(
Isolate* isolate, State initialization_state) {
if (FLAG_vector_ics) {
return VectorKeyedLoadStub(isolate).GetCode();
return VectorRawKeyedLoadStub(isolate).GetCode();
}
switch (initialization_state) {
case UNINITIALIZED:
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -74,6 +74,8 @@ class TypeFeedbackVector : public FixedArray {
static const int kWithTypesIndex = 1;
static const int kGenericCountIndex = 2;
static int elements_per_ic_slot() { return FLAG_vector_ics ? 2 : 1; }
int first_ic_slot_index() const {
DCHECK(length() >= kReservedIndexCount);
return Smi::cast(get(kFirstICSlotIndex))->value();
......@@ -114,7 +116,7 @@ class TypeFeedbackVector : public FixedArray {
int ICSlots() const {
if (length() == 0) return 0;
return length() - first_ic_slot_index();
return (length() - first_ic_slot_index()) / elements_per_ic_slot();
}
// Conversion from a slot or ic slot to an integer index to the underlying
......@@ -127,7 +129,7 @@ class TypeFeedbackVector : public FixedArray {
int GetIndex(FeedbackVectorICSlot slot) const {
int first_ic_slot = first_ic_slot_index();
DCHECK(slot.ToInt() < ICSlots());
return first_ic_slot + slot.ToInt();
return first_ic_slot + slot.ToInt() * elements_per_ic_slot();
}
// Conversion from an integer index to either a slot or an ic slot. The caller
......@@ -140,7 +142,8 @@ class TypeFeedbackVector : public FixedArray {
FeedbackVectorICSlot ToICSlot(int index) const {
DCHECK(index >= first_ic_slot_index() && index < length());
return FeedbackVectorICSlot(index - first_ic_slot_index());
int ic_slot = (index - first_ic_slot_index()) / elements_per_ic_slot();
return FeedbackVectorICSlot(ic_slot);
}
Object* Get(FeedbackVectorSlot slot) const { return get(GetIndex(slot)); }
......@@ -244,14 +247,17 @@ class FeedbackNexus {
void FindAllMaps(MapHandleList* maps) const { ExtractMaps(maps); }
virtual InlineCacheState StateFromFeedback() const = 0;
virtual int ExtractMaps(MapHandleList* maps) const = 0;
virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const = 0;
virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const {
return length == 0;
}
virtual int ExtractMaps(MapHandleList* maps) const;
virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const;
virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const;
virtual Name* FindFirstName() const { return NULL; }
Object* GetFeedback() const { return vector()->Get(slot()); }
Object* GetFeedbackExtra() const {
DCHECK(TypeFeedbackVector::elements_per_ic_slot() > 1);
int extra_index = vector()->GetIndex(slot()) + 1;
return vector()->get(extra_index);
}
protected:
Isolate* GetIsolate() const { return vector()->GetIsolate(); }
......@@ -261,13 +267,17 @@ class FeedbackNexus {
vector()->Set(slot(), feedback, mode);
}
void SetFeedbackExtra(Object* feedback_extra,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
DCHECK(TypeFeedbackVector::elements_per_ic_slot() > 1);
int index = vector()->GetIndex(slot()) + 1;
vector()->set(index, feedback_extra, mode);
}
Handle<FixedArray> EnsureArrayOfSize(int length);
void InstallHandlers(int start_index, MapHandleList* maps,
Handle<FixedArray> EnsureExtraArrayOfSize(int length);
void InstallHandlers(Handle<FixedArray> array, MapHandleList* maps,
CodeHandleList* handlers);
int ExtractMaps(int start_index, MapHandleList* maps) const;
MaybeHandle<Code> FindHandlerForMap(int start_index, Handle<Map> map) const;
bool FindHandlers(int start_index, CodeHandleList* code_list,
int length) const;
private:
// The reason for having a vector handle and a raw pointer is that we can and
......@@ -334,10 +344,6 @@ class LoadICNexus : public FeedbackNexus {
void ConfigurePolymorphic(MapHandleList* maps, CodeHandleList* handlers);
InlineCacheState StateFromFeedback() const OVERRIDE;
int ExtractMaps(MapHandleList* maps) const OVERRIDE;
MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE;
virtual bool FindHandlers(CodeHandleList* code_list,
int length = -1) const OVERRIDE;
};
......@@ -364,10 +370,6 @@ class KeyedLoadICNexus : public FeedbackNexus {
CodeHandleList* handlers);
InlineCacheState StateFromFeedback() const OVERRIDE;
int ExtractMaps(MapHandleList* maps) const OVERRIDE;
MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE;
virtual bool FindHandlers(CodeHandleList* code_list,
int length = -1) const OVERRIDE;
Name* FindFirstName() const OVERRIDE;
};
}
......
......@@ -11,6 +11,7 @@
#include "src/codegen.h"
#include "src/ic/handler-compiler.h"
#include "src/ic/ic.h"
#include "src/ic/stub-cache.h"
#include "src/isolate.h"
#include "src/jsregexp.h"
#include "src/regexp-macro-assembler.h"
......@@ -4337,15 +4338,230 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
VectorLoadStub stub(isolate(), state());
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
VectorRawLoadStub stub(isolate(), state());
stub.GenerateForTrampoline(masm);
}
void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
VectorKeyedLoadStub stub(isolate());
__ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
VectorRawKeyedLoadStub stub(isolate());
stub.GenerateForTrampoline(masm);
}
static void HandleArrayCases(MacroAssembler* masm, Register receiver,
Register key, Register vector, Register slot,
Register feedback, Register scratch1,
Register scratch2, Register scratch3,
Register scratch4, bool is_polymorphic,
Label* miss) {
// feedback initially contains the feedback array
Label next_loop, prepare_next;
Label load_smi_map, compare_map;
Label start_polymorphic;
Register receiver_map = scratch1;
Register counter = scratch2;
Register length = scratch3;
Register cached_map = scratch4;
// Receiver might not be a heap object.
__ JumpIfSmi(receiver, &load_smi_map);
__ movp(receiver_map, FieldOperand(receiver, 0));
__ bind(&compare_map);
__ movp(cached_map, FieldOperand(feedback, FixedArray::OffsetOfElementAt(0)));
__ cmpp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
__ j(not_equal, &start_polymorphic);
// found, now call handler.
Register handler = feedback;
__ movp(handler, FieldOperand(feedback, FixedArray::OffsetOfElementAt(1)));
__ leap(handler, FieldOperand(handler, Code::kHeaderSize));
__ jmp(handler);
// Polymorphic, we have to loop from 2 to N
__ bind(&start_polymorphic);
__ SmiToInteger32(length, FieldOperand(feedback, FixedArray::kLengthOffset));
if (!is_polymorphic) {
// If the IC could be monomorphic we have to make sure we don't go past the
// end of the feedback array.
__ cmpl(length, Immediate(2));
__ j(equal, miss);
}
__ movl(counter, Immediate(2));
__ bind(&next_loop);
__ movp(cached_map, FieldOperand(feedback, counter, times_pointer_size,
FixedArray::kHeaderSize));
__ cmpp(receiver_map, FieldOperand(cached_map, WeakCell::kValueOffset));
__ j(not_equal, &prepare_next);
__ movp(handler, FieldOperand(feedback, counter, times_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ leap(handler, FieldOperand(handler, Code::kHeaderSize));
__ jmp(handler);
__ bind(&prepare_next);
__ addl(counter, Immediate(2));
__ cmpl(counter, length);
__ j(less, &next_loop);
// We exhausted our array of map handler pairs.
__ jmp(miss);
__ bind(&load_smi_map);
__ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
__ jmp(&compare_map);
}
static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
Register key, Register vector, Register slot,
Register weak_cell, Register integer_slot,
Label* miss) {
// feedback initially contains the feedback array
Label compare_smi_map;
// Move the weak map into the weak_cell register.
Register ic_map = weak_cell;
__ movp(ic_map, FieldOperand(weak_cell, WeakCell::kValueOffset));
// Receiver might not be a heap object.
__ JumpIfSmi(receiver, &compare_smi_map);
__ cmpp(ic_map, FieldOperand(receiver, 0));
__ j(not_equal, miss);
Register handler = weak_cell;
__ movp(handler, FieldOperand(vector, integer_slot, times_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ leap(handler, FieldOperand(handler, Code::kHeaderSize));
__ jmp(handler);
// In microbenchmarks, it made sense to unroll this code so that the call to
// the handler is duplicated for a HeapObject receiver and a Smi receiver.
__ bind(&compare_smi_map);
__ CompareRoot(ic_map, Heap::kHeapNumberMapRootIndex);
__ j(not_equal, miss);
__ movp(handler, FieldOperand(vector, integer_slot, times_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
__ leap(handler, FieldOperand(handler, Code::kHeaderSize));
__ jmp(handler);
}
void VectorRawLoadStub::Generate(MacroAssembler* masm) {
GenerateImpl(masm, false);
}
void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
GenerateImpl(masm, true);
}
void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
Register receiver = VectorLoadICDescriptor::ReceiverRegister(); // rdx
Register name = VectorLoadICDescriptor::NameRegister(); // rcx
Register vector = VectorLoadICDescriptor::VectorRegister(); // rbx
Register slot = VectorLoadICDescriptor::SlotRegister(); // rax
Register feedback = rdi;
Register integer_slot = r8;
__ SmiToInteger32(integer_slot, slot);
__ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
FixedArray::kHeaderSize));
// Is it a weak cell?
Label try_array;
Label not_array, smi_key, key_okay, miss;
__ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
__ j(not_equal, &try_array);
HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback,
integer_slot, &miss);
// Is it a fixed array?
__ bind(&try_array);
__ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
__ j(not_equal, &not_array);
HandleArrayCases(masm, receiver, name, vector, slot, feedback, integer_slot,
r9, r11, r15, true, &miss);
__ bind(&not_array);
__ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
__ j(not_equal, &miss);
Code::Flags code_flags = Code::RemoveTypeAndHolderFromFlags(
Code::ComputeHandlerFlags(Code::LOAD_IC));
masm->isolate()->stub_cache()->GenerateProbe(
masm, Code::LOAD_IC, code_flags, false, receiver, name, feedback, no_reg);
__ bind(&miss);
LoadIC::GenerateMiss(masm);
}
void VectorRawKeyedLoadStub::Generate(MacroAssembler* masm) {
GenerateImpl(masm, false);
}
void VectorRawKeyedLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
GenerateImpl(masm, true);
}
void VectorRawKeyedLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
Register receiver = VectorLoadICDescriptor::ReceiverRegister(); // rdx
Register key = VectorLoadICDescriptor::NameRegister(); // rcx
Register vector = VectorLoadICDescriptor::VectorRegister(); // rbx
Register slot = VectorLoadICDescriptor::SlotRegister(); // rax
Register feedback = rdi;
Register integer_slot = r8;
__ SmiToInteger32(integer_slot, slot);
__ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
FixedArray::kHeaderSize));
// Is it a weak cell?
Label try_array;
Label not_array, smi_key, key_okay, miss;
__ CompareRoot(FieldOperand(feedback, 0), Heap::kWeakCellMapRootIndex);
__ j(not_equal, &try_array);
__ JumpIfNotSmi(key, &miss);
HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback,
integer_slot, &miss);
__ bind(&try_array);
// Is it a fixed array?
__ CompareRoot(FieldOperand(feedback, 0), Heap::kFixedArrayMapRootIndex);
__ j(not_equal, &not_array);
// We have a polymorphic element handler.
__ JumpIfNotSmi(key, &miss);
Label polymorphic, try_poly_name;
__ bind(&polymorphic);
HandleArrayCases(masm, receiver, key, vector, slot, feedback, integer_slot,
r9, r11, r15, true, &miss);
__ bind(&not_array);
// Is it generic?
__ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
__ j(not_equal, &try_poly_name);
Handle<Code> megamorphic_stub =
KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
__ jmp(megamorphic_stub, RelocInfo::CODE_TARGET);
__ bind(&try_poly_name);
// We might have a name in feedback, and a fixed array in the next slot.
__ cmpp(key, feedback);
__ j(not_equal, &miss);
// If the name comparison succeeded, we know we have a fixed array with
// at least one map/handler pair.
__ movp(feedback, FieldOperand(vector, integer_slot, times_pointer_size,
FixedArray::kHeaderSize + kPointerSize));
HandleArrayCases(masm, receiver, key, vector, slot, feedback, integer_slot,
r9, r11, r15, false, &miss);
__ bind(&miss);
KeyedLoadIC::GenerateMiss(masm);
}
......
......@@ -71,8 +71,8 @@ TEST(VectorStructure) {
CHECK_EQ(index,
TypeFeedbackVector::kReservedIndexCount + metadata_length + 3);
CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5,
CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 +
5 * TypeFeedbackVector::elements_per_ic_slot(),
vector->length());
}
......
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