Try avoiding MISS for callic monomorphic case.

BUG=
R=bmeurer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#25207}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25207 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 47ee0b02
...@@ -2686,6 +2686,10 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) { ...@@ -2686,6 +2686,10 @@ void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
void CallICStub::Generate(MacroAssembler* masm) { void CallICStub::Generate(MacroAssembler* masm) {
// r1 - function // r1 - function
// r3 - slot id (Smi) // r3 - slot id (Smi)
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, slow_start; Label extra_checks_or_miss, slow_start;
Label slow, non_function, wrap, cont; Label slow, non_function, wrap, cont;
Label have_js_function; Label have_js_function;
...@@ -2724,37 +2728,70 @@ void CallICStub::Generate(MacroAssembler* masm) { ...@@ -2724,37 +2728,70 @@ void CallICStub::Generate(MacroAssembler* masm) {
} }
__ bind(&extra_checks_or_miss); __ bind(&extra_checks_or_miss);
Label miss; Label uninitialized, miss;
__ CompareRoot(r4, Heap::kmegamorphic_symbolRootIndex); __ CompareRoot(r4, Heap::kmegamorphic_symbolRootIndex);
__ b(eq, &slow_start); __ b(eq, &slow_start);
// The following cases attempt to handle MISS cases without going to the
// runtime.
if (FLAG_trace_ic) {
__ jmp(&miss);
}
__ CompareRoot(r4, Heap::kuninitialized_symbolRootIndex); __ CompareRoot(r4, Heap::kuninitialized_symbolRootIndex);
__ b(eq, &uninitialized);
// We are going megamorphic. If the feedback is a JSFunction, it is fine
// to handle it here. More complex cases are dealt with in the runtime.
__ AssertNotSmi(r4);
__ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
__ b(ne, &miss);
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
__ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex);
__ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
// We have to update statistics for runtime profiling.
__ ldr(r4, FieldMemOperand(r2, with_types_offset));
__ sub(r4, r4, Operand(Smi::FromInt(1)));
__ str(r4, FieldMemOperand(r2, with_types_offset));
__ ldr(r4, FieldMemOperand(r2, generic_offset));
__ add(r4, r4, Operand(Smi::FromInt(1)));
__ str(r4, FieldMemOperand(r2, generic_offset));
__ jmp(&slow_start);
__ bind(&uninitialized);
// We are going monomorphic, provided we actually have a JSFunction.
__ JumpIfSmi(r1, &miss);
// Goto miss case if we do not have a function.
__ CompareObjectType(r1, r4, r4, JS_FUNCTION_TYPE);
__ b(ne, &miss);
// Make sure the function is not the Array() function, which requires special
// behavior on MISS.
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r4);
__ cmp(r1, r4);
__ b(eq, &miss); __ b(eq, &miss);
if (!FLAG_trace_ic) { // Update stats.
// We are going megamorphic. If the feedback is a JSFunction, it is fine __ ldr(r4, FieldMemOperand(r2, with_types_offset));
// to handle it here. More complex cases are dealt with in the runtime. __ add(r4, r4, Operand(Smi::FromInt(1)));
__ AssertNotSmi(r4); __ str(r4, FieldMemOperand(r2, with_types_offset));
__ CompareObjectType(r4, r5, r5, JS_FUNCTION_TYPE);
__ b(ne, &miss); // Store the function.
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3)); __ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
__ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex); __ add(r4, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize)); __ str(r1, MemOperand(r4, 0));
// We have to update statistics for runtime profiling.
const int with_types_offset = // Update the write barrier.
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex); __ mov(r5, r1);
__ ldr(r4, FieldMemOperand(r2, with_types_offset)); __ RecordWrite(r2, r4, r5, kLRHasNotBeenSaved, kDontSaveFPRegs,
__ sub(r4, r4, Operand(Smi::FromInt(1))); EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ str(r4, FieldMemOperand(r2, with_types_offset)); __ jmp(&have_js_function);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
__ ldr(r4, FieldMemOperand(r2, generic_offset));
__ add(r4, r4, Operand(Smi::FromInt(1)));
__ str(r4, FieldMemOperand(r2, generic_offset));
__ jmp(&slow_start);
}
// We are here because tracing is on or we are going monomorphic. // We are here because tracing is on or we encountered a MISS case we can't
// handle here.
__ bind(&miss); __ bind(&miss);
GenerateMiss(masm); GenerateMiss(masm);
......
...@@ -3016,6 +3016,10 @@ void CallICStub::Generate(MacroAssembler* masm) { ...@@ -3016,6 +3016,10 @@ void CallICStub::Generate(MacroAssembler* masm) {
// x1 - function // x1 - function
// x3 - slot id (Smi) // x3 - slot id (Smi)
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, slow_start; Label extra_checks_or_miss, slow_start;
Label slow, non_function, wrap, cont; Label slow, non_function, wrap, cont;
Label have_js_function; Label have_js_function;
...@@ -3064,35 +3068,72 @@ void CallICStub::Generate(MacroAssembler* masm) { ...@@ -3064,35 +3068,72 @@ void CallICStub::Generate(MacroAssembler* masm) {
} }
__ bind(&extra_checks_or_miss); __ bind(&extra_checks_or_miss);
Label miss; Label uninitialized, miss;
__ JumpIfRoot(x4, Heap::kmegamorphic_symbolRootIndex, &slow_start); __ JumpIfRoot(x4, Heap::kmegamorphic_symbolRootIndex, &slow_start);
__ JumpIfRoot(x4, Heap::kuninitialized_symbolRootIndex, &miss);
if (!FLAG_trace_ic) { // The following cases attempt to handle MISS cases without going to the
// We are going megamorphic. If the feedback is a JSFunction, it is fine // runtime.
// to handle it here. More complex cases are dealt with in the runtime. if (FLAG_trace_ic) {
__ AssertNotSmi(x4); __ jmp(&miss);
__ JumpIfNotObjectType(x4, x5, x5, JS_FUNCTION_TYPE, &miss);
__ Add(x4, feedback_vector,
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
__ LoadRoot(x5, Heap::kmegamorphic_symbolRootIndex);
__ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize));
// We have to update statistics for runtime profiling.
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
__ Ldr(x4, FieldMemOperand(feedback_vector, with_types_offset));
__ Subs(x4, x4, Operand(Smi::FromInt(1)));
__ Str(x4, FieldMemOperand(feedback_vector, with_types_offset));
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
__ Ldr(x4, FieldMemOperand(feedback_vector, generic_offset));
__ Adds(x4, x4, Operand(Smi::FromInt(1)));
__ Str(x4, FieldMemOperand(feedback_vector, generic_offset));
__ B(&slow_start);
} }
// We are here because tracing is on or we are going monomorphic. __ JumpIfRoot(x4, Heap::kuninitialized_symbolRootIndex, &miss);
// We are going megamorphic. If the feedback is a JSFunction, it is fine
// to handle it here. More complex cases are dealt with in the runtime.
__ AssertNotSmi(x4);
__ JumpIfNotObjectType(x4, x5, x5, JS_FUNCTION_TYPE, &miss);
__ Add(x4, feedback_vector,
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
__ LoadRoot(x5, Heap::kmegamorphic_symbolRootIndex);
__ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize));
// We have to update statistics for runtime profiling.
__ Ldr(x4, FieldMemOperand(feedback_vector, with_types_offset));
__ Subs(x4, x4, Operand(Smi::FromInt(1)));
__ Str(x4, FieldMemOperand(feedback_vector, with_types_offset));
__ Ldr(x4, FieldMemOperand(feedback_vector, generic_offset));
__ Adds(x4, x4, Operand(Smi::FromInt(1)));
__ Str(x4, FieldMemOperand(feedback_vector, generic_offset));
__ B(&slow_start);
__ bind(&uninitialized);
// We are going monomorphic, provided we actually have a JSFunction.
__ JumpIfSmi(function, &miss);
// Goto miss case if we do not have a function.
__ JumpIfNotObjectType(function, x5, x5, JS_FUNCTION_TYPE, &miss);
// Make sure the function is not the Array() function, which requires special
// behavior on MISS.
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, x5);
__ Cmp(function, x5);
__ B(eq, &miss);
// Update stats.
__ Ldr(x4, FieldMemOperand(feedback_vector, with_types_offset));
__ Adds(x4, x4, Operand(Smi::FromInt(1)));
__ Str(x4, FieldMemOperand(feedback_vector, with_types_offset));
// Store the function.
__ Add(x4, feedback_vector,
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
__ Str(function, FieldMemOperand(x4, FixedArray::kHeaderSize));
__ Add(x4, feedback_vector,
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
__ Add(x4, x4, FixedArray::kHeaderSize - kHeapObjectTag);
__ Str(function, MemOperand(x4, 0));
// Update the write barrier.
__ Mov(x5, function);
__ RecordWrite(feedback_vector, x4, x5, kLRHasNotBeenSaved, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
__ B(&have_js_function);
// We are here because tracing is on or we encountered a MISS case we can't
// handle here.
__ bind(&miss); __ bind(&miss);
GenerateMiss(masm); GenerateMiss(masm);
......
...@@ -2214,6 +2214,10 @@ void CallICStub::Generate(MacroAssembler* masm) { ...@@ -2214,6 +2214,10 @@ void CallICStub::Generate(MacroAssembler* masm) {
// edi - function // edi - function
// edx - slot id // edx - slot id
Isolate* isolate = masm->isolate(); Isolate* isolate = masm->isolate();
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, slow_start; Label extra_checks_or_miss, slow_start;
Label slow, non_function, wrap, cont; Label slow, non_function, wrap, cont;
Label have_js_function; Label have_js_function;
...@@ -2253,35 +2257,66 @@ void CallICStub::Generate(MacroAssembler* masm) { ...@@ -2253,35 +2257,66 @@ void CallICStub::Generate(MacroAssembler* masm) {
} }
__ bind(&extra_checks_or_miss); __ bind(&extra_checks_or_miss);
Label miss; Label uninitialized, miss;
__ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size, __ mov(ecx, FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize)); FixedArray::kHeaderSize));
__ cmp(ecx, Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate))); __ cmp(ecx, Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
__ j(equal, &slow_start); __ j(equal, &slow_start);
// The following cases attempt to handle MISS cases without going to the
// runtime.
if (FLAG_trace_ic) {
__ jmp(&miss);
}
__ cmp(ecx, Immediate(TypeFeedbackVector::UninitializedSentinel(isolate))); __ cmp(ecx, Immediate(TypeFeedbackVector::UninitializedSentinel(isolate)));
__ j(equal, &uninitialized);
// We are going megamorphic. If the feedback is a JSFunction, it is fine
// to handle it here. More complex cases are dealt with in the runtime.
__ AssertNotSmi(ecx);
__ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx);
__ j(not_equal, &miss);
__ mov(
FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize),
Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
// We have to update statistics for runtime profiling.
__ sub(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
__ add(FieldOperand(ebx, generic_offset), Immediate(Smi::FromInt(1)));
__ jmp(&slow_start);
__ bind(&uninitialized);
// We are going monomorphic, provided we actually have a JSFunction.
__ JumpIfSmi(edi, &miss);
// Goto miss case if we do not have a function.
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
__ j(not_equal, &miss);
// Make sure the function is not the Array() function, which requires special
// behavior on MISS.
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx);
__ cmp(edi, ecx);
__ j(equal, &miss); __ j(equal, &miss);
if (!FLAG_trace_ic) { // Update stats.
// We are going megamorphic. If the feedback is a JSFunction, it is fine __ add(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
// to handle it here. More complex cases are dealt with in the runtime.
__ AssertNotSmi(ecx); // Store the function.
__ CmpObjectType(ecx, JS_FUNCTION_TYPE, ecx); __ mov(
__ j(not_equal, &miss); FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize),
__ mov(FieldOperand(ebx, edx, times_half_pointer_size, edi);
FixedArray::kHeaderSize),
Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate))); // Update the write barrier.
// We have to update statistics for runtime profiling. __ mov(eax, edi);
const int with_types_offset = __ RecordWriteArray(ebx, eax, edx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex); OMIT_SMI_CHECK);
__ sub(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1))); __ jmp(&have_js_function);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
__ add(FieldOperand(ebx, generic_offset), Immediate(Smi::FromInt(1)));
__ jmp(&slow_start);
}
// We are here because tracing is on or we are going monomorphic. // We are here because tracing is on or we encountered a MISS case we can't
// handle here.
__ bind(&miss); __ bind(&miss);
GenerateMiss(masm); GenerateMiss(masm);
......
...@@ -2087,6 +2087,10 @@ void CallICStub::Generate(MacroAssembler* masm) { ...@@ -2087,6 +2087,10 @@ void CallICStub::Generate(MacroAssembler* masm) {
// rdi - function // rdi - function
// rdx - slot id // rdx - slot id
Isolate* isolate = masm->isolate(); Isolate* isolate = masm->isolate();
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, slow_start; Label extra_checks_or_miss, slow_start;
Label slow, non_function, wrap, cont; Label slow, non_function, wrap, cont;
Label have_js_function; Label have_js_function;
...@@ -2128,34 +2132,64 @@ void CallICStub::Generate(MacroAssembler* masm) { ...@@ -2128,34 +2132,64 @@ void CallICStub::Generate(MacroAssembler* masm) {
} }
__ bind(&extra_checks_or_miss); __ bind(&extra_checks_or_miss);
Label miss; Label uninitialized, miss;
__ movp(rcx, FieldOperand(rbx, rdx, times_pointer_size, __ movp(rcx, FieldOperand(rbx, rdx, times_pointer_size,
FixedArray::kHeaderSize)); FixedArray::kHeaderSize));
__ Cmp(rcx, TypeFeedbackVector::MegamorphicSentinel(isolate)); __ Cmp(rcx, TypeFeedbackVector::MegamorphicSentinel(isolate));
__ j(equal, &slow_start); __ j(equal, &slow_start);
// The following cases attempt to handle MISS cases without going to the
// runtime.
if (FLAG_trace_ic) {
__ jmp(&miss);
}
__ Cmp(rcx, TypeFeedbackVector::UninitializedSentinel(isolate)); __ Cmp(rcx, TypeFeedbackVector::UninitializedSentinel(isolate));
__ j(equal, &uninitialized);
// We are going megamorphic. If the feedback is a JSFunction, it is fine
// to handle it here. More complex cases are dealt with in the runtime.
__ AssertNotSmi(rcx);
__ CmpObjectType(rcx, JS_FUNCTION_TYPE, rcx);
__ j(not_equal, &miss);
__ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
TypeFeedbackVector::MegamorphicSentinel(isolate));
// We have to update statistics for runtime profiling.
__ SmiAddConstant(FieldOperand(rbx, with_types_offset), Smi::FromInt(-1));
__ SmiAddConstant(FieldOperand(rbx, generic_offset), Smi::FromInt(1));
__ jmp(&slow_start);
__ bind(&uninitialized);
// We are going monomorphic, provided we actually have a JSFunction.
__ JumpIfSmi(rdi, &miss);
// Goto miss case if we do not have a function.
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
__ j(not_equal, &miss);
// Make sure the function is not the Array() function, which requires special
// behavior on MISS.
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, rcx);
__ cmpp(rdi, rcx);
__ j(equal, &miss); __ j(equal, &miss);
if (!FLAG_trace_ic) { // Update stats.
// We are going megamorphic. If the feedback is a JSFunction, it is fine __ SmiAddConstant(FieldOperand(rbx, with_types_offset), Smi::FromInt(1));
// to handle it here. More complex cases are dealt with in the runtime.
__ AssertNotSmi(rcx); // Store the function.
__ CmpObjectType(rcx, JS_FUNCTION_TYPE, rcx); __ movp(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
__ j(not_equal, &miss); rdi);
__ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
TypeFeedbackVector::MegamorphicSentinel(isolate)); // Update the write barrier.
// We have to update statistics for runtime profiling. __ movp(rax, rdi);
const int with_types_offset = __ RecordWriteArray(rbx, rax, rdx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex); OMIT_SMI_CHECK);
__ SmiAddConstant(FieldOperand(rbx, with_types_offset), Smi::FromInt(-1)); __ jmp(&have_js_function);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
__ SmiAddConstant(FieldOperand(rbx, generic_offset), Smi::FromInt(1));
__ jmp(&slow_start);
}
// We are here because tracing is on or we are going monomorphic. // We are here because tracing is on or we encountered a MISS case we can't
// handle here.
__ bind(&miss); __ bind(&miss);
GenerateMiss(masm); GenerateMiss(masm);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment