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 { ...@@ -675,16 +675,31 @@ InlineCacheState CallICNexus::StateFromFeedback() const {
return UNINITIALIZED; return UNINITIALIZED;
} }
int CallICNexus::ExtractCallCount() { int CallICNexus::GetCallCount() {
Object* call_count = GetFeedbackExtra(); Object* call_count = GetFeedbackExtra();
CHECK(call_count->IsSmi()); CHECK(call_count->IsSmi());
int value = Smi::ToInt(call_count); uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
return value; 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() { float CallICNexus::ComputeCallFrequency() {
double const invocation_count = vector()->invocation_count(); double const invocation_count = vector()->invocation_count();
double const call_count = ExtractCallCount(); double const call_count = GetCallCount();
if (invocation_count == 0) { if (invocation_count == 0) {
// Prevent division by 0. // Prevent division by 0.
return 0.0f; return 0.0f;
......
...@@ -623,6 +623,7 @@ class FeedbackNexus { ...@@ -623,6 +623,7 @@ class FeedbackNexus {
class CallICNexus final : public FeedbackNexus { class CallICNexus final : public FeedbackNexus {
public: public:
enum SpeculationMode { kAllowSpeculation, kDisallowSpeculation };
CallICNexus(Handle<FeedbackVector> vector, FeedbackSlot slot) CallICNexus(Handle<FeedbackVector> vector, FeedbackSlot slot)
: FeedbackNexus(vector, slot) { : FeedbackNexus(vector, slot) {
DCHECK(vector->IsCallIC(slot)); DCHECK(vector->IsCallIC(slot));
...@@ -647,11 +648,16 @@ class CallICNexus final : public FeedbackNexus { ...@@ -647,11 +648,16 @@ class CallICNexus final : public FeedbackNexus {
return length == 0; 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 // Compute the call frequency based on the call count and the invocation
// count (taken from the type feedback vector). // count (taken from the type feedback vector).
float ComputeCallFrequency(); float ComputeCallFrequency();
typedef BitField<SpeculationMode, 0, 1> SpeculationModeField;
typedef BitField<uint32_t, 1, 31> CallCountField;
}; };
class LoadICNexus : public FeedbackNexus { class LoadICNexus : public FeedbackNexus {
......
...@@ -586,7 +586,16 @@ void InterpreterAssembler::IncrementCallCount(Node* feedback_vector, ...@@ -586,7 +586,16 @@ void InterpreterAssembler::IncrementCallCount(Node* feedback_vector,
Comment("increment call count"); Comment("increment call count");
Node* call_count = Node* call_count =
LoadFeedbackVectorSlot(feedback_vector, slot_id, kPointerSize); 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. // Count is Smi, so we don't need a write barrier.
StoreFeedbackVectorSlot(feedback_vector, slot_id, new_count, StoreFeedbackVectorSlot(feedback_vector, slot_id, new_count,
SKIP_WRITE_BARRIER, kPointerSize); SKIP_WRITE_BARRIER, kPointerSize);
......
...@@ -257,12 +257,12 @@ TEST(VectorCallCounts) { ...@@ -257,12 +257,12 @@ TEST(VectorCallCounts) {
CompileRun("f(foo); f(foo);"); CompileRun("f(foo); f(foo);");
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); 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. // Send the IC megamorphic, but we should still have incrementing counts.
CompileRun("f(function() { return 12; });"); CompileRun("f(function() { return 12; });");
CHECK_EQ(GENERIC, nexus.StateFromFeedback()); CHECK_EQ(GENERIC, nexus.StateFromFeedback());
CHECK_EQ(4, nexus.ExtractCallCount()); CHECK_EQ(4, nexus.GetCallCount());
} }
TEST(VectorConstructCounts) { TEST(VectorConstructCounts) {
...@@ -288,12 +288,42 @@ TEST(VectorConstructCounts) { ...@@ -288,12 +288,42 @@ TEST(VectorConstructCounts) {
CompileRun("f(Foo); f(Foo);"); CompileRun("f(Foo); f(Foo);");
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); 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. // Send the IC megamorphic, but we should still have incrementing counts.
CompileRun("f(function() {});"); CompileRun("f(function() {});");
CHECK_EQ(GENERIC, nexus.StateFromFeedback()); 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) { 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