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/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