Commit 2ab3fcf4 authored by mvstanton's avatar mvstanton Committed by Commit bot

Record call counts also for megamorphic calls.

To make better inlining decisions, it's good to have call counts for poly/mega-morphic cases. This CL makes it work for calls, and another will follow to better unify the code between constructor calls and normal calls (and thence, to record megamorphic call counts there as well).

BUG=

Review-Url: https://codereview.chromium.org/2325083003
Cr-Commit-Position: refs/heads/master@{#39377}
parent 6b000846
......@@ -1785,6 +1785,17 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
// Note: feedback_vector and slot are clobbered after the call.
static void IncrementCallCount(MacroAssembler* masm, Register feedback_vector,
Register slot) {
__ add(feedback_vector, feedback_vector,
Operand::PointerOffsetFromSmiKey(slot));
__ add(feedback_vector, feedback_vector,
Operand(FixedArray::kHeaderSize + kPointerSize));
__ ldr(slot, FieldMemOperand(feedback_vector, 0));
__ add(slot, slot, Operand(Smi::FromInt(1)));
__ str(slot, FieldMemOperand(feedback_vector, 0));
}
void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// r1 - function
......@@ -1798,11 +1809,7 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ mov(r0, Operand(arg_count()));
// Increment the call count for monomorphic function calls.
__ add(r2, r2, Operand::PointerOffsetFromSmiKey(r3));
__ add(r2, r2, Operand(FixedArray::kHeaderSize + kPointerSize));
__ ldr(r3, FieldMemOperand(r2, 0));
__ add(r3, r3, Operand(Smi::FromInt(1)));
__ str(r3, FieldMemOperand(r2, 0));
IncrementCallCount(masm, r2, r3);
__ mov(r2, r4);
__ mov(r3, r1);
......@@ -1815,7 +1822,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
// r1 - function
// r3 - slot id (Smi)
// r2 - vector
Label extra_checks_or_miss, call, call_function;
Label extra_checks_or_miss, call, call_function, call_count_incremented;
int argc = arg_count();
ParameterCount actual(argc);
......@@ -1845,14 +1852,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
// convincing us that we have a monomorphic JSFunction.
__ JumpIfSmi(r1, &extra_checks_or_miss);
__ bind(&call_function);
// Increment the call count for monomorphic function calls.
__ add(r2, r2, Operand::PointerOffsetFromSmiKey(r3));
__ add(r2, r2, Operand(FixedArray::kHeaderSize + kPointerSize));
__ ldr(r3, FieldMemOperand(r2, 0));
__ add(r3, r3, Operand(Smi::FromInt(1)));
__ str(r3, FieldMemOperand(r2, 0));
IncrementCallCount(masm, r2, r3);
__ bind(&call_function);
__ mov(r0, Operand(argc));
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
......@@ -1893,6 +1897,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
__ bind(&call);
// Increment the call count for megamorphic function calls.
IncrementCallCount(masm, r2, r3);
__ bind(&call_count_incremented);
__ mov(r0, Operand(argc));
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET);
......@@ -1919,11 +1928,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ cmp(r4, ip);
__ b(ne, &miss);
// Initialize the call counter.
__ Move(r5, Operand(Smi::FromInt(1)));
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
__ str(r5, FieldMemOperand(r4, FixedArray::kHeaderSize + kPointerSize));
// Store the function. Use a stub since we need a frame for allocation.
// r2 - vector
// r3 - slot
......@@ -1931,9 +1935,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(masm->isolate());
__ Push(r2);
__ Push(r3);
__ Push(cp, r1);
__ CallStub(&create_stub);
__ Pop(cp, r1);
__ Pop(r3);
__ Pop(r2);
}
__ jmp(&call_function);
......@@ -1943,7 +1951,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&miss);
GenerateMiss(masm);
__ jmp(&call);
__ jmp(&call_count_incremented);
}
......
......@@ -1995,6 +1995,17 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
// Note: feedback_vector and slot are clobbered after the call.
static void IncrementCallCount(MacroAssembler* masm, Register feedback_vector,
Register slot) {
__ Add(feedback_vector, feedback_vector,
Operand::UntagSmiAndScale(slot, kPointerSizeLog2));
__ Add(feedback_vector, feedback_vector,
Operand(FixedArray::kHeaderSize + kPointerSize));
__ Ldr(slot, FieldMemOperand(feedback_vector, 0));
__ Add(slot, slot, Operand(Smi::FromInt(1)));
__ Str(slot, FieldMemOperand(feedback_vector, 0));
}
void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// x1 - function
......@@ -2014,13 +2025,7 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ Mov(x0, Operand(arg_count()));
// Increment the call count for monomorphic function calls.
__ Add(feedback_vector, feedback_vector,
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
__ Add(feedback_vector, feedback_vector,
Operand(FixedArray::kHeaderSize + kPointerSize));
__ Ldr(index, FieldMemOperand(feedback_vector, 0));
__ Add(index, index, Operand(Smi::FromInt(1)));
__ Str(index, FieldMemOperand(feedback_vector, 0));
IncrementCallCount(masm, feedback_vector, index);
// Set up arguments for the array constructor stub.
Register allocation_site_arg = feedback_vector;
......@@ -2038,7 +2043,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
// x1 - function
// x3 - slot id (Smi)
// x2 - vector
Label extra_checks_or_miss, call, call_function;
Label extra_checks_or_miss, call, call_function, call_count_incremented;
int argc = arg_count();
ParameterCount actual(argc);
......@@ -2073,16 +2078,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
// convincing us that we have a monomorphic JSFunction.
__ JumpIfSmi(function, &extra_checks_or_miss);
__ Bind(&call_function);
// Increment the call count for monomorphic function calls.
__ Add(feedback_vector, feedback_vector,
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
__ Add(feedback_vector, feedback_vector,
Operand(FixedArray::kHeaderSize + kPointerSize));
__ Ldr(index, FieldMemOperand(feedback_vector, 0));
__ Add(index, index, Operand(Smi::FromInt(1)));
__ Str(index, FieldMemOperand(feedback_vector, 0));
IncrementCallCount(masm, feedback_vector, index);
__ Bind(&call_function);
__ Mov(x0, argc);
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
......@@ -2106,6 +2106,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ jmp(&miss);
}
// TODO(mvstanton): the code below is effectively disabled. Investigate.
__ JumpIfRoot(x4, Heap::kuninitialized_symbolRootIndex, &miss);
// We are going megamorphic. If the feedback is a JSFunction, it is fine
......@@ -2118,6 +2119,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize));
__ Bind(&call);
// Increment the call count for megamorphic function calls.
IncrementCallCount(masm, feedback_vector, index);
__ Bind(&call_count_incremented);
__ Mov(x0, argc);
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET);
......@@ -2143,12 +2149,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ Cmp(x4, x5);
__ B(ne, &miss);
// Initialize the call counter.
__ Mov(x5, Smi::FromInt(1));
__ Adds(x4, feedback_vector,
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
__ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize + kPointerSize));
// Store the function. Use a stub since we need a frame for allocation.
// x2 - vector
// x3 - slot
......@@ -2156,9 +2156,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(masm->isolate());
__ Push(feedback_vector, index);
__ Push(cp, function);
__ CallStub(&create_stub);
__ Pop(cp, function);
__ Pop(feedback_vector, index);
}
__ B(&call_function);
......@@ -2168,7 +2172,8 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&miss);
GenerateMiss(masm);
__ B(&call);
// The runtime increments the call count in the vector for us.
__ B(&call_count_incremented);
}
......
......@@ -1431,6 +1431,12 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
static void IncrementCallCount(MacroAssembler* masm, Register feedback_vector,
Register slot) {
__ add(FieldOperand(feedback_vector, slot, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize),
Immediate(Smi::FromInt(1)));
}
void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// edi - function
......@@ -1446,9 +1452,7 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
FixedArray::kHeaderSize));
// Increment the call count for monomorphic function calls.
__ add(FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize),
Immediate(Smi::FromInt(1)));
IncrementCallCount(masm, ebx, edx);
__ mov(ebx, ecx);
__ mov(edx, edi);
......@@ -1464,7 +1468,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
// edx - slot id
// ebx - vector
Isolate* isolate = masm->isolate();
Label extra_checks_or_miss, call, call_function;
Label extra_checks_or_miss, call, call_function, call_count_incremented;
int argc = arg_count();
ParameterCount actual(argc);
......@@ -1493,12 +1497,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
// convincing us that we have a monomorphic JSFunction.
__ JumpIfSmi(edi, &extra_checks_or_miss);
__ bind(&call_function);
// Increment the call count for monomorphic function calls.
__ add(FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize),
Immediate(Smi::FromInt(1)));
IncrementCallCount(masm, ebx, edx);
__ bind(&call_function);
__ Set(eax, argc);
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
......@@ -1539,6 +1542,12 @@ void CallICStub::Generate(MacroAssembler* masm) {
Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
__ bind(&call);
// Increment the call count for megamorphic function calls.
IncrementCallCount(masm, ebx, edx);
__ bind(&call_count_incremented);
__ Set(eax, argc);
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET);
......@@ -1564,11 +1573,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ cmp(ecx, NativeContextOperand());
__ j(not_equal, &miss);
// Initialize the call counter.
__ mov(FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize),
Immediate(Smi::FromInt(1)));
// Store the function. Use a stub since we need a frame for allocation.
// ebx - vector
// edx - slot
......@@ -1576,11 +1580,15 @@ void CallICStub::Generate(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(isolate);
__ push(ebx);
__ push(edx);
__ push(edi);
__ push(esi);
__ CallStub(&create_stub);
__ pop(esi);
__ pop(edi);
__ pop(edx);
__ pop(ebx);
}
__ jmp(&call_function);
......@@ -1590,7 +1598,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&miss);
GenerateMiss(masm);
__ jmp(&call);
__ jmp(&call_count_incremented);
// Unreachable
__ int3();
......
......@@ -460,6 +460,17 @@ void InterpreterAssembler::CallEpilogue() {
}
}
Node* InterpreterAssembler::IncrementCallCount(Node* type_feedback_vector,
Node* slot_id) {
Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
Node* call_count =
LoadFixedArrayElement(type_feedback_vector, call_count_slot);
Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1)));
// Count is Smi, so we don't need a write barrier.
return StoreFixedArrayElement(type_feedback_vector, call_count_slot,
new_count, SKIP_WRITE_BARRIER);
}
Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Node* first_arg, Node* arg_count,
Node* slot_id,
......@@ -482,13 +493,13 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Variable return_value(this, MachineRepresentation::kTagged);
Label handle_monomorphic(this), extra_checks(this), end(this), call(this),
call_function(this);
call_function(this), call_without_feedback(this);
// Slot id of 0 is used to indicate no typefeedback is available. Call using
// call builtin.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0));
GotoIf(is_feedback_unavailable, &call);
GotoIf(is_feedback_unavailable, &call_without_feedback);
// The checks. First, does function match the recorded monomorphic target?
Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id);
......@@ -504,13 +515,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
GotoIf(is_smi, &extra_checks);
// Increment the call count.
Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
Node* call_count =
LoadFixedArrayElement(type_feedback_vector, call_count_slot);
Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1)));
// Count is Smi, so we don't need a write barrier.
StoreFixedArrayElement(type_feedback_vector, call_count_slot, new_count,
SKIP_WRITE_BARRIER);
IncrementCallCount(type_feedback_vector, slot_id);
// Call using call function builtin.
Callable callable = CodeFactory::InterpreterPushArgsAndCall(
......@@ -548,13 +553,7 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
GotoUnless(is_array_function, &mark_megamorphic);
// It is a monomorphic Array function. Increment the call count.
Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
Node* call_count =
LoadFixedArrayElement(type_feedback_vector, call_count_slot);
Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1)));
// Count is Smi, so we don't need a write barrier.
StoreFixedArrayElement(type_feedback_vector, call_count_slot, new_count,
SKIP_WRITE_BARRIER);
IncrementCallCount(type_feedback_vector, slot_id);
// Call ArrayConstructorStub.
Callable callable_call =
......@@ -599,12 +598,6 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
WordEqual(native_context, LoadNativeContext(context));
GotoUnless(is_same_native_context, &mark_megamorphic);
// Initialize it to a monomorphic target.
Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
// Count is Smi, so we don't need a write barrier.
StoreFixedArrayElement(type_feedback_vector, call_count_slot,
SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER);
CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id),
function);
......@@ -620,12 +613,6 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
HeapConstant(create_stub.GetCode()), context,
type_feedback_vector, SmiTag(slot_id));
// Initialize the count to 1.
Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1));
// Count is Smi, so we don't need a write barrier.
StoreFixedArrayElement(type_feedback_vector, call_count_slot,
SmiTag(Int32Constant(1)), SKIP_WRITE_BARRIER);
// Call using CallFunction builtin. CallICs have a PREMONOMORPHIC state.
// They start collecting feedback only when a call is executed the second
// time. So, do not pass any feedback here.
......@@ -648,6 +635,9 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Bind(&call_function);
{
// Increment the call count.
IncrementCallCount(type_feedback_vector, slot_id);
Callable callable_call = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kJSFunction);
Node* code_target_call = HeapConstant(callable_call.code());
......@@ -658,6 +648,21 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
}
Bind(&call);
{
// Increment the call count.
IncrementCallCount(type_feedback_vector, slot_id);
// Call using call builtin.
Callable callable_call = CodeFactory::InterpreterPushArgsAndCall(
isolate(), tail_call_mode, CallableType::kAny);
Node* code_target_call = HeapConstant(callable_call.code());
Node* ret_value = CallStub(callable_call.descriptor(), code_target_call,
context, arg_count, first_arg, function);
return_value.Bind(ret_value);
Goto(&end);
}
Bind(&call_without_feedback);
{
// Call using call builtin.
Callable callable_call = CodeFactory::InterpreterPushArgsAndCall(
......
......@@ -92,6 +92,11 @@ class InterpreterAssembler : public CodeStubAssembler {
// Load the TypeFeedbackVector for the current function.
compiler::Node* LoadTypeFeedbackVector();
// Increment the call count for a CALL_IC or construct call.
// The call count is located at feedback_vector[slot_id + 1].
compiler::Node* IncrementCallCount(compiler::Node* type_feedback_vector,
compiler::Node* slot_id);
// Call JSFunction or Callable |function| with |arg_count|
// arguments (not including receiver) and the first argument
// located at |first_arg|. Type feedback is collected in the
......
......@@ -1917,6 +1917,14 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
// Note: feedback_vector and slot are clobbered after the call.
static void IncrementCallCount(MacroAssembler* masm, Register feedback_vector,
Register slot) {
__ Lsa(at, feedback_vector, slot, kPointerSizeLog2 - kSmiTagSize);
__ lw(slot, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
__ Addu(slot, slot, Operand(Smi::FromInt(1)));
__ sw(slot, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
}
void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// a1 - function
......@@ -1929,10 +1937,7 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ li(a0, Operand(arg_count()));
// Increment the call count for monomorphic function calls.
__ Lsa(at, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ lw(a3, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
__ Addu(a3, a3, Operand(Smi::FromInt(1)));
__ sw(a3, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
IncrementCallCount(masm, a2, a3);
__ mov(a2, t0);
__ mov(a3, a1);
......@@ -1945,7 +1950,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
// a1 - function
// a3 - slot id (Smi)
// a2 - vector
Label extra_checks_or_miss, call, call_function;
Label extra_checks_or_miss, call, call_function, call_count_incremented;
int argc = arg_count();
ParameterCount actual(argc);
......@@ -1974,13 +1979,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
// convincing us that we have a monomorphic JSFunction.
__ JumpIfSmi(a1, &extra_checks_or_miss);
__ bind(&call_function);
// Increment the call count for monomorphic function calls.
__ Lsa(at, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ lw(a3, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
__ Addu(a3, a3, Operand(Smi::FromInt(1)));
__ sw(a3, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
IncrementCallCount(masm, a2, a3);
__ bind(&call_function);
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg),
......@@ -2021,6 +2024,10 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize));
__ bind(&call);
IncrementCallCount(masm, a2, a3);
__ bind(&call_count_incremented);
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg),
USE_DELAY_SLOT);
......@@ -2046,11 +2053,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ lw(t1, NativeContextMemOperand());
__ Branch(&miss, ne, t0, Operand(t1));
// Initialize the call counter.
__ Lsa(at, a2, a3, kPointerSizeLog2 - kSmiTagSize);
__ li(t0, Operand(Smi::FromInt(1)));
__ sw(t0, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
// Store the function. Use a stub since we need a frame for allocation.
// a2 - vector
// a3 - slot
......@@ -2058,9 +2060,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(masm->isolate());
__ Push(a2, a3);
__ Push(cp, a1);
__ CallStub(&create_stub);
__ Pop(cp, a1);
__ Pop(a2, a3);
}
__ Branch(&call_function);
......@@ -2070,7 +2074,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&miss);
GenerateMiss(masm);
__ Branch(&call);
__ Branch(&call_count_incremented);
}
......
......@@ -1965,6 +1965,15 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
__ bind(&exit_);
}
// Note: feedback_vector and slot are clobbered after the call.
static void IncrementCallCount(MacroAssembler* masm, Register feedback_vector,
Register slot) {
__ dsrl(t0, slot, 32 - kPointerSizeLog2);
__ Daddu(slot, feedback_vector, Operand(t0));
__ ld(t0, FieldMemOperand(slot, FixedArray::kHeaderSize + kPointerSize));
__ Daddu(t0, t0, Operand(Smi::FromInt(1)));
__ sd(t0, FieldMemOperand(slot, FixedArray::kHeaderSize + kPointerSize));
}
void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// a1 - function
......@@ -1977,11 +1986,7 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ li(a0, Operand(arg_count()));
// Increment the call count for monomorphic function calls.
__ dsrl(t0, a3, 32 - kPointerSizeLog2);
__ Daddu(a3, a2, Operand(t0));
__ ld(t0, FieldMemOperand(a3, FixedArray::kHeaderSize + kPointerSize));
__ Daddu(t0, t0, Operand(Smi::FromInt(1)));
__ sd(t0, FieldMemOperand(a3, FixedArray::kHeaderSize + kPointerSize));
IncrementCallCount(masm, a2, a3);
__ mov(a2, a4);
__ mov(a3, a1);
......@@ -1994,7 +1999,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
// a1 - function
// a3 - slot id (Smi)
// a2 - vector
Label extra_checks_or_miss, call, call_function;
Label extra_checks_or_miss, call, call_function, call_count_incremented;
int argc = arg_count();
ParameterCount actual(argc);
......@@ -2024,14 +2029,10 @@ void CallICStub::Generate(MacroAssembler* masm) {
// convincing us that we have a monomorphic JSFunction.
__ JumpIfSmi(a1, &extra_checks_or_miss);
__ bind(&call_function);
// Increment the call count for monomorphic function calls.
__ dsrl(t0, a3, 32 - kPointerSizeLog2);
__ Daddu(a3, a2, Operand(t0));
__ ld(t0, FieldMemOperand(a3, FixedArray::kHeaderSize + kPointerSize));
__ Daddu(t0, t0, Operand(Smi::FromInt(1)));
__ sd(t0, FieldMemOperand(a3, FixedArray::kHeaderSize + kPointerSize));
IncrementCallCount(masm, a2, a3);
__ bind(&call_function);
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg),
......@@ -2073,6 +2074,10 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ sd(at, FieldMemOperand(a4, FixedArray::kHeaderSize));
__ bind(&call);
IncrementCallCount(masm, a2, a3);
__ bind(&call_count_incremented);
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg),
USE_DELAY_SLOT);
......@@ -2098,12 +2103,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ ld(t1, NativeContextMemOperand());
__ Branch(&miss, ne, t0, Operand(t1));
// Initialize the call counter.
__ dsrl(at, a3, 32 - kPointerSizeLog2);
__ Daddu(at, a2, Operand(at));
__ li(t0, Operand(Smi::FromInt(1)));
__ sd(t0, FieldMemOperand(at, FixedArray::kHeaderSize + kPointerSize));
// Store the function. Use a stub since we need a frame for allocation.
// a2 - vector
// a3 - slot
......@@ -2111,9 +2110,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
CreateWeakCellStub create_stub(masm->isolate());
__ Push(a2, a3);
__ Push(cp, a1);
__ CallStub(&create_stub);
__ Pop(cp, a1);
__ Pop(a2, a3);
}
__ Branch(&call_function);
......@@ -2123,7 +2124,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&miss);
GenerateMiss(masm);
__ Branch(&call);
__ Branch(&call_count_incremented);
}
......
......@@ -254,8 +254,11 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::New(
value = *uninitialized_sentinel;
}
array->set(index, value, SKIP_WRITE_BARRIER);
value = kind == FeedbackVectorSlotKind::CALL_IC ? Smi::FromInt(0)
: *uninitialized_sentinel;
for (int j = 1; j < entry_size; j++) {
array->set(index + j, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
array->set(index + j, value, SKIP_WRITE_BARRIER);
}
i += entry_size;
}
......@@ -620,16 +623,19 @@ InlineCacheState CallICNexus::StateFromFeedback() const {
int CallICNexus::ExtractCallCount() {
Object* call_count = GetFeedbackExtra();
if (call_count->IsSmi()) {
int value = Smi::cast(call_count)->value();
return value;
}
return -1;
CHECK(call_count->IsSmi());
int value = Smi::cast(call_count)->value();
return value;
}
void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); }
void CallICNexus::ConfigureUninitialized() {
Isolate* isolate = GetIsolate();
SetFeedback(*TypeFeedbackVector::UninitializedSentinel(isolate),
SKIP_WRITE_BARRIER);
SetFeedbackExtra(Smi::FromInt(0), SKIP_WRITE_BARRIER);
}
void CallICNexus::ConfigureMonomorphicArray() {
Object* feedback = GetFeedback();
......@@ -650,10 +656,13 @@ void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
void CallICNexus::ConfigureMegamorphic() {
FeedbackNexus::ConfigureMegamorphic();
SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(GetIsolate()),
SKIP_WRITE_BARRIER);
Smi* count = Smi::cast(GetFeedbackExtra());
int new_count = count->value() + 1;
SetFeedbackExtra(Smi::FromInt(new_count), SKIP_WRITE_BARRIER);
}
void CallICNexus::ConfigureMegamorphic(int call_count) {
SetFeedback(*TypeFeedbackVector::MegamorphicSentinel(GetIsolate()),
SKIP_WRITE_BARRIER);
......
......@@ -459,6 +459,7 @@ class CallICNexus final : public FeedbackNexus {
void Clear(Code* host);
void ConfigureUninitialized() override;
void ConfigureMonomorphicArray();
void ConfigureMonomorphic(Handle<JSFunction> function);
void ConfigureMegamorphic() final;
......
......@@ -1321,6 +1321,12 @@ void CallConstructStub::Generate(MacroAssembler* masm) {
__ Jump(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
}
static void IncrementCallCount(MacroAssembler* masm, Register feedback_vector,
Register slot) {
__ SmiAddConstant(FieldOperand(feedback_vector, slot, times_pointer_size,
FixedArray::kHeaderSize + kPointerSize),
Smi::FromInt(1));
}
void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
// rdi - function
......@@ -1334,9 +1340,7 @@ void CallICStub::HandleArrayCase(MacroAssembler* masm, Label* miss) {
__ movp(rax, Immediate(arg_count()));
// Increment the call count for monomorphic function calls.
__ SmiAddConstant(FieldOperand(rbx, rdx, times_pointer_size,
FixedArray::kHeaderSize + kPointerSize),
Smi::FromInt(1));
IncrementCallCount(masm, rbx, rdx);
__ movp(rbx, rcx);
__ movp(rdx, rdi);
......@@ -1352,7 +1356,7 @@ void CallICStub::Generate(MacroAssembler* masm) {
// -- rbx - vector
// -----------------------------------
Isolate* isolate = masm->isolate();
Label extra_checks_or_miss, call, call_function;
Label extra_checks_or_miss, call, call_function, call_count_incremented;
int argc = arg_count();
StackArgumentsAccessor args(rsp, argc);
ParameterCount actual(argc);
......@@ -1383,12 +1387,10 @@ void CallICStub::Generate(MacroAssembler* masm) {
// convincing us that we have a monomorphic JSFunction.
__ JumpIfSmi(rdi, &extra_checks_or_miss);
__ bind(&call_function);
// Increment the call count for monomorphic function calls.
__ SmiAddConstant(FieldOperand(rbx, rdx, times_pointer_size,
FixedArray::kHeaderSize + kPointerSize),
Smi::FromInt(1));
IncrementCallCount(masm, rbx, rdx);
__ bind(&call_function);
__ Set(rax, argc);
__ Jump(masm->isolate()->builtins()->CallFunction(convert_mode(),
tail_call_mode()),
......@@ -1428,6 +1430,11 @@ void CallICStub::Generate(MacroAssembler* masm) {
TypeFeedbackVector::MegamorphicSentinel(isolate));
__ bind(&call);
// Increment the call count for megamorphic function calls.
IncrementCallCount(masm, rbx, rdx);
__ bind(&call_count_incremented);
__ Set(rax, argc);
__ Jump(masm->isolate()->builtins()->Call(convert_mode(), tail_call_mode()),
RelocInfo::CODE_TARGET);
......@@ -1453,11 +1460,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ cmpp(rcx, NativeContextOperand());
__ j(not_equal, &miss);
// Initialize the call counter.
__ Move(FieldOperand(rbx, rdx, times_pointer_size,
FixedArray::kHeaderSize + kPointerSize),
Smi::FromInt(1));
// Store the function. Use a stub since we need a frame for allocation.
// rbx - vector
// rdx - slot (needs to be in smi form)
......@@ -1467,11 +1469,16 @@ void CallICStub::Generate(MacroAssembler* masm) {
CreateWeakCellStub create_stub(isolate);
__ Integer32ToSmi(rdx, rdx);
__ Push(rbx);
__ Push(rdx);
__ Push(rdi);
__ Push(rsi);
__ CallStub(&create_stub);
__ Pop(rsi);
__ Pop(rdi);
__ Pop(rdx);
__ Pop(rbx);
__ SmiToInteger32(rdx, rdx);
}
__ jmp(&call_function);
......@@ -1481,20 +1488,19 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ bind(&miss);
GenerateMiss(masm);
__ jmp(&call);
__ jmp(&call_count_incremented);
// Unreachable
__ int3();
}
void CallICStub::GenerateMiss(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::INTERNAL);
// Push the receiver and the function and feedback info.
__ Integer32ToSmi(rdx, rdx);
__ Push(rdi);
__ Push(rbx);
__ Integer32ToSmi(rdx, rdx);
__ Push(rdx);
// Call the entry.
......@@ -1504,7 +1510,6 @@ void CallICStub::GenerateMiss(MacroAssembler* masm) {
__ movp(rdi, rax);
}
bool CEntryStub::NeedsImmovableCode() {
return false;
}
......
......@@ -269,6 +269,11 @@ TEST(VectorCallCounts) {
CompileRun("f(foo); f(foo);");
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
CHECK_EQ(3, nexus.ExtractCallCount());
// Send the IC megamorphic, but we should still have incrementing counts.
CompileRun("f(function() { return 12; });");
CHECK_EQ(GENERIC, nexus.StateFromFeedback());
CHECK_EQ(4, nexus.ExtractCallCount());
}
TEST(VectorConstructCounts) {
......
......@@ -30,7 +30,7 @@ function __f_3(x) {
var __v_1 = arguments;
__v_1[1000] = 123;
depth++;
if (depth > 2500) return;
if (depth > 2400) return;
function __f_4() {
++__v_1[0];
__f_3(0.5);
......
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