ART: Add GetAllStackTraces
Add support for GetAllStackTraces. Add a test.
Bug: 31684812
Test: m test-art-host-run-test-911-get-stack-trace
Change-Id: I81f783a6b37bfc7b68c10ba6c803a11e1bd5d350
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index c52dd76..cf9e2e8 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -237,7 +237,7 @@
jint max_frame_count,
jvmtiStackInfo** stack_info_ptr,
jint* thread_count_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ return StackUtil::GetAllStackTraces(env, max_frame_count, stack_info_ptr, thread_count_ptr);
}
static jvmtiError GetThreadListStackTraces(jvmtiEnv* env,
diff --git a/runtime/openjdkjvmti/ti_stack.cc b/runtime/openjdkjvmti/ti_stack.cc
index 579fb50..e33ea5f 100644
--- a/runtime/openjdkjvmti/ti_stack.cc
+++ b/runtime/openjdkjvmti/ti_stack.cc
@@ -31,9 +31,15 @@
#include "ti_stack.h"
+#include <list>
+#include <unordered_map>
+#include <vector>
+
#include "art_jvmti.h"
#include "art_method-inl.h"
+#include "base/bit_utils.h"
#include "base/enums.h"
+#include "base/mutex.h"
#include "dex_file.h"
#include "dex_file_annotations.h"
#include "jni_env_ext.h"
@@ -41,19 +47,19 @@
#include "mirror/class.h"
#include "mirror/dex_cache.h"
#include "scoped_thread_state_change-inl.h"
+#include "ScopedLocalRef.h"
#include "stack.h"
-#include "thread.h"
+#include "thread-inl.h"
+#include "thread_list.h"
#include "thread_pool.h"
namespace openjdkjvmti {
struct GetStackTraceVisitor : public art::StackVisitor {
GetStackTraceVisitor(art::Thread* thread_in,
- art::ScopedObjectAccessAlreadyRunnable& soa_,
size_t start_,
size_t stop_)
: StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- soa(soa_),
start(start_),
stop(stop_) {}
@@ -85,7 +91,6 @@
return true;
}
- art::ScopedObjectAccessAlreadyRunnable& soa;
std::vector<jvmtiFrameInfo> frames;
size_t start;
size_t stop;
@@ -99,10 +104,8 @@
start_result(0),
stop_result(0) {}
- void Run(art::Thread* self) OVERRIDE {
- art::ScopedObjectAccess soa(art::Thread::Current());
-
- GetStackTraceVisitor visitor(self, soa, start_input, stop_input);
+ void Run(art::Thread* self) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ GetStackTraceVisitor visitor(self, start_input, stop_input);
visitor.WalkStack(false);
frames.swap(visitor.frames);
@@ -118,6 +121,44 @@
size_t stop_result;
};
+static jvmtiError TranslateFrameVector(const std::vector<jvmtiFrameInfo>& frames,
+ jint start_depth,
+ size_t start_result,
+ jint max_frame_count,
+ jvmtiFrameInfo* frame_buffer,
+ jint* count_ptr) {
+ size_t collected_frames = frames.size();
+
+ // Assume we're here having collected something.
+ DCHECK_GT(max_frame_count, 0);
+
+ // Frames from the top.
+ if (start_depth >= 0) {
+ if (start_result != 0) {
+ // Not enough frames.
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+ DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
+ if (frames.size() > 0) {
+ memcpy(frame_buffer, frames.data(), collected_frames * sizeof(jvmtiFrameInfo));
+ }
+ *count_ptr = static_cast<jint>(frames.size());
+ return ERR(NONE);
+ }
+
+ // Frames from the bottom.
+ if (collected_frames < static_cast<size_t>(-start_depth)) {
+ return ERR(ILLEGAL_ARGUMENT);
+ }
+
+ size_t count = std::min(static_cast<size_t>(-start_depth), static_cast<size_t>(max_frame_count));
+ memcpy(frame_buffer,
+ &frames.data()[collected_frames + start_depth],
+ count * sizeof(jvmtiFrameInfo));
+ *count_ptr = static_cast<jint>(count);
+ return ERR(NONE);
+}
+
jvmtiError StackUtil::GetStackTrace(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED,
jthread java_thread,
jint start_depth,
@@ -157,35 +198,174 @@
}
GetStackTraceClosure closure(start_depth >= 0 ? static_cast<size_t>(start_depth) : 0,
- start_depth >= 0 ?static_cast<size_t>(max_frame_count) : 0);
+ start_depth >= 0 ? static_cast<size_t>(max_frame_count) : 0);
thread->RequestSynchronousCheckpoint(&closure);
- size_t collected_frames = closure.frames.size();
+ return TranslateFrameVector(closure.frames,
+ start_depth,
+ closure.start_result,
+ max_frame_count,
+ frame_buffer,
+ count_ptr);
+}
- // Frames from the top.
- if (start_depth >= 0) {
- if (closure.start_result != 0) {
- // Not enough frames.
- return ERR(ILLEGAL_ARGUMENT);
- }
- DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
- if (closure.frames.size() > 0) {
- memcpy(frame_buffer, closure.frames.data(), collected_frames * sizeof(jvmtiFrameInfo));
- }
- *count_ptr = static_cast<jint>(closure.frames.size());
- return ERR(NONE);
+struct GetAllStackTraceClosure : public art::Closure {
+ public:
+ explicit GetAllStackTraceClosure(size_t stop)
+ : start_input(0),
+ stop_input(stop),
+ frames_lock("GetAllStackTraceGuard", art::LockLevel::kAbortLock),
+ start_result(0),
+ stop_result(0) {}
+
+ void Run(art::Thread* self)
+ OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) REQUIRES(!frames_lock) {
+ // self should be live here (so it could be suspended). No need to filter.
+
+ art::Thread* current = art::Thread::Current();
+ std::vector<jvmtiFrameInfo> self_frames;
+
+ GetStackTraceVisitor visitor(self, start_input, stop_input);
+ visitor.WalkStack(false);
+
+ self_frames.swap(visitor.frames);
+
+ art::MutexLock mu(current, frames_lock);
+ frames.emplace(self, self_frames);
}
- // Frames from the bottom.
- if (collected_frames < static_cast<size_t>(-start_depth)) {
+ const size_t start_input;
+ const size_t stop_input;
+
+ art::Mutex frames_lock;
+ std::unordered_map<art::Thread*, std::vector<jvmtiFrameInfo>> frames GUARDED_BY(frames_lock);
+ size_t start_result;
+ size_t stop_result;
+};
+
+
+
+jvmtiError StackUtil::GetAllStackTraces(jvmtiEnv* env,
+ jint max_frame_count,
+ jvmtiStackInfo** stack_info_ptr,
+ jint* thread_count_ptr) {
+ if (max_frame_count < 0) {
return ERR(ILLEGAL_ARGUMENT);
}
+ if (stack_info_ptr == nullptr || thread_count_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
- size_t count = std::min(static_cast<size_t>(-start_depth), static_cast<size_t>(max_frame_count));
- memcpy(frame_buffer,
- &closure.frames.data()[collected_frames + start_depth],
- count * sizeof(jvmtiFrameInfo));
- *count_ptr = static_cast<jint>(count);
+
+ art::Thread* current = art::Thread::Current();
+ art::ScopedObjectAccess soa(current); // Now we know we have the shared lock.
+ art::ScopedThreadSuspension sts(current, art::kWaitingForDebuggerSuspension);
+ art::ScopedSuspendAll ssa("GetAllStackTraces");
+
+ std::vector<art::Thread*> threads;
+ std::vector<std::vector<jvmtiFrameInfo>> frames;
+ {
+ std::list<art::Thread*> thread_list;
+ {
+ art::MutexLock mu(current, *art::Locks::thread_list_lock_);
+ thread_list = art::Runtime::Current()->GetThreadList()->GetList();
+ }
+
+ for (art::Thread* thread : thread_list) {
+ GetStackTraceClosure closure(0u, static_cast<size_t>(max_frame_count));
+ thread->RequestSynchronousCheckpoint(&closure);
+
+ threads.push_back(thread);
+ frames.emplace_back();
+ frames.back().swap(closure.frames);
+ }
+ }
+
+ // Convert the data into our output format. Note: we need to keep the threads suspended,
+ // as we need to access them for their peers.
+
+ // Note: we use an array of jvmtiStackInfo for convenience. The spec says we need to
+ // allocate one big chunk for this and the actual frames, which means we need
+ // to either be conservative or rearrange things later (the latter is implemented).
+ std::unique_ptr<jvmtiStackInfo[]> stack_info_array(new jvmtiStackInfo[frames.size()]);
+ std::vector<std::unique_ptr<jvmtiFrameInfo[]>> frame_infos;
+ frame_infos.reserve(frames.size());
+
+ // Now run through and add data for each thread.
+ size_t sum_frames = 0;
+ for (size_t index = 0; index < frames.size(); ++index) {
+ jvmtiStackInfo& stack_info = stack_info_array.get()[index];
+ memset(&stack_info, 0, sizeof(jvmtiStackInfo));
+
+ art::Thread* self = threads[index];
+ const std::vector<jvmtiFrameInfo>& thread_frames = frames[index];
+
+ // For the time being, set the thread to null. We don't have good ScopedLocalRef
+ // infrastructure.
+ DCHECK(self->GetPeer() != nullptr);
+ stack_info.thread = nullptr;
+ stack_info.state = JVMTI_THREAD_STATE_SUSPENDED;
+
+ size_t collected_frames = thread_frames.size();
+ if (max_frame_count == 0 || collected_frames == 0) {
+ stack_info.frame_count = 0;
+ stack_info.frame_buffer = nullptr;
+ continue;
+ }
+ DCHECK_LE(collected_frames, static_cast<size_t>(max_frame_count));
+
+ jvmtiFrameInfo* frame_info = new jvmtiFrameInfo[collected_frames];
+ frame_infos.emplace_back(frame_info);
+
+ jint count;
+ jvmtiError translate_result = TranslateFrameVector(thread_frames,
+ 0,
+ 0,
+ static_cast<jint>(collected_frames),
+ frame_info,
+ &count);
+ DCHECK(translate_result == JVMTI_ERROR_NONE);
+ stack_info.frame_count = static_cast<jint>(collected_frames);
+ stack_info.frame_buffer = frame_info;
+ sum_frames += static_cast<size_t>(count);
+ }
+
+ // No errors, yet. Now put it all into an output buffer.
+ size_t rounded_stack_info_size = art::RoundUp(sizeof(jvmtiStackInfo) * frames.size(),
+ alignof(jvmtiFrameInfo));
+ size_t chunk_size = rounded_stack_info_size + sum_frames * sizeof(jvmtiFrameInfo);
+ unsigned char* chunk_data;
+ jvmtiError alloc_result = env->Allocate(chunk_size, &chunk_data);
+ if (alloc_result != ERR(NONE)) {
+ return alloc_result;
+ }
+
+ jvmtiStackInfo* stack_info = reinterpret_cast<jvmtiStackInfo*>(chunk_data);
+ // First copy in all the basic data.
+ memcpy(stack_info, stack_info_array.get(), sizeof(jvmtiStackInfo) * frames.size());
+
+ // Now copy the frames and fix up the pointers.
+ jvmtiFrameInfo* frame_info = reinterpret_cast<jvmtiFrameInfo*>(
+ chunk_data + rounded_stack_info_size);
+ for (size_t i = 0; i < frames.size(); ++i) {
+ jvmtiStackInfo& old_stack_info = stack_info_array.get()[i];
+ jvmtiStackInfo& new_stack_info = stack_info[i];
+
+ jthread thread_peer = current->GetJniEnv()->AddLocalReference<jthread>(threads[i]->GetPeer());
+ new_stack_info.thread = thread_peer;
+
+ if (old_stack_info.frame_count > 0) {
+ // Only copy when there's data - leave the nullptr alone.
+ size_t frames_size = static_cast<size_t>(old_stack_info.frame_count) * sizeof(jvmtiFrameInfo);
+ memcpy(frame_info, old_stack_info.frame_buffer, frames_size);
+ new_stack_info.frame_buffer = frame_info;
+ frame_info += old_stack_info.frame_count;
+ }
+ }
+
+ *stack_info_ptr = stack_info;
+ *thread_count_ptr = static_cast<jint>(frames.size());
+
return ERR(NONE);
}
diff --git a/runtime/openjdkjvmti/ti_stack.h b/runtime/openjdkjvmti/ti_stack.h
index 1931ed3..7619f98 100644
--- a/runtime/openjdkjvmti/ti_stack.h
+++ b/runtime/openjdkjvmti/ti_stack.h
@@ -32,12 +32,21 @@
#ifndef ART_RUNTIME_OPENJDKJVMTI_TI_STACK_H_
#define ART_RUNTIME_OPENJDKJVMTI_TI_STACK_H_
+#include "jni.h"
#include "jvmti.h"
+#include "base/mutex.h"
+
namespace openjdkjvmti {
class StackUtil {
public:
+ static jvmtiError GetAllStackTraces(jvmtiEnv* env,
+ jint max_frame_count,
+ jvmtiStackInfo** stack_info_ptr,
+ jint* thread_count_ptr)
+ REQUIRES(!art::Locks::thread_list_lock_);
+
static jvmtiError GetStackTrace(jvmtiEnv* env,
jthread thread,
jint start_depth,
diff --git a/test/911-get-stack-trace/expected.txt b/test/911-get-stack-trace/expected.txt
index f8c97ce..284a071 100644
--- a/test/911-get-stack-trace/expected.txt
+++ b/test/911-get-stack-trace/expected.txt
@@ -4,72 +4,72 @@
From top
---------
getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2
- print (Ljava/lang/Thread;II)V 0 124
- printOrWait (IILMain$ControlData;)V 6 151
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- doTest ()V 38 34
- main ([Ljava/lang/String;)V 6 24
+ print (Ljava/lang/Thread;II)V 0 172
+ printOrWait (IILMain$ControlData;)V 6 235
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ doTest ()V 38 41
+ main ([Ljava/lang/String;)V 6 27
---------
- print (Ljava/lang/Thread;II)V 0 124
- printOrWait (IILMain$ControlData;)V 6 151
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- doTest ()V 42 35
- main ([Ljava/lang/String;)V 6 24
+ print (Ljava/lang/Thread;II)V 0 172
+ printOrWait (IILMain$ControlData;)V 6 235
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ doTest ()V 42 42
+ main ([Ljava/lang/String;)V 6 27
---------
getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2
- print (Ljava/lang/Thread;II)V 0 124
- printOrWait (IILMain$ControlData;)V 6 151
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
+ print (Ljava/lang/Thread;II)V 0 172
+ printOrWait (IILMain$ControlData;)V 6 235
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
---------
- printOrWait (IILMain$ControlData;)V 6 151
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
+ printOrWait (IILMain$ControlData;)V 6 235
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
From bottom
---------
- main ([Ljava/lang/String;)V 6 24
+ main ([Ljava/lang/String;)V 6 27
---------
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- doTest ()V 65 41
- main ([Ljava/lang/String;)V 6 24
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ doTest ()V 65 48
+ main ([Ljava/lang/String;)V 6 27
---------
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
################################
### Other thread (suspended) ###
@@ -77,132 +77,519 @@
From top
---------
wait ()V -1 -2
- printOrWait (IILMain$ControlData;)V 24 157
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 54
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 61
---------
- printOrWait (IILMain$ControlData;)V 24 157
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 54
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 61
---------
wait ()V -1 -2
- printOrWait (IILMain$ControlData;)V 24 157
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
---------
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
From bottom
---------
- run ()V 4 54
+ run ()V 4 61
---------
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 54
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 61
---------
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
###########################
### Other thread (live) ###
###########################
From top
---------
- printOrWait (IILMain$ControlData;)V 44 164
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 88
+ printOrWait (IILMain$ControlData;)V 44 248
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 95
---------
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 88
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 95
---------
- printOrWait (IILMain$ControlData;)V 44 164
- baz (IIILMain$ControlData;)Ljava/lang/Object; 2 142
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
+ printOrWait (IILMain$ControlData;)V 44 248
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
---------
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
From bottom
---------
- run ()V 4 88
+ run ()V 4 95
---------
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- run ()V 4 88
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 95
---------
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
- foo (IIILMain$ControlData;)I 0 131
- baz (IIILMain$ControlData;)Ljava/lang/Object; 9 144
- bar (IIILMain$ControlData;)J 0 136
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+
+################################
+### Other threads (suspended) ###
+################################
+---------
+FinalizerDaemon
+<not printed>
+---------
+FinalizerWatchdogDaemon
+<not printed>
+---------
+HeapTaskDaemon
+<not printed>
+---------
+ReferenceQueueDaemon
+<not printed>
+---------
+Signal Catcher
+
+---------
+Thread-10
+
+---------
+Thread-11
+
+---------
+Thread-2
+
+---------
+Thread-3
+
+---------
+Thread-4
+
+---------
+Thread-5
+
+---------
+Thread-6
+
+---------
+Thread-7
+
+---------
+Thread-8
+
+---------
+Thread-9
+
+---------
+main
+
+---------
+FinalizerDaemon
+<not printed>
+---------
+FinalizerWatchdogDaemon
+<not printed>
+---------
+HeapTaskDaemon
+<not printed>
+---------
+ReferenceQueueDaemon
+<not printed>
+---------
+Signal Catcher
+
+---------
+Thread-10
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+
+---------
+Thread-11
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+
+---------
+Thread-2
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+
+---------
+Thread-3
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+
+---------
+Thread-4
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+
+---------
+Thread-5
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+
+---------
+Thread-6
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+
+---------
+Thread-7
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+
+---------
+Thread-8
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+
+---------
+Thread-9
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+
+---------
+main
+ getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
+ printAll (I)V 0 208
+ doTestAllStackTraces ()V 81 147
+ main ([Ljava/lang/String;)V 15 31
+
+---------
+FinalizerDaemon
+<not printed>
+---------
+FinalizerWatchdogDaemon
+<not printed>
+---------
+HeapTaskDaemon
+<not printed>
+---------
+ReferenceQueueDaemon
+<not printed>
+---------
+Signal Catcher
+
+---------
+Thread-10
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 135
+
+---------
+Thread-11
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 135
+
+---------
+Thread-2
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 135
+
+---------
+Thread-3
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 135
+
+---------
+Thread-4
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 135
+
+---------
+Thread-5
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 135
+
+---------
+Thread-6
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 135
+
+---------
+Thread-7
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 135
+
+---------
+Thread-8
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 135
+
+---------
+Thread-9
+ wait ()V -1 -2
+ printOrWait (IILMain$ControlData;)V 24 241
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 2 226
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ baz (IIILMain$ControlData;)Ljava/lang/Object; 9 228
+ bar (IIILMain$ControlData;)J 0 220
+ foo (IIILMain$ControlData;)I 0 215
+ run ()V 4 135
+
+---------
+main
+ getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
+ printAll (I)V 0 208
+ doTestAllStackTraces ()V 86 149
+ main ([Ljava/lang/String;)V 15 31
+
+Done
diff --git a/test/911-get-stack-trace/src/Main.java b/test/911-get-stack-trace/src/Main.java
index 722bee8..500e945 100644
--- a/test/911-get-stack-trace/src/Main.java
+++ b/test/911-get-stack-trace/src/Main.java
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
public class Main {
@@ -24,6 +27,10 @@
doTest();
doTestOtherThreadWait();
doTestOtherThreadBusyLoop();
+
+ doTestAllStackTraces();
+
+ System.out.println("Done");
}
public static void doTest() throws Exception {
@@ -109,6 +116,47 @@
t.join();
}
+ public static void doTestAllStackTraces() throws Exception {
+ System.out.println();
+ System.out.println("################################");
+ System.out.println("### Other threads (suspended) ###");
+ System.out.println("################################");
+
+ final int N = 10;
+
+ final ControlData data = new ControlData(N);
+ data.waitFor = new Object();
+
+ Thread threads[] = new Thread[N];
+
+ for (int i = 0; i < N; i++) {
+ Thread t = new Thread() {
+ public void run() {
+ Recurse.foo(4, 0, 0, data);
+ }
+ };
+ t.start();
+ threads[i] = t;
+ }
+ data.reached.await();
+ Thread.yield();
+ Thread.sleep(500); // A little bit of time...
+
+ printAll(0);
+
+ printAll(5);
+
+ printAll(25);
+
+ // Let the thread make progress and die.
+ synchronized(data.waitFor) {
+ data.waitFor.notifyAll();
+ }
+ for (int i = 0; i < N; i++) {
+ threads[i].join();
+ }
+ }
+
public static void print(String[][] stack) {
System.out.println("---------");
for (String[] stackElement : stack) {
@@ -124,6 +172,42 @@
print(getStackTrace(t, start, max));
}
+ public static void printAll(Object[][] stacks) {
+ List<String> stringified = new ArrayList<String>(stacks.length);
+
+ for (Object[] stackInfo : stacks) {
+ Thread t = (Thread)stackInfo[0];
+ String name = (t != null) ? t.getName() : "null";
+ String stackSerialization;
+ if (name.contains("Daemon")) {
+ // Do not print daemon stacks, as they're non-deterministic.
+ stackSerialization = "<not printed>";
+ } else {
+ StringBuilder sb = new StringBuilder();
+ for (String[] stackElement : (String[][])stackInfo[1]) {
+ for (String part : stackElement) {
+ sb.append(' ');
+ sb.append(part);
+ }
+ sb.append('\n');
+ }
+ stackSerialization = sb.toString();
+ }
+ stringified.add(name + "\n" + stackSerialization);
+ }
+
+ Collections.sort(stringified);
+
+ for (String s : stringified) {
+ System.out.println("---------");
+ System.out.println(s);
+ }
+ }
+
+ public static void printAll(int max) {
+ printAll(getAllStackTraces(max));
+ }
+
// Wrap generated stack traces into a class to separate them nicely.
public static class Recurse {
@@ -170,10 +254,22 @@
}
public static class ControlData {
- CountDownLatch reached = new CountDownLatch(1);
+ CountDownLatch reached;
Object waitFor = null;
volatile boolean stop = false;
+
+ public ControlData() {
+ this(1);
+ }
+
+ public ControlData(int latchCount) {
+ reached = new CountDownLatch(latchCount);
+ }
}
public static native String[][] getStackTrace(Thread thread, int start, int max);
+ // Get all stack traces. This will return an array with an element for each thread. The element
+ // is an array itself with the first element being the thread, and the second element a nested
+ // String array as in getStackTrace.
+ public static native Object[][] getAllStackTraces(int max);
}
diff --git a/test/911-get-stack-trace/stack_trace.cc b/test/911-get-stack-trace/stack_trace.cc
index cca163b..57d4f6d 100644
--- a/test/911-get-stack-trace/stack_trace.cc
+++ b/test/911-get-stack-trace/stack_trace.cc
@@ -50,22 +50,9 @@
return line_number;
}
-extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getStackTrace(
- JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thread, jint start, jint max) {
- std::unique_ptr<jvmtiFrameInfo[]> frames(new jvmtiFrameInfo[max]);
-
- jint count;
- {
- jvmtiError result = jvmti_env->GetStackTrace(thread, start, max, frames.get(), &count);
- if (result != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(result, &err);
- printf("Failure running GetStackTrace: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- return nullptr;
- }
- }
-
+static jobjectArray TranslateJvmtiFrameInfoArray(JNIEnv* env,
+ jvmtiFrameInfo* frames,
+ jint count) {
auto callback = [&](jint method_index) -> jobjectArray {
char* name;
char* sig;
@@ -140,5 +127,58 @@
return CreateObjectArray(env, count, "[Ljava/lang/String;", callback);
}
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getStackTrace(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thread, jint start, jint max) {
+ std::unique_ptr<jvmtiFrameInfo[]> frames(new jvmtiFrameInfo[max]);
+
+ jint count;
+ {
+ jvmtiError result = jvmti_env->GetStackTrace(thread, start, max, frames.get(), &count);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running GetStackTrace: %s\n", err);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ return nullptr;
+ }
+ }
+
+ return TranslateJvmtiFrameInfoArray(env, frames.get(), count);
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getAllStackTraces(
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jint max) {
+ std::unique_ptr<jvmtiFrameInfo[]> frames(new jvmtiFrameInfo[max]);
+
+ jint thread_count;
+ jvmtiStackInfo* stack_infos;
+ {
+ jvmtiError result = jvmti_env->GetAllStackTraces(max, &stack_infos, &thread_count);
+ if (result != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result, &err);
+ printf("Failure running GetAllStackTraces: %s\n", err);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ return nullptr;
+ }
+ }
+
+ auto callback = [&](jint thread_index) -> jobject {
+ auto inner_callback = [&](jint index) -> jobject {
+ if (index == 0) {
+ return stack_infos[thread_index].thread;
+ } else {
+ return TranslateJvmtiFrameInfoArray(env,
+ stack_infos[thread_index].frame_buffer,
+ stack_infos[thread_index].frame_count);
+ }
+ };
+ return CreateObjectArray(env, 2, "java/lang/Object", inner_callback);
+ };
+ jobjectArray ret = CreateObjectArray(env, thread_count, "[Ljava/lang/Object;", callback);
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(stack_infos));
+ return ret;
+}
+
} // namespace Test911GetStackTrace
} // namespace art