[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:
parent
cad36659b1
commit
308788b306
@ -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 {
|
||||
|
@ -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_;
|
||||
|
@ -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() {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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: [
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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: [
|
||||
|
@ -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: [
|
||||
|
Loading…
Reference in New Issue
Block a user