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