Commit 7be22a8c authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

Use bits of call count on CallIC as flags

This CL uses bits of the call count as flags according
to CallCountField and SpeculationModeField defined in
CallICNexus.

Bug: v8:7127
Change-Id: I3f64c1807d61410f9029b46b9a59a1fcaa5a0a3b
Reviewed-on: https://chromium-review.googlesource.com/808926
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49959}
parent 64a4f417
......@@ -675,16 +675,31 @@ InlineCacheState CallICNexus::StateFromFeedback() const {
return UNINITIALIZED;
}
int CallICNexus::ExtractCallCount() {
int CallICNexus::GetCallCount() {
Object* call_count = GetFeedbackExtra();
CHECK(call_count->IsSmi());
int value = Smi::ToInt(call_count);
return value;
uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
return CallCountField::decode(value);
}
void CallICNexus::SetSpeculationMode(SpeculationMode mode) {
Object* call_count = GetFeedbackExtra();
CHECK(call_count->IsSmi());
uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
int result = static_cast<int>(CallCountField::decode(value) |
SpeculationModeField::encode(mode));
SetFeedbackExtra(Smi::FromInt(result), SKIP_WRITE_BARRIER);
}
CallICNexus::SpeculationMode CallICNexus::GetSpeculationMode() {
Object* call_count = GetFeedbackExtra();
CHECK(call_count->IsSmi());
uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
return SpeculationModeField::decode(value);
}
float CallICNexus::ComputeCallFrequency() {
double const invocation_count = vector()->invocation_count();
double const call_count = ExtractCallCount();
double const call_count = GetCallCount();
if (invocation_count == 0) {
// Prevent division by 0.
return 0.0f;
......
......@@ -623,6 +623,7 @@ class FeedbackNexus {
class CallICNexus final : public FeedbackNexus {
public:
enum SpeculationMode { kAllowSpeculation, kDisallowSpeculation };
CallICNexus(Handle<FeedbackVector> vector, FeedbackSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->IsCallIC(slot));
......@@ -647,11 +648,16 @@ class CallICNexus final : public FeedbackNexus {
return length == 0;
}
int ExtractCallCount();
int GetCallCount();
void SetSpeculationMode(SpeculationMode mode);
SpeculationMode GetSpeculationMode();
// Compute the call frequency based on the call count and the invocation
// count (taken from the type feedback vector).
float ComputeCallFrequency();
typedef BitField<SpeculationMode, 0, 1> SpeculationModeField;
typedef BitField<uint32_t, 1, 31> CallCountField;
};
class LoadICNexus : public FeedbackNexus {
......
......@@ -586,7 +586,16 @@ void InterpreterAssembler::IncrementCallCount(Node* feedback_vector,
Comment("increment call count");
Node* call_count =
LoadFeedbackVectorSlot(feedback_vector, slot_id, kPointerSize);
Node* new_count = SmiAdd(call_count, SmiConstant(1));
// The lowest {CallICNexus::CallCountField::kShift} bits of the call
// count are used as flags. To increment the call count by 1 we hence
// have to increment by 1 << {CallICNexus::CallCountField::kShift}.
Node* new_count =
SmiAdd(call_count, SmiConstant(1 << CallICNexus::CallCountField::kShift));
CSA_ASSERT(
this,
SmiEqual(SmiMod(new_count,
SmiConstant(1 << CallICNexus::CallCountField::kShift)),
SmiConstant(0)));
// Count is Smi, so we don't need a write barrier.
StoreFeedbackVectorSlot(feedback_vector, slot_id, new_count,
SKIP_WRITE_BARRIER, kPointerSize);
......
......@@ -257,12 +257,12 @@ TEST(VectorCallCounts) {
CompileRun("f(foo); f(foo);");
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
CHECK_EQ(3, nexus.ExtractCallCount());
CHECK_EQ(3, nexus.GetCallCount());
// 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());
CHECK_EQ(4, nexus.GetCallCount());
}
TEST(VectorConstructCounts) {
......@@ -288,12 +288,42 @@ TEST(VectorConstructCounts) {
CompileRun("f(Foo); f(Foo);");
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
CHECK_EQ(3, nexus.ExtractCallCount());
CHECK_EQ(3, nexus.GetCallCount());
// Send the IC megamorphic, but we should still have incrementing counts.
CompileRun("f(function() {});");
CHECK_EQ(GENERIC, nexus.StateFromFeedback());
CHECK_EQ(4, nexus.ExtractCallCount());
CHECK_EQ(4, nexus.GetCallCount());
}
TEST(VectorSpeculationMode) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
Isolate* isolate = CcTest::i_isolate();
// Make sure function f has a call that uses a type feedback slot.
CompileRun(
"function Foo() {}"
"function f(a) { new a(); } f(Foo);");
Handle<JSFunction> f = GetFunction("f");
Handle<FeedbackVector> feedback_vector =
Handle<FeedbackVector>(f->feedback_vector(), isolate);
FeedbackSlot slot(0);
CallICNexus nexus(feedback_vector, slot);
CHECK_EQ(CallICNexus::kAllowSpeculation, nexus.GetSpeculationMode());
CompileRun("f(Foo); f(Foo);");
CHECK_EQ(3, nexus.GetCallCount());
CHECK_EQ(CallICNexus::kAllowSpeculation, nexus.GetSpeculationMode());
nexus.SetSpeculationMode(CallICNexus::kAllowSpeculation);
nexus.SetSpeculationMode(CallICNexus::kDisallowSpeculation);
CHECK_EQ(CallICNexus::kDisallowSpeculation, nexus.GetSpeculationMode());
nexus.SetSpeculationMode(CallICNexus::kAllowSpeculation);
CHECK_EQ(CallICNexus::kAllowSpeculation, nexus.GetSpeculationMode());
}
TEST(VectorLoadICStates) {
......
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