Commit f41e519f authored by Mythri A's avatar Mythri A Committed by Commit Bot

[Turboprop] Differentiate between a deopt when we discard / reuse code

In turboprop, we reuse the code on a soft deopt. It will be good to
differentiate between a deopt that reuses the optimized code on the
next run and the deopt that discards the code. The deopt that reuses the
code is called a "bailout" because it is just bails out for one
execution to the unoptimized code.

Change-Id: I9a300201e9b327415e94c2817065d6a561f8ece5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2277807
Commit-Queue: Mythri Alle <mythria@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68722}
parent ea2460e2
...@@ -480,7 +480,7 @@ void RelocInfo::Print(Isolate* isolate, std::ostream& os) { // NOLINT ...@@ -480,7 +480,7 @@ void RelocInfo::Print(Isolate* isolate, std::ostream& os) { // NOLINT
// Deoptimization bailouts are stored as runtime entries. // Deoptimization bailouts are stored as runtime entries.
DeoptimizeKind type; DeoptimizeKind type;
if (Deoptimizer::IsDeoptimizationEntry(isolate, target_address(), &type)) { if (Deoptimizer::IsDeoptimizationEntry(isolate, target_address(), &type)) {
os << " (" << Deoptimizer::MessageFor(type) os << " (" << Deoptimizer::MessageFor(type, false)
<< " deoptimization bailout)"; << " deoptimization bailout)";
} }
} else if (IsConstPool(rmode_)) { } else if (IsConstPool(rmode_)) {
......
...@@ -466,14 +466,16 @@ void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) { ...@@ -466,14 +466,16 @@ void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
deoptimizer->DoComputeOutputFrames(); deoptimizer->DoComputeOutputFrames();
} }
const char* Deoptimizer::MessageFor(DeoptimizeKind kind) { const char* Deoptimizer::MessageFor(DeoptimizeKind kind, bool reuse_code) {
switch (kind) { switch (kind) {
case DeoptimizeKind::kEager: case DeoptimizeKind::kEager:
return "eager"; DCHECK(!reuse_code);
return "deopt-eager";
case DeoptimizeKind::kSoft: case DeoptimizeKind::kSoft:
return "soft"; return reuse_code ? "bailout-soft" : "deopt-soft";
case DeoptimizeKind::kLazy: case DeoptimizeKind::kLazy:
return "lazy"; DCHECK(!reuse_code);
return "deopt-lazy";
} }
FATAL("Unsupported deopt kind"); FATAL("Unsupported deopt kind");
return nullptr; return nullptr;
...@@ -536,8 +538,9 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction function, ...@@ -536,8 +538,9 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction function,
compiled_code_.set_deopt_already_counted(true); compiled_code_.set_deopt_already_counted(true);
{ {
HandleScope scope(isolate_); HandleScope scope(isolate_);
PROFILE(isolate_, CodeDeoptEvent(handle(compiled_code_, isolate_), kind, PROFILE(isolate_,
from_, fp_to_sp_delta_)); CodeDeoptEvent(handle(compiled_code_, isolate_), kind, from_,
fp_to_sp_delta_, should_reuse_code()));
} }
unsigned size = ComputeInputFrameSize(); unsigned size = ComputeInputFrameSize();
const int parameter_count = const int parameter_count =
...@@ -600,6 +603,12 @@ Handle<Code> Deoptimizer::compiled_code() const { ...@@ -600,6 +603,12 @@ Handle<Code> Deoptimizer::compiled_code() const {
return Handle<Code>(compiled_code_, isolate()); return Handle<Code>(compiled_code_, isolate());
} }
bool Deoptimizer::should_reuse_code() const {
int count = compiled_code_.deoptimization_count();
return deopt_kind_ == DeoptimizeKind::kSoft &&
count < FLAG_reuse_opt_code_count;
}
Deoptimizer::~Deoptimizer() { Deoptimizer::~Deoptimizer() {
DCHECK(input_ == nullptr && output_ == nullptr); DCHECK(input_ == nullptr && output_ == nullptr);
DCHECK_NULL(disallow_heap_allocation_); DCHECK_NULL(disallow_heap_allocation_);
...@@ -748,8 +757,8 @@ void Deoptimizer::DoComputeOutputFrames() { ...@@ -748,8 +757,8 @@ void Deoptimizer::DoComputeOutputFrames() {
if (trace_scope_ != nullptr) { if (trace_scope_ != nullptr) {
timer.Start(); timer.Start();
PrintF(trace_scope_->file(), "[deoptimizing (DEOPT %s): begin ", PrintF(trace_scope_->file(), "[bailout (kind: %s): begin ",
MessageFor(deopt_kind_)); MessageFor(deopt_kind_, should_reuse_code()));
PrintFunctionName(); PrintFunctionName();
PrintF(trace_scope_->file(), PrintF(trace_scope_->file(),
" (opt #%d) @%d, FP to SP delta: %d, caller sp: " V8PRIxPTR_FMT " (opt #%d) @%d, FP to SP delta: %d, caller sp: " V8PRIxPTR_FMT
...@@ -850,8 +859,8 @@ void Deoptimizer::DoComputeOutputFrames() { ...@@ -850,8 +859,8 @@ void Deoptimizer::DoComputeOutputFrames() {
if (trace_scope_ != nullptr) { if (trace_scope_ != nullptr) {
double ms = timer.Elapsed().InMillisecondsF(); double ms = timer.Elapsed().InMillisecondsF();
int index = output_count_ - 1; // Index of the topmost frame. int index = output_count_ - 1; // Index of the topmost frame.
PrintF(trace_scope_->file(), "[deoptimizing (%s): end ", PrintF(trace_scope_->file(), "[bailout (kind: %s): end ",
MessageFor(deopt_kind_)); MessageFor(deopt_kind_, should_reuse_code()));
PrintFunctionName(); PrintFunctionName();
PrintF(trace_scope_->file(), PrintF(trace_scope_->file(),
" @%d => node=%d, pc=" V8PRIxPTR_FMT " @%d => node=%d, pc=" V8PRIxPTR_FMT
......
...@@ -444,7 +444,7 @@ class Deoptimizer : public Malloced { ...@@ -444,7 +444,7 @@ class Deoptimizer : public Malloced {
static int ComputeSourcePositionFromBytecodeArray(SharedFunctionInfo shared, static int ComputeSourcePositionFromBytecodeArray(SharedFunctionInfo shared,
BailoutId node_id); BailoutId node_id);
static const char* MessageFor(DeoptimizeKind kind); static const char* MessageFor(DeoptimizeKind kind, bool reuse_code);
int output_count() const { return output_count_; } int output_count() const { return output_count_; }
...@@ -455,6 +455,8 @@ class Deoptimizer : public Malloced { ...@@ -455,6 +455,8 @@ class Deoptimizer : public Malloced {
// Number of created JS frames. Not all created frames are necessarily JS. // Number of created JS frames. Not all created frames are necessarily JS.
int jsframe_count() const { return jsframe_count_; } int jsframe_count() const { return jsframe_count_; }
bool should_reuse_code() const;
static Deoptimizer* New(Address raw_function, DeoptimizeKind kind, static Deoptimizer* New(Address raw_function, DeoptimizeKind kind,
unsigned bailout_id, Address from, int fp_to_sp_delta, unsigned bailout_id, Address from, int fp_to_sp_delta,
Isolate* isolate); Isolate* isolate);
......
...@@ -260,7 +260,7 @@ static void PrintRelocInfo(StringBuilder* out, Isolate* isolate, ...@@ -260,7 +260,7 @@ static void PrintRelocInfo(StringBuilder* out, Isolate* isolate,
DeoptimizeKind type; DeoptimizeKind type;
if (Deoptimizer::IsDeoptimizationEntry(isolate, addr, &type)) { if (Deoptimizer::IsDeoptimizationEntry(isolate, addr, &type)) {
out->AddFormatted(" ;; %s deoptimization bailout", out->AddFormatted(" ;; %s deoptimization bailout",
Deoptimizer::MessageFor(type)); Deoptimizer::MessageFor(type, false));
} else { } else {
out->AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode)); out->AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode));
} }
......
...@@ -99,7 +99,8 @@ class CodeEventListener { ...@@ -99,7 +99,8 @@ class CodeEventListener {
virtual void CodeDisableOptEvent(Handle<AbstractCode> code, virtual void CodeDisableOptEvent(Handle<AbstractCode> code,
Handle<SharedFunctionInfo> shared) = 0; Handle<SharedFunctionInfo> shared) = 0;
virtual void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, virtual void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind,
Address pc, int fp_to_sp_delta) = 0; Address pc, int fp_to_sp_delta,
bool reuse_code) = 0;
// These events can happen when 1. an assumption made by optimized code fails // These events can happen when 1. an assumption made by optimized code fails
// or 2. a weakly embedded object dies. // or 2. a weakly embedded object dies.
virtual void CodeDependencyChangeEvent(Handle<Code> code, virtual void CodeDependencyChangeEvent(Handle<Code> code,
...@@ -220,9 +221,9 @@ class CodeEventDispatcher : public CodeEventListener { ...@@ -220,9 +221,9 @@ class CodeEventDispatcher : public CodeEventListener {
}); });
} }
void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc, void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc,
int fp_to_sp_delta) override { int fp_to_sp_delta, bool reuse_code) override {
DispatchEventToListeners([=](CodeEventListener* listener) { DispatchEventToListeners([=](CodeEventListener* listener) {
listener->CodeDeoptEvent(code, kind, pc, fp_to_sp_delta); listener->CodeDeoptEvent(code, kind, pc, fp_to_sp_delta, reuse_code);
}); });
} }
void CodeDependencyChangeEvent(Handle<Code> code, void CodeDependencyChangeEvent(Handle<Code> code,
......
...@@ -1401,10 +1401,11 @@ void Logger::ProcessDeoptEvent(Handle<Code> code, SourcePosition position, ...@@ -1401,10 +1401,11 @@ void Logger::ProcessDeoptEvent(Handle<Code> code, SourcePosition position,
} }
void Logger::CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc, void Logger::CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc,
int fp_to_sp_delta) { int fp_to_sp_delta, bool reuse_code) {
if (!log_->IsEnabled()) return; if (!log_->IsEnabled()) return;
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(*code, pc); Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(*code, pc);
ProcessDeoptEvent(code, info.position, Deoptimizer::MessageFor(kind), ProcessDeoptEvent(code, info.position,
Deoptimizer::MessageFor(kind, reuse_code),
DeoptimizeReasonToString(info.deopt_reason)); DeoptimizeReasonToString(info.deopt_reason));
} }
......
...@@ -213,7 +213,7 @@ class Logger : public CodeEventListener { ...@@ -213,7 +213,7 @@ class Logger : public CodeEventListener {
void CodeDisableOptEvent(Handle<AbstractCode> code, void CodeDisableOptEvent(Handle<AbstractCode> code,
Handle<SharedFunctionInfo> shared) override; Handle<SharedFunctionInfo> shared) override;
void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc, void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc,
int fp_to_sp_delta) override; int fp_to_sp_delta, bool reuse_code) override;
void CodeDependencyChangeEvent(Handle<Code> code, void CodeDependencyChangeEvent(Handle<Code> code,
Handle<SharedFunctionInfo> sfi, Handle<SharedFunctionInfo> sfi,
const char* reason) override; const char* reason) override;
...@@ -404,7 +404,7 @@ class V8_EXPORT_PRIVATE CodeEventLogger : public CodeEventListener { ...@@ -404,7 +404,7 @@ class V8_EXPORT_PRIVATE CodeEventLogger : public CodeEventListener {
void NativeContextMoveEvent(Address from, Address to) override {} void NativeContextMoveEvent(Address from, Address to) override {}
void CodeMovingGCEvent() override {} void CodeMovingGCEvent() override {}
void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc, void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc,
int fp_to_sp_delta) override {} int fp_to_sp_delta, bool reuse_code) override {}
void CodeDependencyChangeEvent(Handle<Code> code, void CodeDependencyChangeEvent(Handle<Code> code,
Handle<SharedFunctionInfo> sfi, Handle<SharedFunctionInfo> sfi,
const char* reason) override {} const char* reason) override {}
...@@ -467,7 +467,7 @@ class ExternalCodeEventListener : public CodeEventListener { ...@@ -467,7 +467,7 @@ class ExternalCodeEventListener : public CodeEventListener {
Handle<SharedFunctionInfo> shared) override {} Handle<SharedFunctionInfo> shared) override {}
void CodeMovingGCEvent() override {} void CodeMovingGCEvent() override {}
void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc, void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc,
int fp_to_sp_delta) override {} int fp_to_sp_delta, bool reuse_code) override {}
void CodeDependencyChangeEvent(Handle<Code> code, void CodeDependencyChangeEvent(Handle<Code> code,
Handle<SharedFunctionInfo> sfi, Handle<SharedFunctionInfo> sfi,
const char* reason) override {} const char* reason) override {}
......
...@@ -274,7 +274,10 @@ void ProfilerListener::CodeDisableOptEvent(Handle<AbstractCode> code, ...@@ -274,7 +274,10 @@ void ProfilerListener::CodeDisableOptEvent(Handle<AbstractCode> code,
} }
void ProfilerListener::CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, void ProfilerListener::CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind,
Address pc, int fp_to_sp_delta) { Address pc, int fp_to_sp_delta,
bool reuse_code) {
// When reuse_code is true it is just a bailout and not an actual deopt.
if (reuse_code) return;
CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT); CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT);
CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_; CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(*code, pc); Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(*code, pc);
......
...@@ -55,7 +55,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener { ...@@ -55,7 +55,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
void CodeDisableOptEvent(Handle<AbstractCode> code, void CodeDisableOptEvent(Handle<AbstractCode> code,
Handle<SharedFunctionInfo> shared) override; Handle<SharedFunctionInfo> shared) override;
void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc, void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc,
int fp_to_sp_delta) override; int fp_to_sp_delta, bool reuse_code) override;
void CodeDependencyChangeEvent(Handle<Code> code, void CodeDependencyChangeEvent(Handle<Code> code,
Handle<SharedFunctionInfo> sfi, Handle<SharedFunctionInfo> sfi,
const char* reason) override {} const char* reason) override {}
......
...@@ -157,6 +157,7 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) { ...@@ -157,6 +157,7 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
// code object from deoptimizer. // code object from deoptimizer.
Handle<Code> optimized_code = deoptimizer->compiled_code(); Handle<Code> optimized_code = deoptimizer->compiled_code();
DeoptimizeKind type = deoptimizer->deopt_kind(); DeoptimizeKind type = deoptimizer->deopt_kind();
bool should_reuse_code = deoptimizer->should_reuse_code();
// TODO(turbofan): We currently need the native context to materialize // TODO(turbofan): We currently need the native context to materialize
// the arguments object, but only to get to its map. // the arguments object, but only to get to its map.
...@@ -171,8 +172,7 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) { ...@@ -171,8 +172,7 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
JavaScriptFrame* top_frame = top_it.frame(); JavaScriptFrame* top_frame = top_it.frame();
isolate->set_context(Context::cast(top_frame->context())); isolate->set_context(Context::cast(top_frame->context()));
int count = optimized_code->deoptimization_count(); if (should_reuse_code) {
if (type == DeoptimizeKind::kSoft && count < FLAG_reuse_opt_code_count) {
optimized_code->increment_deoptimization_count(); optimized_code->increment_deoptimization_count();
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
} }
......
...@@ -1587,7 +1587,7 @@ RUNTIME_FUNCTION(Runtime_EnableCodeLoggingForTesting) { ...@@ -1587,7 +1587,7 @@ RUNTIME_FUNCTION(Runtime_EnableCodeLoggingForTesting) {
void CodeDisableOptEvent(Handle<AbstractCode> code, void CodeDisableOptEvent(Handle<AbstractCode> code,
Handle<SharedFunctionInfo> shared) final {} Handle<SharedFunctionInfo> shared) final {}
void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc, void CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind, Address pc,
int fp_to_sp_delta) final {} int fp_to_sp_delta, bool reuse_code) final {}
void CodeDependencyChangeEvent(Handle<Code> code, void CodeDependencyChangeEvent(Handle<Code> code,
Handle<SharedFunctionInfo> shared, Handle<SharedFunctionInfo> shared,
const char* reason) final {} const char* reason) final {}
......
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