[ic] Unify CallIC feedback collection and handling.

Consistently collect CallIC feedback in fullcodegen and Ignition, even
for possibly direct eval calls, that were treated specially so far, for
no apparent reason. With the upcoming SharedFunctionInfo based CallIC
feedback, we might be able to even inline certain direct eval calls, if
they manage to hit the eval cache. More importantly, this patch
simplifies the collection and dealing with CallIC feedback (and as a
side effect fixes an inconsistency with feedback for super constructor
calls).

R=mvstanton@chromium.org, mythria@chromium.org
BUG=v8:2206,v8:4280,v8:5267

Review-Url: https://codereview.chromium.org/2426693002
Cr-Commit-Position: refs/heads/master@{#40397}
This commit is contained in:
bmeurer 2016-10-18 05:01:05 -07:00 committed by Commit bot
parent cad36659b1
commit 308788b306
18 changed files with 58 additions and 102 deletions

View File

@ -889,25 +889,9 @@ bool Expression::IsMonomorphic() const {
}
}
bool Call::IsUsingCallFeedbackICSlot() const {
return GetCallType() != POSSIBLY_EVAL_CALL;
}
bool Call::IsUsingCallFeedbackSlot() const {
// SuperConstructorCall uses a CallConstructStub, which wants
// a Slot, in addition to any IC slots requested elsewhere.
return GetCallType() == SUPER_CALL;
}
void Call::AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
FeedbackVectorSlotCache* cache) {
if (IsUsingCallFeedbackICSlot()) {
ic_slot_ = spec->AddCallICSlot();
}
if (IsUsingCallFeedbackSlot()) {
stub_slot_ = spec->AddGeneralSlot();
}
ic_slot_ = spec->AddCallICSlot();
}
Call::CallType Call::GetCallType() const {

View File

@ -1839,8 +1839,6 @@ class Call final : public Expression {
void AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec,
FeedbackVectorSlotCache* cache);
FeedbackVectorSlot CallFeedbackSlot() const { return stub_slot_; }
FeedbackVectorSlot CallFeedbackICSlot() const { return ic_slot_; }
SmallMapList* GetReceiverTypes() {
@ -1912,8 +1910,6 @@ class Call final : public Expression {
// Helpers to determine how to handle the call.
CallType GetCallType() const;
bool IsUsingCallFeedbackSlot() const;
bool IsUsingCallFeedbackICSlot() const;
#ifdef DEBUG
// Used to assert that the FullCodeGenerator records the return site.
@ -1946,7 +1942,6 @@ class Call final : public Expression {
class IsPossiblyEvalField : public BitField<bool, IsTailField::kNext, 1> {};
FeedbackVectorSlot ic_slot_;
FeedbackVectorSlot stub_slot_;
Expression* expression_;
ZoneList<Expression*>* arguments_;
Handle<JSFunction> target_;

View File

@ -1527,11 +1527,8 @@ CompareOperationHint BytecodeGraphBuilder::GetCompareOperationHint() {
}
float BytecodeGraphBuilder::ComputeCallFrequency(int slot_id) const {
if (slot_id >= TypeFeedbackVector::kReservedIndexCount) {
CallICNexus nexus(feedback_vector(), feedback_vector()->ToSlot(slot_id));
return nexus.ComputeCallFrequency() * invocation_frequency_;
}
return 0.0f;
CallICNexus nexus(feedback_vector(), feedback_vector()->ToSlot(slot_id));
return nexus.ComputeCallFrequency() * invocation_frequency_;
}
void BytecodeGraphBuilder::VisitAdd() {

View File

@ -9605,7 +9605,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
syntactic_tail_call_mode, tail_call_mode);
} else {
PushArgumentsFromEnvironment(argument_count);
if (expr->is_uninitialized() && expr->IsUsingCallFeedbackICSlot()) {
if (expr->is_uninitialized()) {
// We've never seen this call before, so let's have Crankshaft learn
// through the type vector.
call = NewCallFunctionViaIC(function, argument_count,

View File

@ -517,16 +517,12 @@ void AstTyper::VisitProperty(Property* expr) {
void AstTyper::VisitCall(Call* expr) {
// Collect type feedback.
RECURSE(Visit(expr->expression()));
bool is_uninitialized = true;
if (expr->IsUsingCallFeedbackICSlot()) {
FeedbackVectorSlot slot = expr->CallFeedbackICSlot();
is_uninitialized = oracle()->CallIsUninitialized(slot);
if (!expr->expression()->IsProperty() &&
oracle()->CallIsMonomorphic(slot)) {
expr->set_target(oracle()->GetCallTarget(slot));
Handle<AllocationSite> site = oracle()->GetCallAllocationSite(slot);
expr->set_allocation_site(site);
}
FeedbackVectorSlot slot = expr->CallFeedbackICSlot();
bool is_uninitialized = oracle()->CallIsUninitialized(slot);
if (!expr->expression()->IsProperty() && oracle()->CallIsMonomorphic(slot)) {
expr->set_target(oracle()->GetCallTarget(slot));
Handle<AllocationSite> site = oracle()->GetCallAllocationSite(slot);
expr->set_allocation_site(site);
}
expr->set_is_uninitialized(is_uninitialized);

View File

@ -2491,11 +2491,13 @@ void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
// Record source position for debugger.
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny,
expr->tail_call_mode())
.code();
__ mov(r3, Operand(SmiFromSlot(expr->CallFeedbackICSlot())));
__ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ mov(r0, Operand(arg_count));
__ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny,
expr->tail_call_mode()),
RelocInfo::CODE_TARGET);
__ Call(code, RelocInfo::CODE_TARGET);
OperandStackDepthDecrement(arg_count + 1);
RecordJSReturnSite(expr);
RestoreContext();

View File

@ -2396,11 +2396,13 @@ void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
SetCallPosition(expr);
// Call the evaluated function.
Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny,
expr->tail_call_mode())
.code();
__ Mov(x3, SmiFromSlot(expr->CallFeedbackICSlot()));
__ Peek(x1, (arg_count + 1) * kXRegSize);
__ Mov(x0, arg_count);
__ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny,
expr->tail_call_mode()),
RelocInfo::CODE_TARGET);
__ Call(code, RelocInfo::CODE_TARGET);
OperandStackDepthDecrement(arg_count + 1);
RecordJSReturnSite(expr);
RestoreContext();

View File

@ -2385,11 +2385,13 @@ void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS);
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny,
expr->tail_call_mode())
.code();
__ Move(edx, Immediate(SmiFromSlot(expr->CallFeedbackICSlot())));
__ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
__ Set(eax, arg_count);
__ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny,
expr->tail_call_mode()),
RelocInfo::CODE_TARGET);
__ Move(eax, Immediate(arg_count));
__ call(code, RelocInfo::CODE_TARGET);
OperandStackDepthDecrement(arg_count + 1);
RecordJSReturnSite(expr);
RestoreContext();

