// 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()) {} 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* old_pending_deopts = pending_deopts_; MallocGrowableArray* new_pending_deopts = new MallocGrowableArray(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) { // 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( 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