Commit b34d2ec6 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[objects] Move deopt_count to FeedbackVector

Since any deopt-count-based heuristics should be native context
dependent, it belongs in the feedback vector rather than the SFI.

Bug: v8:6402
Change-Id: I30804d58bc1dec9150558e6ee21ee5b4dbd36c8d
Reviewed-on: https://chromium-review.googlesource.com/593661
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47014}
parent 2d79d2c3
...@@ -243,13 +243,12 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) { ...@@ -243,13 +243,12 @@ void Deoptimizer::DeoptimizeMarkedCodeForContext(Context* context) {
if (!code->marked_for_deoptimization()) return; if (!code->marked_for_deoptimization()) return;
// Unlink this function. // Unlink this function.
SharedFunctionInfo* shared = function->shared();
if (!code->deopt_already_counted()) { if (!code->deopt_already_counted()) {
shared->increment_deopt_count(); function->feedback_vector()->increment_deopt_count();
code->set_deopt_already_counted(true); code->set_deopt_already_counted(true);
} }
function->set_code(shared->code()); function->set_code(function->shared()->code());
if (FLAG_trace_deopt) { if (FLAG_trace_deopt) {
CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer()); CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
...@@ -535,7 +534,7 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function, ...@@ -535,7 +534,7 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction* function,
// that can eventually lead to disabling optimization for a function. // that can eventually lead to disabling optimization for a function.
isolate->counters()->soft_deopts_executed()->Increment(); isolate->counters()->soft_deopts_executed()->Increment();
} else if (function != nullptr) { } else if (function != nullptr) {
function->shared()->increment_deopt_count(); function->feedback_vector()->increment_deopt_count();
} }
} }
if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) { if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
......
...@@ -100,6 +100,7 @@ ACCESSORS(FeedbackVector, optimized_code_cell, Object, kOptimizedCodeOffset) ...@@ -100,6 +100,7 @@ ACCESSORS(FeedbackVector, optimized_code_cell, Object, kOptimizedCodeOffset)
INT32_ACCESSORS(FeedbackVector, length, kLengthOffset) INT32_ACCESSORS(FeedbackVector, length, kLengthOffset)
INT32_ACCESSORS(FeedbackVector, invocation_count, kInvocationCountOffset) INT32_ACCESSORS(FeedbackVector, invocation_count, kInvocationCountOffset)
INT32_ACCESSORS(FeedbackVector, profiler_ticks, kProfilerTicksOffset) INT32_ACCESSORS(FeedbackVector, profiler_ticks, kProfilerTicksOffset)
INT32_ACCESSORS(FeedbackVector, deopt_count, kDeoptCountOffset)
bool FeedbackVector::is_empty() const { return length() == 0; } bool FeedbackVector::is_empty() const { return length() == 0; }
...@@ -109,6 +110,13 @@ FeedbackMetadata* FeedbackVector::metadata() const { ...@@ -109,6 +110,13 @@ FeedbackMetadata* FeedbackVector::metadata() const {
void FeedbackVector::clear_invocation_count() { set_invocation_count(0); } void FeedbackVector::clear_invocation_count() { set_invocation_count(0); }
void FeedbackVector::increment_deopt_count() {
int count = deopt_count();
if (count < std::numeric_limits<int32_t>::max()) {
set_deopt_count(count + 1);
}
}
Code* FeedbackVector::optimized_code() const { Code* FeedbackVector::optimized_code() const {
Object* slot = optimized_code_cell(); Object* slot = optimized_code_cell();
if (slot->IsSmi()) return nullptr; if (slot->IsSmi()) return nullptr;
......
...@@ -206,6 +206,7 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate, ...@@ -206,6 +206,7 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
Smi::FromEnum(OptimizationMarker::kNone)); Smi::FromEnum(OptimizationMarker::kNone));
DCHECK_EQ(vector->invocation_count(), 0); DCHECK_EQ(vector->invocation_count(), 0);
DCHECK_EQ(vector->profiler_ticks(), 0); DCHECK_EQ(vector->profiler_ticks(), 0);
DCHECK_EQ(vector->deopt_count(), 0);
// Ensure we can skip the write barrier // Ensure we can skip the write barrier
Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate); Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
...@@ -334,7 +335,7 @@ void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization( ...@@ -334,7 +335,7 @@ void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
PrintF("]\n"); PrintF("]\n");
} }
if (!code->deopt_already_counted()) { if (!code->deopt_already_counted()) {
shared->increment_deopt_count(); increment_deopt_count();
code->set_deopt_already_counted(true); code->set_deopt_already_counted(true);
} }
ClearOptimizedCode(); ClearOptimizedCode();
......
...@@ -148,7 +148,11 @@ class FeedbackVector : public HeapObject { ...@@ -148,7 +148,11 @@ class FeedbackVector : public HeapObject {
// runtime profiler. // runtime profiler.
DECL_INT32_ACCESSORS(profiler_ticks) DECL_INT32_ACCESSORS(profiler_ticks)
// [deopt_count]: The number of times this function has deoptimized.
DECL_INT32_ACCESSORS(deopt_count)
inline void clear_invocation_count(); inline void clear_invocation_count();
inline void increment_deopt_count();
inline Code* optimized_code() const; inline Code* optimized_code() const;
inline OptimizationMarker optimization_marker() const; inline OptimizationMarker optimization_marker() const;
...@@ -243,6 +247,7 @@ class FeedbackVector : public HeapObject { ...@@ -243,6 +247,7 @@ class FeedbackVector : public HeapObject {
V(kLengthOffset, kInt32Size) \ V(kLengthOffset, kInt32Size) \
V(kInvocationCountOffset, kInt32Size) \ V(kInvocationCountOffset, kInt32Size) \
V(kProfilerTicksOffset, kInt32Size) \ V(kProfilerTicksOffset, kInt32Size) \
V(kDeoptCountOffset, kInt32Size) \
V(kUnalignedHeaderSize, 0) V(kUnalignedHeaderSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, FEEDBACK_VECTOR_FIELDS) DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, FEEDBACK_VECTOR_FIELDS)
......
...@@ -4228,9 +4228,10 @@ AllocationResult Heap::CopyFeedbackVector(FeedbackVector* src) { ...@@ -4228,9 +4228,10 @@ AllocationResult Heap::CopyFeedbackVector(FeedbackVector* src) {
// Slow case: Just copy the content one-by-one. // Slow case: Just copy the content one-by-one.
result->set_shared_function_info(src->shared_function_info()); result->set_shared_function_info(src->shared_function_info());
result->set_optimized_code_cell(src->optimized_code_cell());
result->set_invocation_count(src->invocation_count()); result->set_invocation_count(src->invocation_count());
result->set_profiler_ticks(src->profiler_ticks()); result->set_profiler_ticks(src->profiler_ticks());
result->set_optimized_code_cell(src->optimized_code_cell()); result->set_deopt_count(src->deopt_count());
for (int i = 0; i < len; i++) result->set(i, src->get(i), mode); for (int i = 0; i < len; i++) result->set(i, src->get(i), mode);
return result; return result;
} }
...@@ -4373,6 +4374,7 @@ AllocationResult Heap::AllocateFeedbackVector(SharedFunctionInfo* shared, ...@@ -4373,6 +4374,7 @@ AllocationResult Heap::AllocateFeedbackVector(SharedFunctionInfo* shared,
vector->set_length(length); vector->set_length(length);
vector->set_invocation_count(0); vector->set_invocation_count(0);
vector->set_profiler_ticks(0); vector->set_profiler_ticks(0);
vector->set_deopt_count(0);
// TODO(leszeks): Initialize based on the feedback metadata. // TODO(leszeks): Initialize based on the feedback metadata.
MemsetPointer(vector->slots_start(), undefined_value(), length); MemsetPointer(vector->slots_start(), undefined_value(), length);
return vector; return vector;
......
...@@ -13852,7 +13852,6 @@ void Map::StartInobjectSlackTracking() { ...@@ -13852,7 +13852,6 @@ void Map::StartInobjectSlackTracking() {
void SharedFunctionInfo::ResetForNewContext(int new_ic_age) { void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
set_ic_age(new_ic_age); set_ic_age(new_ic_age);
set_deopt_count(0);
} }
void ObjectVisitor::VisitCodeTarget(Code* host, RelocInfo* rinfo) { void ObjectVisitor::VisitCodeTarget(Code* host, RelocInfo* rinfo) {
......
...@@ -358,23 +358,10 @@ void SharedFunctionInfo::set_inferred_name(String* inferred_name) { ...@@ -358,23 +358,10 @@ void SharedFunctionInfo::set_inferred_name(String* inferred_name) {
BIT_FIELD_ACCESSORS(SharedFunctionInfo, counters_and_bailout_reason, ic_age, BIT_FIELD_ACCESSORS(SharedFunctionInfo, counters_and_bailout_reason, ic_age,
SharedFunctionInfo::ICAgeBits) SharedFunctionInfo::ICAgeBits)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, counters_and_bailout_reason,
deopt_count, SharedFunctionInfo::DeoptCountBits)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, counters_and_bailout_reason, BIT_FIELD_ACCESSORS(SharedFunctionInfo, counters_and_bailout_reason,
disable_optimization_reason, disable_optimization_reason,
SharedFunctionInfo::DisabledOptimizationReasonBits) SharedFunctionInfo::DisabledOptimizationReasonBits)
void SharedFunctionInfo::increment_deopt_count() {
int value = counters_and_bailout_reason();
int deopt_count = DeoptCountBits::decode(value);
// Saturate the deopt count when incrementing, rather than overflowing.
if (deopt_count < DeoptCountBits::kMax) {
set_counters_and_bailout_reason(
DeoptCountBits::update(value, deopt_count + 1));
}
}
bool SharedFunctionInfo::IsUserJavaScript() { bool SharedFunctionInfo::IsUserJavaScript() {
Object* script_obj = script(); Object* script_obj = script();
if (script_obj->IsUndefined(GetIsolate())) return false; if (script_obj->IsUndefined(GetIsolate())) return false;
......
...@@ -337,10 +337,6 @@ class SharedFunctionInfo : public HeapObject { ...@@ -337,10 +337,6 @@ class SharedFunctionInfo : public HeapObject {
Handle<Object> GetSourceCode(); Handle<Object> GetSourceCode();
Handle<Object> GetSourceCodeHarmony(); Handle<Object> GetSourceCodeHarmony();
// Number of times the function was deoptimized.
DECL_INT_ACCESSORS(deopt_count)
inline void increment_deopt_count();
// Stores deopt_count, ic_age and bailout_reason as bit-fields. // Stores deopt_count, ic_age and bailout_reason as bit-fields.
DECL_INT_ACCESSORS(counters_and_bailout_reason) DECL_INT_ACCESSORS(counters_and_bailout_reason)
...@@ -515,7 +511,6 @@ class SharedFunctionInfo : public HeapObject { ...@@ -515,7 +511,6 @@ class SharedFunctionInfo : public HeapObject {
// Bit fields in |counters_and_bailout_reason|. // Bit fields in |counters_and_bailout_reason|.
#define COUNTERS_AND_BAILOUT_REASON_BIT_FIELDS(V, _) \ #define COUNTERS_AND_BAILOUT_REASON_BIT_FIELDS(V, _) \
V(DeoptCountBits, int, 4, _) \
V(ICAgeBits, int, 8, _) \ V(ICAgeBits, int, 8, _) \
V(DisabledOptimizationReasonBits, BailoutReason, 8, _) V(DisabledOptimizationReasonBits, BailoutReason, 8, _)
......
...@@ -417,7 +417,9 @@ RUNTIME_FUNCTION(Runtime_GetDeoptCount) { ...@@ -417,7 +417,9 @@ RUNTIME_FUNCTION(Runtime_GetDeoptCount) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(1, args.length()); DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
return Smi::FromInt(function->shared()->deopt_count()); // Functions without a feedback vector have never deoptimized.
if (!function->has_feedback_vector()) return Smi::kZero;
return Smi::FromInt(function->feedback_vector()->deopt_count());
} }
static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) { static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
......
...@@ -2265,8 +2265,6 @@ TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) { ...@@ -2265,8 +2265,6 @@ TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
CcTest::CollectAllGarbage(); CcTest::CollectAllGarbage();
CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age()); CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
CHECK_EQ(0, f->shared()->deopt_count());
CHECK_EQ(0, f->feedback_vector()->profiler_ticks());
} }
...@@ -2308,8 +2306,6 @@ TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) { ...@@ -2308,8 +2306,6 @@ TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
CcTest::CollectAllGarbage(); CcTest::CollectAllGarbage();
CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age()); CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
CHECK_EQ(0, f->shared()->deopt_count());
CHECK_EQ(0, f->feedback_vector()->profiler_ticks());
} }
......
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