mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
![Alexander Markov](/assets/img/avatar_default.png)
The new implementation is based on suspend/resume stubs and doesn't use desugaring of async functions on kernel AST. Previously, new implementation of async/async* was only supported in AOT mode. This change adds all necessary bits for the JIT mode: * Suspending variable-length frames (for unoptimized code). * Handling of Code and pool pointers in Dart stack frames. * OSR. * Deoptimization. * Hot reload. * Debugger. The new implementation is not enabled in JIT mode yet. Design doc: go/compact-async-await. TEST=ci Issue: https://github.com/dart-lang/sdk/issues/48378 Change-Id: I477d6684bdce7cbc1edb179ae2271ff598b7dcc5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/246081 Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
115 lines
4 KiB
C++
115 lines
4 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;
|
|
}
|
|
|
|
uword PendingDeopts::FindPendingDeopt(uword fp) {
|
|
for (intptr_t i = 0; i < pending_deopts_->length(); i++) {
|
|
if ((*pending_deopts_)[i].fp() == fp) {
|
|
return (*pending_deopts_)[i].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.
|
|
for (intptr_t i = 0; i < pending_deopts_->length(); i++) {
|
|
if ((*pending_deopts_)[i].fp() == frame_pointer) {
|
|
// Deopt should now resume in the catch handler instead of after the
|
|
// call.
|
|
(*pending_deopts_)[i].set_pc(program_counter);
|
|
|
|
// Jump to the deopt stub instead of the catch handler.
|
|
program_counter = StubCode::DeoptimizeLazyFromThrow().EntryPoint();
|
|
if (FLAG_trace_deoptimization) {
|
|
THR_Print("Throwing to frame scheduled for lazy deopt fp=%" Pp "\n",
|
|
frame_pointer);
|
|
|
|
#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
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return program_counter;
|
|
}
|
|
|
|
} // namespace dart
|