7eed880d53
Instead of having special support for targeting catch entry as a lazy deoptimization target, split this into two independent operations: * Perform lazy deoptimization at call. * Rethrow the exception once deoptimization is complete. TEST=ci Change-Id: Ib275d615bc6717e1184e88602ae5459d5b771f2b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/361580 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Slava Egorov <vegorov@google.com>
117 lines
3.9 KiB
C++
117 lines
3.9 KiB
C++
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "vm/pending_deopts.h"
|
|
#include "vm/log.h"
|
|
#include "vm/stack_frame.h"
|
|
#include "vm/stub_code.h"
|
|
|
|
namespace dart {
|
|
|
|
DECLARE_FLAG(bool, trace_deoptimization);
|
|
|
|
PendingDeopts::PendingDeopts()
|
|
: pending_deopts_(new MallocGrowableArray<PendingLazyDeopt>()) {}
|
|
PendingDeopts::~PendingDeopts() {
|
|
delete pending_deopts_;
|
|
pending_deopts_ = nullptr;
|
|
}
|
|
|
|
void PendingDeopts::AddPendingDeopt(uword fp, uword pc) {
|
|
// GrowableArray::Add is not atomic and may be interrupted by a profiler
|
|
// stack walk.
|
|
MallocGrowableArray<PendingLazyDeopt>* old_pending_deopts = pending_deopts_;
|
|
MallocGrowableArray<PendingLazyDeopt>* new_pending_deopts =
|
|
new MallocGrowableArray<PendingLazyDeopt>(old_pending_deopts->length() +
|
|
1);
|
|
for (intptr_t i = 0; i < old_pending_deopts->length(); i++) {
|
|
ASSERT((*old_pending_deopts)[i].fp() != fp);
|
|
new_pending_deopts->Add((*old_pending_deopts)[i]);
|
|
}
|
|
PendingLazyDeopt deopt(fp, pc);
|
|
new_pending_deopts->Add(deopt);
|
|
|
|
pending_deopts_ = new_pending_deopts;
|
|
delete old_pending_deopts;
|
|
}
|
|
|
|
PendingLazyDeopt* PendingDeopts::FindPendingDeoptRecord(uword fp) {
|
|
for (intptr_t i = 0; i < pending_deopts_->length(); i++) {
|
|
if ((*pending_deopts_)[i].fp() == fp) {
|
|
return &(*pending_deopts_)[i];
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
uword PendingDeopts::FindPendingDeopt(uword fp) {
|
|
auto record = FindPendingDeoptRecord(fp);
|
|
if (record != nullptr) {
|
|
return record->pc();
|
|
}
|
|
FATAL("Missing pending deopt entry");
|
|
return 0;
|
|
}
|
|
|
|
void PendingDeopts::ClearPendingDeoptsBelow(uword fp, ClearReason reason) {
|
|
for (intptr_t i = pending_deopts_->length() - 1; i >= 0; i--) {
|
|
if ((*pending_deopts_)[i].fp() < fp) {
|
|
if (FLAG_trace_deoptimization) {
|
|
switch (reason) {
|
|
case kClearDueToThrow:
|
|
THR_Print(
|
|
"Lazy deopt skipped due to throw for "
|
|
"fp=%" Pp ", pc=%" Pp "\n",
|
|
(*pending_deopts_)[i].fp(), (*pending_deopts_)[i].pc());
|
|
break;
|
|
case kClearDueToDeopt:
|
|
THR_Print("Lazy deopt fp=%" Pp " pc=%" Pp "\n",
|
|
(*pending_deopts_)[i].fp(), (*pending_deopts_)[i].pc());
|
|
break;
|
|
}
|
|
}
|
|
pending_deopts_->RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PendingDeopts::ClearPendingDeoptsAtOrBelow(uword fp, ClearReason reason) {
|
|
ClearPendingDeoptsBelow(fp + kWordSize, reason);
|
|
}
|
|
|
|
uword PendingDeopts::RemapExceptionPCForDeopt(uword program_counter,
|
|
uword frame_pointer,
|
|
bool* clear_deopt) {
|
|
*clear_deopt = false;
|
|
|
|
// Do not attempt to deopt at async exception handler as it doesn't
|
|
// belong to the function code. Async handler never continues execution
|
|
// in the same frame - it either rethrows exception to the caller or
|
|
// tail calls Dart handler, leaving the function frame before the call.
|
|
if (program_counter == StubCode::AsyncExceptionHandler().EntryPoint()) {
|
|
*clear_deopt = true;
|
|
return program_counter;
|
|
}
|
|
|
|
// Check if the target frame is scheduled for lazy deopt.
|
|
if (FindPendingDeoptRecord(frame_pointer) != nullptr) {
|
|
#if defined(DEBUG)
|
|
// Ensure the frame references optimized code.
|
|
ObjectPtr pc_marker = *(reinterpret_cast<ObjectPtr*>(
|
|
frame_pointer + runtime_frame_layout.code_from_fp * kWordSize));
|
|
Code& code = Code::Handle(Code::RawCast(pc_marker));
|
|
ASSERT(code.is_optimized() && !code.is_force_optimized());
|
|
#endif
|
|
if (FLAG_trace_deoptimization) {
|
|
THR_Print("Throwing to frame scheduled for lazy deopt fp=%" Pp "\n",
|
|
frame_pointer);
|
|
}
|
|
return StubCode::DeoptimizeLazyFromThrow().EntryPoint();
|
|
}
|
|
|
|
return program_counter;
|
|
}
|
|
|
|
} // namespace dart
|