View File

@ -2500,11 +2500,13 @@ void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS);
// Record source position for debugger.
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny,
expr->tail_call_mode())
.code();
__ li(a3, Operand(SmiFromSlot(expr->CallFeedbackICSlot())));
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ li(a0, Operand(arg_count));
__ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny,
expr->tail_call_mode()),
RelocInfo::CODE_TARGET);
__ Call(code, RelocInfo::CODE_TARGET);
OperandStackDepthDecrement(arg_count + 1);
RecordJSReturnSite(expr);
RestoreContext();

View File

@ -2499,11 +2499,13 @@ void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS);
// Record source position for debugger.
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny,
expr->tail_call_mode())
.code();
__ li(a3, Operand(SmiFromSlot(expr->CallFeedbackICSlot())));
__ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ li(a0, Operand(arg_count));
__ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny,
expr->tail_call_mode()),
RelocInfo::CODE_TARGET);
__ Call(code, RelocInfo::CODE_TARGET);
OperandStackDepthDecrement(arg_count + 1);
RecordJSReturnSite(expr);
RestoreContext();

View File

@ -2375,11 +2375,13 @@ void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS);
SetCallPosition(expr);
Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny,
expr->tail_call_mode())
.code();
__ Move(rdx, SmiFromSlot(expr->CallFeedbackICSlot()));
__ movp(rdi, Operand(rsp, (arg_count + 1) * kPointerSize));
__ Set(rax, arg_count);
__ Call(isolate()->builtins()->Call(ConvertReceiverMode::kAny,
expr->tail_call_mode()),
RelocInfo::CODE_TARGET);
__ call(code, RelocInfo::CODE_TARGET);
OperandStackDepthDecrement(arg_count + 1);
RecordJSReturnSite(expr);
RestoreContext();

View File

@ -2466,17 +2466,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()->SetExpressionPosition(expr);
int feedback_slot_index;
if (expr->CallFeedbackICSlot().IsInvalid()) {
DCHECK(call_type == Call::POSSIBLY_EVAL_CALL);
// Valid type feedback slots can only be greater than kReservedIndexCount.
// We use 0 to indicate an invalid slot id. Statically assert that 0 cannot
// be a valid slot id.
STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
feedback_slot_index = 0;
} else {
feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
}
int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
builder()->Call(callee, args, feedback_slot_index, expr->tail_call_mode());
}

View File

@ -567,13 +567,7 @@ 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_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_without_feedback);
call_function(this);
// The checks. First, does function match the recorded monomorphic target?
Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id);
@ -733,18 +727,6 @@ Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context,
Goto(&end);
}
Bind(&call_without_feedback);
{
// 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(&end);
return return_value.value();
}

