#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"
void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
- VectorLoadStub stub(isolate(), state());
- __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+ VectorRawLoadStub stub(isolate(), state());
+ stub.GenerateForTrampoline(masm);
}
void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
- VectorKeyedLoadStub stub(isolate());
- __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+ VectorRawKeyedLoadStub stub(isolate());
+ stub.GenerateForTrampoline(masm);
}
}
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+ GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+ GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+ Register key, Register vector, Register slot,
+ Register feedback, Register scratch1,
+ Register scratch2, Register scratch3,
+ 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 cached_map = scratch2;
+
+ // Receiver might not be a heap object.
+ __ JumpIfSmi(receiver, &load_smi_map);
+ __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ bind(&compare_map);
+ __ ldr(cached_map,
+ FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+ __ ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+ __ cmp(receiver_map, cached_map);
+ __ b(ne, &start_polymorphic);
+ // found, now call handler.
+ Register handler = feedback;
+ __ ldr(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+ __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+
+ Register length = scratch3;
+ __ bind(&start_polymorphic);
+ __ ldr(length, FieldMemOperand(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.
+ __ cmp(length, Operand(Smi::FromInt(2)));
+ __ b(eq, miss);
+ }
+
+ Register too_far = length;
+ Register pointer_reg = feedback;
+
+ // +-----+------+------+-----+-----+ ... ----+
+ // | map | len | wm0 | h0 | wm1 | hN |
+ // +-----+------+------+-----+-----+ ... ----+
+ // 0 1 2 len-1
+ // ^ ^
+ // | |
+ // pointer_reg too_far
+ // aka feedback scratch3
+ // also need receiver_map (aka scratch1)
+ // use cached_map (scratch2) to look in the weak map values.
+ __ add(too_far, feedback, Operand::PointerOffsetFromSmiKey(length));
+ __ add(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ add(pointer_reg, feedback,
+ Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
+
+ __ bind(&next_loop);
+ __ ldr(cached_map, MemOperand(pointer_reg));
+ __ ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+ __ cmp(receiver_map, cached_map);
+ __ b(ne, &prepare_next);
+ __ ldr(handler, MemOperand(pointer_reg, kPointerSize));
+ __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+ __ bind(&prepare_next);
+ __ add(pointer_reg, pointer_reg, Operand(kPointerSize * 2));
+ __ cmp(pointer_reg, too_far);
+ __ b(lt, &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 scratch,
+ Label* miss) {
+ // feedback initially contains the feedback array
+ Label compare_smi_map;
+ Register receiver_map = scratch;
+ Register cached_map = weak_cell;
+
+ // Move the weak map into the weak_cell register.
+ __ ldr(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+ // Receiver might not be a heap object.
+ __ JumpIfSmi(receiver, &compare_smi_map);
+ __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ cmp(cached_map, receiver_map);
+ __ b(ne, miss);
+
+ Register handler = weak_cell;
+ __ add(handler, vector, Operand::PointerOffsetFromSmiKey(slot));
+ __ ldr(handler,
+ FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+ __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+
+ // 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(weak_cell, Heap::kHeapNumberMapRootIndex);
+ __ b(ne, miss);
+ __ add(handler, vector, Operand::PointerOffsetFromSmiKey(slot));
+ __ ldr(handler,
+ FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+ __ add(pc, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+ Register receiver = VectorLoadICDescriptor::ReceiverRegister(); // r1
+ Register name = VectorLoadICDescriptor::NameRegister(); // r2
+ Register vector = VectorLoadICDescriptor::VectorRegister(); // r3
+ Register slot = VectorLoadICDescriptor::SlotRegister(); // r0
+ Register feedback = r4;
+ Register scratch1 = r5;
+
+ __ add(feedback, vector, Operand::PointerOffsetFromSmiKey(slot));
+ __ ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+ // Is it a weak cell?
+ Label try_array;
+ Label not_array, smi_key, key_okay, miss;
+ __ ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+ __ CompareRoot(scratch1, Heap::kWeakCellMapRootIndex);
+ __ b(ne, &try_array);
+ HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+ &miss);
+
+ // Is it a fixed array?
+ __ bind(&try_array);
+ __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex);
+ __ b(ne, ¬_array);
+ HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, r8,
+ r9, true, &miss);
+
+ __ bind(¬_array);
+ __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+ __ b(ne, &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,
+ scratch1, r8, r9);
+
+ __ 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(); // r1
+ Register key = VectorLoadICDescriptor::NameRegister(); // r2
+ Register vector = VectorLoadICDescriptor::VectorRegister(); // r3
+ Register slot = VectorLoadICDescriptor::SlotRegister(); // r0
+ Register feedback = r4;
+ Register scratch1 = r5;
+
+ __ add(feedback, vector, Operand::PointerOffsetFromSmiKey(slot));
+ __ ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+ // Is it a weak cell?
+ Label try_array;
+ Label not_array, smi_key, key_okay, miss;
+ __ ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+ __ CompareRoot(scratch1, Heap::kWeakCellMapRootIndex);
+ __ b(ne, &try_array);
+ __ JumpIfNotSmi(key, &miss);
+ HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+ &miss);
+
+ __ bind(&try_array);
+ // Is it a fixed array?
+ __ CompareRoot(scratch1, Heap::kFixedArrayMapRootIndex);
+ __ b(ne, ¬_array);
+ // We have a polymorphic element handler.
+ __ JumpIfNotSmi(key, &miss);
+
+ Label polymorphic, try_poly_name;
+ __ bind(&polymorphic);
+ HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, r8,
+ r9, true, &miss);
+
+ __ bind(¬_array);
+ // Is it generic?
+ __ CompareRoot(feedback, Heap::kmegamorphic_symbolRootIndex);
+ __ b(ne, &try_poly_name);
+ Handle<Code> megamorphic_stub =
+ KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+ __ Jump(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);
+ __ b(ne, &miss);
+ // If the name comparison succeeded, we know we have a fixed array with
+ // at least one map/handler pair.
+ __ add(feedback, vector, Operand::PointerOffsetFromSmiKey(slot));
+ __ ldr(feedback,
+ FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+ HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, r8,
+ r9, false, &miss);
+
+ __ bind(&miss);
+ KeyedLoadIC::GenerateMiss(masm);
+}
+
+
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
if (masm->isolate()->function_entry_hook() != NULL) {
ProfileEntryHookStub stub(masm->isolate());
#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"
void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
- VectorLoadStub stub(isolate(), state());
- __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+ VectorRawLoadStub stub(isolate(), state());
+ stub.GenerateForTrampoline(masm);
}
void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
- VectorKeyedLoadStub stub(isolate());
- __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+ VectorRawKeyedLoadStub stub(isolate());
+ stub.GenerateForTrampoline(masm);
}
}
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+ GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+ GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+ Register key, Register vector, Register slot,
+ Register feedback, Register scratch1,
+ Register scratch2, Register scratch3,
+ 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 cached_map = scratch2;
+
+ // Receiver might not be a heap object.
+ __ JumpIfSmi(receiver, &load_smi_map);
+ __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ Bind(&compare_map);
+ __ Ldr(cached_map,
+ FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+ __ Ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+ __ Cmp(receiver_map, cached_map);
+ __ B(ne, &start_polymorphic);
+ // found, now call handler.
+ Register handler = feedback;
+ __ Ldr(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+ __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+ __ Jump(feedback);
+
+ Register length = scratch3;
+ __ Bind(&start_polymorphic);
+ __ Ldr(length, FieldMemOperand(feedback, FixedArray::kLengthOffset));
+ if (!is_polymorphic) {
+ __ Cmp(length, Operand(Smi::FromInt(2)));
+ __ B(eq, miss);
+ }
+
+ Register too_far = length;
+ Register pointer_reg = feedback;
+
+ // +-----+------+------+-----+-----+ ... ----+
+ // | map | len | wm0 | h0 | wm1 | hN |
+ // +-----+------+------+-----+-----+ ... ----+
+ // 0 1 2 len-1
+ // ^ ^
+ // | |
+ // pointer_reg too_far
+ // aka feedback scratch3
+ // also need receiver_map (aka scratch1)
+ // use cached_map (scratch2) to look in the weak map values.
+ __ Add(too_far, feedback,
+ Operand::UntagSmiAndScale(length, kPointerSizeLog2));
+ __ Add(too_far, too_far, FixedArray::kHeaderSize - kHeapObjectTag);
+ __ Add(pointer_reg, feedback,
+ FixedArray::OffsetOfElementAt(2) - kHeapObjectTag);
+
+ __ Bind(&next_loop);
+ __ Ldr(cached_map, MemOperand(pointer_reg));
+ __ Ldr(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+ __ Cmp(receiver_map, cached_map);
+ __ B(ne, &prepare_next);
+ __ Ldr(handler, MemOperand(pointer_reg, kPointerSize));
+ __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+ __ Jump(handler);
+
+ __ Bind(&prepare_next);
+ __ Add(pointer_reg, pointer_reg, kPointerSize * 2);
+ __ Cmp(pointer_reg, too_far);
+ __ B(lt, &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 scratch,
+ Label* miss) {
+ // feedback initially contains the feedback array
+ Label compare_smi_map;
+ Register receiver_map = scratch;
+ Register cached_map = weak_cell;
+
+ // Move the weak map into the weak_cell register.
+ __ Ldr(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+ // Receiver might not be a heap object.
+ __ JumpIfSmi(receiver, &compare_smi_map);
+ __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ Cmp(cached_map, receiver_map);
+ __ B(ne, miss);
+
+ Register handler = weak_cell;
+ __ Add(handler, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+ __ Ldr(handler,
+ FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+ __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+ __ Jump(weak_cell);
+
+ // 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.
+ // TODO(mvstanton): does this hold on ARM?
+ __ Bind(&compare_smi_map);
+ __ JumpIfNotRoot(weak_cell, Heap::kHeapNumberMapRootIndex, miss);
+ __ Add(handler, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+ __ Ldr(handler,
+ FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+ __ Add(handler, handler, Code::kHeaderSize - kHeapObjectTag);
+ __ Jump(handler);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+ Register receiver = VectorLoadICDescriptor::ReceiverRegister(); // x1
+ Register name = VectorLoadICDescriptor::NameRegister(); // x2
+ Register vector = VectorLoadICDescriptor::VectorRegister(); // x3
+ Register slot = VectorLoadICDescriptor::SlotRegister(); // x0
+ Register feedback = x4;
+ Register scratch1 = x5;
+
+ __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+ __ Ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+ // Is it a weak cell?
+ Label try_array;
+ Label not_array, smi_key, key_okay, miss;
+ __ Ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+ __ JumpIfNotRoot(scratch1, Heap::kWeakCellMapRootIndex, &try_array);
+ HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+ &miss);
+
+ // Is it a fixed array?
+ __ Bind(&try_array);
+ __ JumpIfNotRoot(scratch1, Heap::kFixedArrayMapRootIndex, ¬_array);
+ HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, x6,
+ x7, true, &miss);
+
+ __ Bind(¬_array);
+ __ JumpIfNotRoot(feedback, Heap::kmegamorphic_symbolRootIndex, &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,
+ scratch1, x6, x7);
+
+ __ 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(); // x1
+ Register key = VectorLoadICDescriptor::NameRegister(); // x2
+ Register vector = VectorLoadICDescriptor::VectorRegister(); // x3
+ Register slot = VectorLoadICDescriptor::SlotRegister(); // x0
+ Register feedback = x4;
+ Register scratch1 = x5;
+
+ __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+ __ Ldr(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+ // Is it a weak cell?
+ Label try_array;
+ Label not_array, smi_key, key_okay, miss;
+ __ Ldr(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+ __ JumpIfNotRoot(scratch1, Heap::kWeakCellMapRootIndex, &try_array);
+ __ JumpIfNotSmi(key, &miss);
+ HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+ &miss);
+
+ __ Bind(&try_array);
+ // Is it a fixed array?
+ __ JumpIfNotRoot(scratch1, Heap::kFixedArrayMapRootIndex, ¬_array);
+ // We have a polymorphic element handler.
+ __ JumpIfNotSmi(key, &miss);
+
+ Label polymorphic, try_poly_name;
+ __ Bind(&polymorphic);
+ HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, x6,
+ x7, true, &miss);
+
+ __ Bind(¬_array);
+ // Is it generic?
+ __ JumpIfNotRoot(feedback, Heap::kmegamorphic_symbolRootIndex,
+ &try_poly_name);
+ Handle<Code> megamorphic_stub =
+ KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+ __ Jump(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);
+ __ B(ne, &miss);
+ // If the name comparison succeeded, we know we have a fixed array with
+ // at least one map/handler pair.
+ __ Add(feedback, vector, Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
+ __ Ldr(feedback,
+ FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+ HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, x6,
+ x7, false, &miss);
+
+ __ Bind(&miss);
+ KeyedLoadIC::GenerateMiss(masm);
+}
+
+
// The entry hook is a "BumpSystemStackPointer" instruction (sub), followed by
// a "Push lr" instruction, followed by a call.
static const unsigned int kProfileEntryHookCallSize =
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,
}
-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);
}
}
-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) {}
V(StringAdd) \
V(ToBoolean) \
V(TransitionElementsKind) \
- V(VectorKeyedLoad) \
- V(VectorLoad) \
+ V(VectorRawKeyedLoad) \
+ V(VectorRawLoad) \
/* IC Handler stubs */ \
V(LoadConstant) \
V(LoadField) \
};
-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);
};
#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"
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, ¬_array);
+ HandleArrayCases(masm, receiver, name, vector, slot, scratch, true, &miss);
+
+ __ bind(¬_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, ¬_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(¬_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);
}
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);
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:
#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"
void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
- VectorLoadStub stub(isolate(), state());
- __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+ VectorRawLoadStub stub(isolate(), state());
+ stub.GenerateForTrampoline(masm);
}
void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
- VectorKeyedLoadStub stub(isolate());
- __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+ VectorRawKeyedLoadStub stub(isolate());
+ stub.GenerateForTrampoline(masm);
}
}
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+ GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+ GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+ Register key, Register vector, Register slot,
+ Register feedback, Register scratch1,
+ Register scratch2, Register scratch3,
+ 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 cached_map = scratch2;
+
+ // Receiver might not be a heap object.
+ __ JumpIfSmi(receiver, &load_smi_map);
+ __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ bind(&compare_map);
+ __ lw(cached_map,
+ FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+ __ lw(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+ __ Branch(&start_polymorphic, ne, receiver_map, Operand(cached_map));
+ // found, now call handler.
+ Register handler = feedback;
+ __ lw(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+ __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Jump(t9);
+
+
+ Register length = scratch3;
+ __ bind(&start_polymorphic);
+ __ lw(length, FieldMemOperand(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.
+ __ Branch(miss, eq, length, Operand(Smi::FromInt(2)));
+ }
+
+ Register too_far = length;
+ Register pointer_reg = feedback;
+
+ // +-----+------+------+-----+-----+ ... ----+
+ // | map | len | wm0 | h0 | wm1 | hN |
+ // +-----+------+------+-----+-----+ ... ----+
+ // 0 1 2 len-1
+ // ^ ^
+ // | |
+ // pointer_reg too_far
+ // aka feedback scratch3
+ // also need receiver_map (aka scratch1)
+ // use cached_map (scratch2) to look in the weak map values.
+ __ sll(at, length, kPointerSizeLog2 - kSmiTagSize);
+ __ Addu(too_far, feedback, Operand(at));
+ __ Addu(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ Addu(pointer_reg, feedback,
+ Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
+
+ __ bind(&next_loop);
+ __ lw(cached_map, MemOperand(pointer_reg));
+ __ lw(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+ __ Branch(&prepare_next, ne, receiver_map, Operand(cached_map));
+ __ lw(handler, MemOperand(pointer_reg, kPointerSize));
+ __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Jump(t9);
+
+ __ bind(&prepare_next);
+ __ Addu(pointer_reg, pointer_reg, Operand(kPointerSize * 2));
+ __ Branch(&next_loop, lt, pointer_reg, Operand(too_far));
+
+ // 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 scratch,
+ Label* miss) {
+ // feedback initially contains the feedback array
+ Label compare_smi_map;
+ Register receiver_map = scratch;
+ Register cached_map = weak_cell;
+
+ // Move the weak map into the weak_cell register.
+ __ lw(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+ // Receiver might not be a heap object.
+ __ JumpIfSmi(receiver, &compare_smi_map);
+ __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ Branch(miss, ne, cached_map, Operand(receiver_map));
+
+ Register handler = weak_cell;
+ __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+ __ Addu(handler, vector, Operand(at));
+ __ lw(handler,
+ FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+ __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Jump(t9);
+
+ // 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);
+ __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
+ __ Branch(miss, ne, at, Operand(weak_cell));
+ __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+ __ Addu(handler, vector, Operand(at));
+ __ lw(handler,
+ FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+ __ Addu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Jump(t9);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+ Register receiver = VectorLoadICDescriptor::ReceiverRegister(); // a1
+ Register name = VectorLoadICDescriptor::NameRegister(); // a2
+ Register vector = VectorLoadICDescriptor::VectorRegister(); // a3
+ Register slot = VectorLoadICDescriptor::SlotRegister(); // a0
+ Register feedback = t0;
+ Register scratch1 = t1;
+
+ __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+ __ Addu(feedback, vector, Operand(at));
+ __ lw(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+ // Is it a weak cell?
+ Label try_array;
+ Label not_array, smi_key, key_okay, miss;
+ __ lw(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+ __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+ __ Branch(&try_array, ne, at, Operand(scratch1));
+ HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+ &miss);
+
+ // Is it a fixed array?
+ __ bind(&try_array);
+ __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+ __ Branch(¬_array, ne, at, Operand(scratch1));
+ HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, t4,
+ t5, true, &miss);
+
+ __ bind(¬_array);
+ __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+ __ Branch(&miss, ne, at, Operand(feedback));
+ 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,
+ scratch1, t4, t5);
+
+ __ 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(); // a1
+ Register key = VectorLoadICDescriptor::NameRegister(); // a2
+ Register vector = VectorLoadICDescriptor::VectorRegister(); // a3
+ Register slot = VectorLoadICDescriptor::SlotRegister(); // a0
+ Register feedback = t0;
+ Register scratch1 = t1;
+
+ __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+ __ Addu(feedback, vector, Operand(at));
+ __ lw(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+ // Is it a weak cell?
+ Label try_array;
+ Label not_array, smi_key, key_okay, miss;
+ __ lw(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+ __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+ __ Branch(&try_array, ne, at, Operand(scratch1));
+ __ JumpIfNotSmi(key, &miss);
+ HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+ &miss);
+
+ __ bind(&try_array);
+ // Is it a fixed array?
+ __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+ __ Branch(¬_array, ne, at, Operand(scratch1));
+ // We have a polymorphic element handler.
+ __ JumpIfNotSmi(key, &miss);
+
+ Label polymorphic, try_poly_name;
+ __ bind(&polymorphic);
+ HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, t4,
+ t5, true, &miss);
+
+ __ bind(¬_array);
+ // Is it generic?
+ __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+ __ Branch(&try_poly_name, ne, at, Operand(feedback));
+ Handle<Code> megamorphic_stub =
+ KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+ __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+ __ bind(&try_poly_name);
+ // We might have a name in feedback, and a fixed array in the next slot.
+ __ Branch(&miss, ne, key, Operand(feedback));
+ // If the name comparison succeeded, we know we have a fixed array with
+ // at least one map/handler pair.
+ __ sll(at, slot, kPointerSizeLog2 - kSmiTagSize);
+ __ Addu(feedback, vector, Operand(at));
+ __ lw(feedback,
+ FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+ HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, t4,
+ t5, false, &miss);
+
+ __ bind(&miss);
+ KeyedLoadIC::GenerateMiss(masm);
+}
+
+
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
if (masm->isolate()->function_entry_hook() != NULL) {
ProfileEntryHookStub stub(masm->isolate());
#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"
void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
- VectorLoadStub stub(isolate(), state());
- __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+ VectorRawLoadStub stub(isolate(), state());
+ stub.GenerateForTrampoline(masm);
}
void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
- VectorKeyedLoadStub stub(isolate());
- __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+ VectorRawKeyedLoadStub stub(isolate());
+ stub.GenerateForTrampoline(masm);
}
}
+void VectorRawLoadStub::Generate(MacroAssembler* masm) {
+ GenerateImpl(masm, false);
+}
+
+
+void VectorRawLoadStub::GenerateForTrampoline(MacroAssembler* masm) {
+ GenerateImpl(masm, true);
+}
+
+
+static void HandleArrayCases(MacroAssembler* masm, Register receiver,
+ Register key, Register vector, Register slot,
+ Register feedback, Register scratch1,
+ Register scratch2, Register scratch3,
+ 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 cached_map = scratch2;
+
+ // Receiver might not be a heap object.
+ __ JumpIfSmi(receiver, &load_smi_map);
+ __ ld(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ bind(&compare_map);
+ __ ld(cached_map,
+ FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(0)));
+ __ ld(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+ __ Branch(&start_polymorphic, ne, receiver_map, Operand(cached_map));
+ // found, now call handler.
+ Register handler = feedback;
+ __ ld(handler, FieldMemOperand(feedback, FixedArray::OffsetOfElementAt(1)));
+ __ Daddu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Jump(t9);
+
+ Register length = scratch3;
+ __ bind(&start_polymorphic);
+ __ ld(length, FieldMemOperand(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.
+ __ Branch(miss, eq, length, Operand(Smi::FromInt(2)));
+ }
+
+ Register too_far = length;
+ Register pointer_reg = feedback;
+
+ // +-----+------+------+-----+-----+ ... ----+
+ // | map | len | wm0 | h0 | wm1 | hN |
+ // +-----+------+------+-----+-----+ ... ----+
+ // 0 1 2 len-1
+ // ^ ^
+ // | |
+ // pointer_reg too_far
+ // aka feedback scratch3
+ // also need receiver_map (aka scratch1)
+ // use cached_map (scratch2) to look in the weak map values.
+ __ SmiScale(too_far, length, kPointerSizeLog2);
+ __ Daddu(too_far, feedback, Operand(too_far));
+ __ Daddu(too_far, too_far, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+ __ Daddu(pointer_reg, feedback,
+ Operand(FixedArray::OffsetOfElementAt(2) - kHeapObjectTag));
+
+ __ bind(&next_loop);
+ __ ld(cached_map, MemOperand(pointer_reg));
+ __ ld(cached_map, FieldMemOperand(cached_map, WeakCell::kValueOffset));
+ __ Branch(&prepare_next, ne, receiver_map, Operand(cached_map));
+ __ ld(handler, MemOperand(pointer_reg, kPointerSize));
+ __ Daddu(t9, handler, Operand(Code::kHeaderSize - kHeapObjectTag));
+ __ Jump(t9);
+
+ __ bind(&prepare_next);
+ __ Daddu(pointer_reg, pointer_reg, Operand(kPointerSize * 2));
+ __ Branch(&next_loop, lt, pointer_reg, Operand(too_far));
+
+ // We exhausted our array of map handler pairs.
+ __ Branch(miss);
+
+ __ bind(&load_smi_map);
+ __ LoadRoot(receiver_map, Heap::kHeapNumberMapRootIndex);
+ __ Branch(&compare_map);
+}
+
+
+static void HandleMonomorphicCase(MacroAssembler* masm, Register receiver,
+ Register key, Register vector, Register slot,
+ Register weak_cell, Register scratch,
+ Label* miss) {
+ // feedback initially contains the feedback array
+ Label compare_smi_map;
+ Register receiver_map = scratch;
+ Register cached_map = weak_cell;
+
+ // Move the weak map into the weak_cell register.
+ __ ld(cached_map, FieldMemOperand(weak_cell, WeakCell::kValueOffset));
+
+ // Receiver might not be a heap object.
+ __ JumpIfSmi(receiver, &compare_smi_map);
+ __ ld(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ Branch(miss, ne, cached_map, Operand(receiver_map));
+
+ Register handler = weak_cell;
+ __ SmiScale(handler, slot, kPointerSizeLog2);
+ __ Daddu(handler, vector, Operand(handler));
+ __ ld(handler,
+ FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+ __ Daddu(t9, handler, Code::kHeaderSize - kHeapObjectTag);
+ __ Jump(t9);
+
+ // 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.
+ // TODO(mvstanton): does this hold on ARM?
+ __ bind(&compare_smi_map);
+ __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
+ __ Branch(miss, ne, weak_cell, Operand(at));
+ __ SmiScale(handler, slot, kPointerSizeLog2);
+ __ Daddu(handler, vector, Operand(handler));
+ __ ld(handler,
+ FieldMemOperand(handler, FixedArray::kHeaderSize + kPointerSize));
+ __ Daddu(t9, handler, Code::kHeaderSize - kHeapObjectTag);
+ __ Jump(t9);
+}
+
+
+void VectorRawLoadStub::GenerateImpl(MacroAssembler* masm, bool in_frame) {
+ Register receiver = VectorLoadICDescriptor::ReceiverRegister(); // a1
+ Register name = VectorLoadICDescriptor::NameRegister(); // a2
+ Register vector = VectorLoadICDescriptor::VectorRegister(); // a3
+ Register slot = VectorLoadICDescriptor::SlotRegister(); // a0
+ Register feedback = a4;
+ Register scratch1 = a5;
+
+ __ SmiScale(feedback, slot, kPointerSizeLog2);
+ __ Daddu(feedback, vector, Operand(feedback));
+ __ ld(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+ // Is it a weak cell?
+ Label try_array;
+ Label not_array, smi_key, key_okay, miss;
+ __ ld(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+ __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+ __ Branch(&try_array, ne, scratch1, Operand(at));
+ HandleMonomorphicCase(masm, receiver, name, vector, slot, feedback, scratch1,
+ &miss);
+
+ // Is it a fixed array?
+ __ bind(&try_array);
+ __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+ __ Branch(¬_array, ne, scratch1, Operand(at));
+ HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, a6,
+ a7, true, &miss);
+
+ __ bind(¬_array);
+ __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+ __ Branch(&miss, ne, feedback, Operand(at));
+ 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,
+ scratch1, a6, a7);
+
+ __ 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(); // a1
+ Register key = VectorLoadICDescriptor::NameRegister(); // a2
+ Register vector = VectorLoadICDescriptor::VectorRegister(); // a3
+ Register slot = VectorLoadICDescriptor::SlotRegister(); // a0
+ Register feedback = a4;
+ Register scratch1 = a5;
+
+ __ SmiScale(feedback, slot, kPointerSizeLog2);
+ __ Daddu(feedback, vector, Operand(feedback));
+ __ ld(feedback, FieldMemOperand(feedback, FixedArray::kHeaderSize));
+
+ // Is it a weak cell?
+ Label try_array;
+ Label not_array, smi_key, key_okay, miss;
+ __ ld(scratch1, FieldMemOperand(feedback, HeapObject::kMapOffset));
+ __ LoadRoot(at, Heap::kWeakCellMapRootIndex);
+ __ Branch(&try_array, ne, scratch1, Operand(at));
+ __ JumpIfNotSmi(key, &miss);
+ HandleMonomorphicCase(masm, receiver, key, vector, slot, feedback, scratch1,
+ &miss);
+
+ __ bind(&try_array);
+ // Is it a fixed array?
+ __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
+ __ Branch(¬_array, ne, scratch1, Operand(at));
+ // We have a polymorphic element handler.
+ __ JumpIfNotSmi(key, &miss);
+
+ Label polymorphic, try_poly_name;
+ __ bind(&polymorphic);
+ HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, a6,
+ a7, true, &miss);
+
+ __ bind(¬_array);
+ // Is it generic?
+ __ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
+ __ Branch(&try_poly_name, ne, feedback, Operand(at));
+ Handle<Code> megamorphic_stub =
+ KeyedLoadIC::ChooseMegamorphicStub(masm->isolate());
+ __ Jump(megamorphic_stub, RelocInfo::CODE_TARGET);
+
+ __ bind(&try_poly_name);
+ // We might have a name in feedback, and a fixed array in the next slot.
+ __ Branch(&miss, ne, key, Operand(feedback));
+ // If the name comparison succeeded, we know we have a fixed array with
+ // at least one map/handler pair.
+ __ SmiScale(feedback, slot, kPointerSizeLog2);
+ __ Daddu(feedback, vector, Operand(feedback));
+ __ ld(feedback,
+ FieldMemOperand(feedback, FixedArray::kHeaderSize + kPointerSize));
+ HandleArrayCases(masm, receiver, key, vector, slot, feedback, scratch1, a6,
+ a7, false, &miss);
+
+ __ bind(&miss);
+ KeyedLoadIC::GenerateMiss(masm);
+}
+
+
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
if (masm->isolate()->function_entry_hook() != NULL) {
ProfileEntryHookStub stub(masm->isolate());
const int ic_slot_count = spec.ic_slots();
const int index_count =
FLAG_vector_ics ? VectorICComputer::word_count(ic_slot_count) : 0;
- const int length =
- slot_count + ic_slot_count + index_count + kReservedIndexCount;
+ const int length = slot_count + (ic_slot_count * elements_per_ic_slot()) +
+ index_count + kReservedIndexCount;
if (length == kReservedIndexCount) {
return Handle<TypeFeedbackVector>::cast(
isolate->factory()->empty_fixed_array());
}
-void FeedbackNexus::InstallHandlers(int start_index, MapHandleList* maps,
- CodeHandleList* handlers) {
+Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
Isolate* isolate = GetIsolate();
- Handle<FixedArray> array = handle(FixedArray::cast(GetFeedback()), isolate);
+ Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
+ if (!feedback_extra->IsFixedArray() ||
+ FixedArray::cast(*feedback_extra)->length() != length) {
+ Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
+ SetFeedbackExtra(*array);
+ return array;
+ }
+ return Handle<FixedArray>::cast(feedback_extra);
+}
+
+
+void FeedbackNexus::InstallHandlers(Handle<FixedArray> array,
+ MapHandleList* maps,
+ CodeHandleList* handlers) {
int receiver_count = maps->length();
for (int current = 0; current < receiver_count; ++current) {
Handle<Map> map = maps->at(current);
Handle<WeakCell> cell = Map::WeakCellForMap(map);
- array->set(start_index + (current * 2), *cell);
- array->set(start_index + (current * 2 + 1), *handlers->at(current));
+ array->set(current * 2, *cell);
+ array->set(current * 2 + 1, *handlers->at(current));
}
}
InlineCacheState LoadICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
+
if (feedback == *vector()->UninitializedSentinel(isolate)) {
return UNINITIALIZED;
} else if (feedback == *vector()->MegamorphicSentinel(isolate)) {
} else if (feedback->IsFixedArray()) {
// Determine state purely by our structure, don't check if the maps are
// cleared.
- FixedArray* array = FixedArray::cast(feedback);
- int length = array->length();
- DCHECK(length >= 2);
- return length == 2 ? MONOMORPHIC : POLYMORPHIC;
+ return POLYMORPHIC;
+ } else if (feedback->IsWeakCell()) {
+ // Don't check if the map is cleared.
+ return MONOMORPHIC;
}
return UNINITIALIZED;
InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
+
if (feedback == *vector()->UninitializedSentinel(isolate)) {
return UNINITIALIZED;
} else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
} else if (feedback->IsFixedArray()) {
// Determine state purely by our structure, don't check if the maps are
// cleared.
- FixedArray* array = FixedArray::cast(feedback);
- int length = array->length();
- DCHECK(length >= 3);
- return length == 3 ? MONOMORPHIC : POLYMORPHIC;
+ return POLYMORPHIC;
+ } else if (feedback->IsWeakCell()) {
+ // Don't check if the map is cleared.
+ return MONOMORPHIC;
+ } else if (feedback->IsName()) {
+ Object* extra = GetFeedbackExtra();
+ FixedArray* extra_array = FixedArray::cast(extra);
+ return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
}
return UNINITIALIZED;
InlineCacheState CallICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
+ DCHECK(!FLAG_vector_ics ||
+ GetFeedbackExtra() == *vector()->UninitializedSentinel(isolate));
if (feedback == *vector()->MegamorphicSentinel(isolate)) {
return GENERIC;
void KeyedLoadICNexus::ConfigureMegamorphic() {
- SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+ Isolate* isolate = GetIsolate();
+ SetFeedback(*vector()->MegamorphicSentinel(isolate), SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(*vector()->UninitializedSentinel(isolate),
+ SKIP_WRITE_BARRIER);
}
void LoadICNexus::ConfigureMegamorphic() {
SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(*vector()->UninitializedSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
}
void LoadICNexus::ConfigurePremonomorphic() {
SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(*vector()->UninitializedSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
}
void KeyedLoadICNexus::ConfigurePremonomorphic() {
- SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
- SKIP_WRITE_BARRIER);
+ Isolate* isolate = GetIsolate();
+ SetFeedback(*vector()->PremonomorphicSentinel(isolate), SKIP_WRITE_BARRIER);
+ SetFeedbackExtra(*vector()->UninitializedSentinel(isolate),
+ SKIP_WRITE_BARRIER);
}
void LoadICNexus::ConfigureMonomorphic(Handle<Map> receiver_map,
Handle<Code> handler) {
- Handle<FixedArray> array = EnsureArrayOfSize(2);
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
- array->set(0, *cell);
- array->set(1, *handler);
+ SetFeedback(*cell);
+ SetFeedbackExtra(*handler);
}
void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
Handle<Map> receiver_map,
Handle<Code> handler) {
- Handle<FixedArray> array = EnsureArrayOfSize(3);
+ Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
if (name.is_null()) {
- array->set(0, Smi::FromInt(0));
+ SetFeedback(*cell);
+ SetFeedbackExtra(*handler);
} else {
- array->set(0, *name);
+ SetFeedback(*name);
+ Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
+ array->set(0, *cell);
+ array->set(1, *handler);
}
- Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
- array->set(1, *cell);
- array->set(2, *handler);
}
void LoadICNexus::ConfigurePolymorphic(MapHandleList* maps,
CodeHandleList* handlers) {
+ Isolate* isolate = GetIsolate();
int receiver_count = maps->length();
- EnsureArrayOfSize(receiver_count * 2);
- InstallHandlers(0, maps, handlers);
+ Handle<FixedArray> array = EnsureArrayOfSize(receiver_count * 2);
+ InstallHandlers(array, maps, handlers);
+ SetFeedbackExtra(*vector()->UninitializedSentinel(isolate),
+ SKIP_WRITE_BARRIER);
}
MapHandleList* maps,
CodeHandleList* handlers) {
int receiver_count = maps->length();
- Handle<FixedArray> array = EnsureArrayOfSize(1 + receiver_count * 2);
+ DCHECK(receiver_count > 1);
+ Handle<FixedArray> array;
if (name.is_null()) {
- array->set(0, Smi::FromInt(0));
+ array = EnsureArrayOfSize(receiver_count * 2);
+ SetFeedbackExtra(*vector()->UninitializedSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
} else {
- array->set(0, *name);
+ SetFeedback(*name);
+ array = EnsureExtraArrayOfSize(receiver_count * 2);
}
- InstallHandlers(1, maps, handlers);
+
+ InstallHandlers(array, maps, handlers);
}
-int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
+int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
- if (feedback->IsFixedArray()) {
+ if (feedback->IsFixedArray() || feedback->IsString()) {
int found = 0;
+ if (feedback->IsString()) {
+ feedback = GetFeedbackExtra();
+ }
FixedArray* array = FixedArray::cast(feedback);
// The array should be of the form [<optional name>], then
// [map, handler, map, handler, ... ]
- DCHECK(array->length() >= (2 + start_index));
- for (int i = start_index; i < array->length(); i += 2) {
+ DCHECK(array->length() >= 2);
+ for (int i = 0; i < array->length(); i += 2) {
WeakCell* cell = WeakCell::cast(array->get(i));
if (!cell->cleared()) {
Map* map = Map::cast(cell->value());
}
}
return found;
+ } else if (feedback->IsWeakCell()) {
+ WeakCell* cell = WeakCell::cast(feedback);
+ if (!cell->cleared()) {
+ Map* map = Map::cast(cell->value());
+ maps->Add(handle(map, isolate));
+ return 1;
+ }
}
return 0;
}
-MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index,
- Handle<Map> map) const {
+MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
Object* feedback = GetFeedback();
- if (feedback->IsFixedArray()) {
+ if (feedback->IsFixedArray() || feedback->IsString()) {
+ if (feedback->IsString()) {
+ feedback = GetFeedbackExtra();
+ }
FixedArray* array = FixedArray::cast(feedback);
- for (int i = start_index; i < array->length(); i += 2) {
+ for (int i = 0; i < array->length(); i += 2) {
WeakCell* cell = WeakCell::cast(array->get(i));
if (!cell->cleared()) {
Map* array_map = Map::cast(cell->value());
}
}
}
+ } else if (feedback->IsWeakCell()) {
+ WeakCell* cell = WeakCell::cast(feedback);
+ if (!cell->cleared()) {
+ Map* cell_map = Map::cast(cell->value());
+ if (cell_map == *map) {
+ Code* code = Code::cast(GetFeedbackExtra());
+ DCHECK(code->kind() == Code::HANDLER);
+ return handle(code);
+ }
+ }
}
return MaybeHandle<Code>();
}
-bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
- int length) const {
+bool FeedbackNexus::FindHandlers(CodeHandleList* code_list, int length) const {
Object* feedback = GetFeedback();
int count = 0;
- if (feedback->IsFixedArray()) {
+ if (feedback->IsFixedArray() || feedback->IsString()) {
+ if (feedback->IsString()) {
+ feedback = GetFeedbackExtra();
+ }
FixedArray* array = FixedArray::cast(feedback);
- // The array should be of the form [<optional name>], then
- // [map, handler, map, handler, ... ]. Be sure to skip handlers whose maps
- // have been cleared.
- DCHECK(array->length() >= (2 + start_index));
- for (int i = start_index; i < array->length(); i += 2) {
+ // The array should be of the form [map, handler, map, handler, ... ].
+ // Be sure to skip handlers whose maps have been cleared.
+ DCHECK(array->length() >= 2);
+ for (int i = 0; i < array->length(); i += 2) {
WeakCell* cell = WeakCell::cast(array->get(i));
if (!cell->cleared()) {
Code* code = Code::cast(array->get(i + 1));
count++;
}
}
+ } else if (feedback->IsWeakCell()) {
+ WeakCell* cell = WeakCell::cast(feedback);
+ if (!cell->cleared()) {
+ Code* code = Code::cast(GetFeedbackExtra());
+ DCHECK(code->kind() == Code::HANDLER);
+ code_list->Add(handle(code));
+ count++;
+ }
}
return count == length;
}
-int LoadICNexus::ExtractMaps(MapHandleList* maps) const {
- return FeedbackNexus::ExtractMaps(0, maps);
-}
-
-
void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
}
-int KeyedLoadICNexus::ExtractMaps(MapHandleList* maps) const {
- return FeedbackNexus::ExtractMaps(1, maps);
-}
-
-
-MaybeHandle<Code> LoadICNexus::FindHandlerForMap(Handle<Map> map) const {
- return FeedbackNexus::FindHandlerForMap(0, map);
-}
-
-
-MaybeHandle<Code> KeyedLoadICNexus::FindHandlerForMap(Handle<Map> map) const {
- return FeedbackNexus::FindHandlerForMap(1, map);
-}
-
-
-bool LoadICNexus::FindHandlers(CodeHandleList* code_list, int length) const {
- return FeedbackNexus::FindHandlers(0, code_list, length);
-}
-
-
-bool KeyedLoadICNexus::FindHandlers(CodeHandleList* code_list,
- int length) const {
- return FeedbackNexus::FindHandlers(1, code_list, length);
-}
-
-
Name* KeyedLoadICNexus::FindFirstName() const {
Object* feedback = GetFeedback();
- if (feedback->IsFixedArray()) {
- FixedArray* array = FixedArray::cast(feedback);
- DCHECK(array->length() >= 3);
- Object* name = array->get(0);
- if (name->IsName()) return Name::cast(name);
+ if (feedback->IsString()) {
+ return Name::cast(feedback);
}
return NULL;
}
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();
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
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
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)); }
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(); }
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
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;
};
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;
};
}
#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"
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, ¬_array);
+ HandleArrayCases(masm, receiver, name, vector, slot, feedback, integer_slot,
+ r9, r11, r15, true, &miss);
+
+ __ bind(¬_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, ¬_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(¬_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);
}
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());
}