summaryrefslogtreecommitdiff
path: root/openjdkjvmti/ti_stack.cc
diff options
context:
space:
mode:
Diffstat (limited to 'openjdkjvmti/ti_stack.cc')
-rw-r--r--openjdkjvmti/ti_stack.cc100
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