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
// Deoptimization bailouts are stored as runtime entries.
DeoptimizeKind type;
if (Deoptimizer::IsDeoptimizationEntry(isolate, target_address(), &type)) {
os << " (" << Deoptimizer::MessageFor(type)
os << " (" << Deoptimizer::MessageFor(type, false)
<< " deoptimization bailout)";
}
} else if (IsConstPool(rmode_)) {
......
......@@ -466,14 +466,16 @@ void Deoptimizer::ComputeOutputFrames(Deoptimizer* deoptimizer) {
deoptimizer->DoComputeOutputFrames();
}
const char* Deoptimizer::MessageFor(DeoptimizeKind kind) {
const char* Deoptimizer::MessageFor(DeoptimizeKind kind, bool reuse_code) {
switch (kind) {
case DeoptimizeKind::kEager:
return "eager";
DCHECK(!reuse_code);
return "deopt-eager";
case DeoptimizeKind::kSoft:
return "soft";
return reuse_code ? "bailout-soft" : "deopt-soft";
case DeoptimizeKind::kLazy:
return "lazy";
DCHECK(!reuse_code);
return "deopt-lazy";
}
FATAL("Unsupported deopt kind");
return nullptr;
......@@ -536,8 +538,9 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction function,
compiled_code_.set_deopt_already_counted(true);
{
HandleScope scope(isolate_);
PROFILE(isolate_, CodeDeoptEvent(handle(compiled_code_, isolate_), kind,
from_, fp_to_sp_delta_));
PROFILE(isolate_,
CodeDeoptEvent(handle(compiled_code_, isolate_), kind, from_,
fp_to_sp_delta_, should_reuse_code()));
}
unsigned size = ComputeInputFrameSize();
const int parameter_count =
......@@ -600,6 +603,12 @@ Handle<Code> Deoptimizer::compiled_code() const {
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() {
DCHECK(input_ == nullptr && output_ == nullptr);
DCHECK_NULL(disallow_heap_allocation_);
......@@ -748,8 +757,8 @@ void Deoptimizer::DoComputeOutputFrames() {
if (trace_scope_ != nullptr) {
timer.Start();
PrintF(trace_scope_->file(), "[deoptimizing (DEOPT %s): begin ",
MessageFor(deopt_kind_));
PrintF(trace_scope_->file(), "[bailout (kind: %s): begin ",
MessageFor(deopt_kind_, should_reuse_code()));
PrintFunctionName();
PrintF(trace_scope_->file(),
" (opt #%d) @%d, FP to SP delta: %d, caller sp: " V8PRIxPTR_FMT
......@@ -850,8 +859,8 @@ void Deoptimizer::DoComputeOutputFrames() {
if (trace_scope_ != nullptr) {
double ms = timer.Elapsed().InMillisecondsF();
int index = output_count_ - 1; // Index of the topmost frame.
PrintF(trace_scope_->file(), "[deoptimizing (%s): end ",
MessageFor(deopt_kind_));
PrintF(trace_scope_->file(), "[bailout (kind: %s): end ",
MessageFor(deopt_kind_, should_reuse_code()));
PrintFunctionName();
PrintF(trace_scope_->file(),
" @%d => node=%d, pc=" V8PRIxPTR_FMT
......
......@@ -444,7 +444,7 @@ class Deoptimizer : public Malloced {
static int ComputeSourcePositionFromBytecodeArray(SharedFunctionInfo shared,
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_; }
......@@ -455,6 +455,8 @@ class Deoptimizer : public Malloced {
// Number of created JS frames. Not all created frames are necessarily JS.
int jsframe_count() const { return jsframe_count_; }
bool should_reuse_code() const;
static Deoptimizer* New(Address raw_function, DeoptimizeKind kind,
unsigned bailout_id, Address from, int fp_to_sp_delta,
Isolate* isolate);
......
......@@ -260,7 +260,7 @@ static void PrintRelocInfo(StringBuilder* out, Isolate* isolate,
DeoptimizeKind type;
if (Deoptimizer::IsDeoptimizationEntry(isolate, addr, &type)) {
out->AddFormatted(" ;; %s deoptimization bailout",
Deoptimizer::MessageFor(type));
Deoptimizer::MessageFor(type, false));
} else {
out->AddFormatted(" ;; %s", RelocInfo::RelocModeName(rmode));
}
......
......@@ -99,7 +99,8 @@ class CodeEventListener {
virtual void CodeDisableOptEvent(Handle<AbstractCode> code,
Handle<SharedFunctionInfo> shared) = 0;
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
// or 2. a weakly embedded object dies.
virtual void CodeDependencyChangeEvent(Handle<Code> code,
......@@ -220,9 +221,9 @@ class CodeEventDispatcher : public CodeEventListener {
});
}
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) {
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,
......
......@@ -1401,10 +1401,11 @@ void Logger::ProcessDeoptEvent(Handle<Code> code, SourcePosition position,
}
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;
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));
}
......
......@@ -213,7 +213,7 @@ class Logger : public CodeEventListener {
void CodeDisableOptEvent(Handle<AbstractCode> code,
Handle<SharedFunctionInfo> shared) override;
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,
Handle<SharedFunctionInfo> sfi,
const char* reason) override;
......@@ -404,7 +404,7 @@ class V8_EXPORT_PRIVATE CodeEventLogger : public CodeEventListener {
void NativeContextMoveEvent(Address from, Address to) override {}
void CodeMovingGCEvent() override {}
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,
Handle<SharedFunctionInfo> sfi,
const char* reason) override {}
......@@ -467,7 +467,7 @@ class ExternalCodeEventListener : public CodeEventListener {
Handle<SharedFunctionInfo> shared) override {}
void CodeMovingGCEvent() override {}
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,
Handle<SharedFunctionInfo> sfi,
const char* reason) override {}
......
......@@ -274,7 +274,10 @@ void ProfilerListener::CodeDisableOptEvent(Handle<AbstractCode> code,
}
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);
CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(*code, pc);
......
......@@ -55,7 +55,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
void CodeDisableOptEvent(Handle<AbstractCode> code,
Handle<SharedFunctionInfo> shared) override;
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,
Handle<SharedFunctionInfo> sfi,
const char* reason) override {}
......
......@@ -157,6 +157,7 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
// code object from deoptimizer.
Handle<Code> optimized_code = deoptimizer->compiled_code();
DeoptimizeKind type = deoptimizer->deopt_kind();
bool should_reuse_code = deoptimizer->should_reuse_code();
// TODO(turbofan): We currently need the native context to materialize
// the arguments object, but only to get to its map.
......@@ -171,8 +172,7 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
JavaScriptFrame* top_frame = top_it.frame();
isolate->set_context(Context::cast(top_frame->context()));
int count = optimized_code->deoptimization_count();
if (type == DeoptimizeKind::kSoft && count < FLAG_reuse_opt_code_count) {
if (should_reuse_code) {
optimized_code->increment_deoptimization_count();
return ReadOnlyRoots(isolate).undefined_value();
}
......
......@@ -1587,7 +1587,7 @@ RUNTIME_FUNCTION(Runtime_EnableCodeLoggingForTesting) {
void CodeDisableOptEvent(Handle<AbstractCode> code,
Handle<SharedFunctionInfo> shared) final {}
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,
Handle<SharedFunctionInfo> shared,
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