diff options
Diffstat (limited to 'openjdkjvmti/ti_stack.cc')
-rw-r--r-- | openjdkjvmti/ti_stack.cc | 100 |
1 files changed, 90 insertions, 10 deletions
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc index 220ad22be5..3ba5d3a316 100644 --- a/openjdkjvmti/ti_stack.cc +++ b/openjdkjvmti/ti_stack.cc @@ -112,6 +112,23 @@ struct GetStackTraceVisitor : public art::StackVisitor { size_t stop; }; +art::ShadowFrame* FindFrameAtDepthVisitor::GetOrCreateShadowFrame(bool* created_frame) { + art::ShadowFrame* cur = GetCurrentShadowFrame(); + if (cur == nullptr) { + *created_frame = true; + art::ArtMethod* method = GetMethod(); + const uint16_t num_regs = method->DexInstructionData().RegistersSize(); + cur = GetThread()->FindOrCreateDebuggerShadowFrame(GetFrameId(), + num_regs, + method, + GetDexPc()); + DCHECK(cur != nullptr); + } else { + *created_frame = false; + } + return cur; +} + template <typename FrameFn> GetStackTraceVisitor<FrameFn> MakeStackTraceVisitor(art::Thread* thread_in, size_t start, @@ -1065,16 +1082,7 @@ jvmtiError StackUtil::NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth) // From here we are sure to succeed. bool needs_instrument = false; // Get/create a shadow frame - art::ShadowFrame* shadow_frame = visitor.GetCurrentShadowFrame(); - if (shadow_frame == nullptr) { - needs_instrument = true; - const size_t frame_id = visitor.GetFrameId(); - const uint16_t num_regs = method->DexInstructionData().RegistersSize(); - shadow_frame = target->FindOrCreateDebuggerShadowFrame(frame_id, - num_regs, - method, - visitor.GetDexPc()); - } + art::ShadowFrame* shadow_frame = visitor.GetOrCreateShadowFrame(&needs_instrument); { art::WriterMutexLock lk(self, tienv->event_info_mutex_); // Mark shadow frame as needs_notify_pop_ @@ -1089,4 +1097,76 @@ jvmtiError StackUtil::NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth) } while (true); } +jvmtiError StackUtil::PopFrame(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread thread) { + art::Thread* self = art::Thread::Current(); + art::Thread* target; + do { + ThreadUtil::SuspendCheck(self); + art::MutexLock ucsl_mu(self, *art::Locks::user_code_suspension_lock_); + // Make sure we won't be suspended in the middle of holding the thread_suspend_count_lock_ by a + // user-code suspension. We retry and do another SuspendCheck to clear this. + if (ThreadUtil::WouldSuspendForUserCodeLocked(self)) { + continue; + } + // From now on we know we cannot get suspended by user-code. + // NB This does a SuspendCheck (during thread state change) so we need to make sure we don't + // have the 'suspend_lock' locked here. + art::ScopedObjectAccess soa(self); + art::MutexLock tll_mu(self, *art::Locks::thread_list_lock_); + jvmtiError err = ERR(INTERNAL); + if (!ThreadUtil::GetAliveNativeThread(thread, soa, &target, &err)) { + return err; + } + { + art::MutexLock tscl_mu(self, *art::Locks::thread_suspend_count_lock_); + if (target == self || target->GetUserCodeSuspendCount() == 0) { + // We cannot be the current thread for this function. + return ERR(THREAD_NOT_SUSPENDED); + } + } + // We hold the user_code_suspension_lock_ so the target thread is staying suspended until we are + // done. + std::unique_ptr<art::Context> context(art::Context::Create()); + FindFrameAtDepthVisitor final_frame(target, context.get(), 0); + FindFrameAtDepthVisitor penultimate_frame(target, context.get(), 1); + final_frame.WalkStack(); + penultimate_frame.WalkStack(); + + if (!final_frame.FoundFrame() || !penultimate_frame.FoundFrame()) { + // Cannot do it if there is only one frame! + return ERR(NO_MORE_FRAMES); + } + + art::ArtMethod* called_method = final_frame.GetMethod(); + art::ArtMethod* calling_method = penultimate_frame.GetMethod(); + if (calling_method->IsNative() || called_method->IsNative()) { + return ERR(OPAQUE_FRAME); + } + // From here we are sure to succeed. + + // Get/create a shadow frame + bool created_final_frame = false; + bool created_penultimate_frame = false; + art::ShadowFrame* called_shadow_frame = + final_frame.GetOrCreateShadowFrame(&created_final_frame); + art::ShadowFrame* calling_shadow_frame = + penultimate_frame.GetOrCreateShadowFrame(&created_penultimate_frame); + + bool needs_instrument = created_penultimate_frame || created_final_frame; + + CHECK_NE(called_shadow_frame, calling_shadow_frame) + << "Frames at different depths not different!"; + + // Tell the shadow-frame to return immediately and skip all exit events. + called_shadow_frame->SetForcePopFrame(true); + calling_shadow_frame->SetForceRetryInstruction(true); + + // Make sure can we will go to the interpreter and use the shadow frames. + if (needs_instrument) { + art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(target); + } + return OK; + } while (true); +} + } // namespace openjdkjvmti |