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}
This commit is contained in:
mvstanton 2015-03-17 04:28:09 -07:00 committed by Commit bot
parent d74f5c6f09
commit 34a1a76ddf
13 changed files with 1581 additions and 395 deletions

View File

@ -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"
@ -4323,15 +4324,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
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);
}
@ -4349,6 +4350,239 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* 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, &not_array);
HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, r8,
r9, true, &miss);
__ bind(&not_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, &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, scratch1, r8,
r9, true, &miss);
__ bind(&not_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());

View File

@ -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"
@ -4451,15 +4452,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
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);
}
@ -4477,6 +4478,236 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* 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, &not_array);
HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, x6,
x7, true, &miss);
__ Bind(&not_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, &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, scratch1, x6,
x7, true, &miss);
__ Bind(&not_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 =

View File

@ -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);
}

View File

@ -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) {}

View File

@ -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; }
virtual ExtraICState GetExtraICState() const FINAL OVERRIDE {
return static_cast<ExtraICState>(minor_key_);
}
private:
LoadICState state() const { return LoadICState(GetExtraICState()); }
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);
};

View File

@ -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);
}

View File

@ -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:

View File

@ -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"
@ -4554,15 +4555,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
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);
}
@ -4580,6 +4581,243 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* 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(&not_array, ne, at, Operand(scratch1));
HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, t4,
t5, true, &miss);
__ bind(&not_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(&not_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(&not_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());

View File

@ -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"
@ -4597,15 +4598,15 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
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);
}
@ -4623,6 +4624,243 @@ void CallIC_ArrayTrampolineStub::Generate(MacroAssembler* 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(&not_array, ne, scratch1, Operand(at));
HandleArrayCases(masm, receiver, name, vector, slot, feedback, scratch1, a6,
a7, true, &miss);
__ bind(&not_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(&not_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(&not_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());

View File

@ -82,8 +82,8 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(
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());
@ -207,16 +207,28 @@ Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
}
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));
}
}
@ -224,6 +236,7 @@ void FeedbackNexus::InstallHandlers(int start_index, MapHandleList* maps,
InlineCacheState LoadICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
if (feedback == *vector()->UninitializedSentinel(isolate)) {
return UNINITIALIZED;
} else if (feedback == *vector()->MegamorphicSentinel(isolate)) {
@ -233,10 +246,10 @@ InlineCacheState LoadICNexus::StateFromFeedback() const {
} 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;
@ -246,6 +259,7 @@ InlineCacheState LoadICNexus::StateFromFeedback() const {
InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
if (feedback == *vector()->UninitializedSentinel(isolate)) {
return UNINITIALIZED;
} else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
@ -255,10 +269,14 @@ InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
} 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;
@ -268,6 +286,8 @@ InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
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;
@ -311,56 +331,68 @@ void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
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);
if (name.is_null()) {
array->set(0, Smi::FromInt(0));
} else {
array->set(0, *name);
}
Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
array->set(1, *cell);
array->set(2, *handler);
if (name.is_null()) {
SetFeedback(*cell);
SetFeedbackExtra(*handler);
} else {
SetFeedback(*name);
Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
array->set(0, *cell);
array->set(1, *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);
}
@ -368,26 +400,34 @@ void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
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());
@ -396,18 +436,27 @@ int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
}
}
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());
@ -418,23 +467,34 @@ MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index,
}
}
}
} 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));
@ -443,16 +503,19 @@ bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
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); }
@ -461,39 +524,10 @@ void KeyedLoadICNexus::Clear(Code* host) {
}
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;
}

View File

@ -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;
};
}

View File

@ -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);
}

View File

@ -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());
}