View File

@ -40,11 +40,11 @@ bytecodes: [
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1),
/* 52 E> */ B(Call), R(1), R(2), U8(2), U8(0),
/* 52 E> */ B(Call), R(1), R(2), U8(2), U8(2),
/* 62 S> */ B(LdaConstant), U8(1),
B(Star), R(3),
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1),
/* 69 E> */ B(Call), R(1), R(2), U8(1), U8(4),
/* 69 E> */ B(Call), R(1), R(2), U8(1), U8(6),
/* 74 S> */ B(Return),
]
constant pool: [

View File

@ -131,7 +131,7 @@ bytecodes: [
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1),
B(Star), R(2),
B(LdaSmi), U8(2),
/* 136 E> */ B(StaNamedPropertyStrict), R(2), U8(1), U8(5),
/* 136 E> */ B(StaNamedPropertyStrict), R(2), U8(1), U8(4),
B(Ldar), R(this),
B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(0),
@ -186,7 +186,7 @@ bytecodes: [
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1),
B(Star), R(2),
B(LdaSmi), U8(2),
/* 134 E> */ B(StaNamedPropertyStrict), R(2), U8(1), U8(5),
/* 134 E> */ B(StaNamedPropertyStrict), R(2), U8(1), U8(4),
B(Ldar), R(this),
B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(0),

View File

@ -901,8 +901,8 @@ bytecodes: [
/* 3435 S> */ B(LdaZero),
/* 3435 E> */ B(StaContextSlot), R(context), U8(255), U8(0),
/* 3438 S> */ B(LdrUndefined), R(2),
/* 3438 E> */ B(LdrGlobal), U8(2), R(1),
/* 3438 E> */ B(Call), R(1), R(2), U8(1), U8(0),
/* 3438 E> */ B(LdrGlobal), U8(4), R(1),
/* 3438 E> */ B(Call), R(1), R(2), U8(1), U8(2),
/* 3454 S> */ B(LdaSmi), U8(100),
/* 3454 E> */ B(Wide), B(StaContextSlot), R16(context), U16(256), U16(0),
/* 3459 S> */ B(Wide), B(LdaContextSlot), R16(context), U16(256), U16(0),

View File

@ -38,7 +38,7 @@ bytecodes: [
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1),
/* 41 E> */ B(Call), R(1), R(2), U8(2), U8(0),
/* 41 E> */ B(Call), R(1), R(2), U8(2), U8(2),
/* 53 S> */ B(Return),
]
constant pool: [

View File

@ -39,8 +39,8 @@ bytecodes: [
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1),
/* 14 E> */ B(Call), R(1), R(2), U8(2), U8(0),
/* 35 S> */ B(LdaLookupGlobalSlot), U8(2), U8(4), U8(1),
/* 14 E> */ B(Call), R(1), R(2), U8(2), U8(2),
/* 35 S> */ B(LdaLookupGlobalSlot), U8(2), U8(6), U8(1),
/* 45 S> */ B(Return),
]
constant pool: [
@ -84,8 +84,8 @@ bytecodes: [
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1),
/* 14 E> */ B(Call), R(1), R(2), U8(2), U8(0),
/* 35 S> */ B(LdaLookupGlobalSlotInsideTypeof), U8(2), U8(4), U8(1),
/* 14 E> */ B(Call), R(1), R(2), U8(2), U8(2),
/* 35 S> */ B(LdaLookupGlobalSlotInsideTypeof), U8(2), U8(6), U8(1),
B(TypeOf),
/* 52 S> */ B(Return),
]
@ -132,7 +132,7 @@ bytecodes: [
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1),
/* 29 E> */ B(Call), R(1), R(2), U8(2), U8(0),
/* 29 E> */ B(Call), R(1), R(2), U8(2), U8(2),
/* 39 S> */ B(Return),
]
constant pool: [
@ -181,7 +181,7 @@ bytecodes: [
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1),
/* 44 E> */ B(Call), R(1), R(2), U8(2), U8(0),
/* 44 E> */ B(Call), R(1), R(2), U8(2), U8(2),
/* 66 S> */ B(LdaLookupContextSlot), U8(2), U8(6), U8(1),
/* 76 S> */ B(Return),
]
@ -231,8 +231,8 @@ bytecodes: [
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(1),
/* 40 E> */ B(Call), R(1), R(2), U8(2), U8(0),
/* 62 S> */ B(LdaLookupGlobalSlot), U8(2), U8(4), U8(1),
/* 40 E> */ B(Call), R(1), R(2), U8(2), U8(2),
/* 62 S> */ B(LdaLookupGlobalSlot), U8(2), U8(6), U8(1),
/* 72 S> */ B(Return),
]
constant pool: [