ART: Add GetThreadListStackTraces

Add support for GetThreadListStackTraces. Add a test.

Bug: 31684812
Test: m test-art-host-run-test-911-get-stack-trace
Change-Id: I958d02306d515f7ac03fddf4371805b133330d26
diff --git a/test/911-get-stack-trace/stack_trace.cc b/test/911-get-stack-trace/stack_trace.cc
index 8fc0af4..f853387 100644
--- a/test/911-get-stack-trace/stack_trace.cc
+++ b/test/911-get-stack-trace/stack_trace.cc
@@ -59,11 +59,7 @@
     char* gen;
     {
       jvmtiError result2 = jvmti_env->GetMethodName(frames[method_index].method, &name, &sig, &gen);
-      if (result2 != JVMTI_ERROR_NONE) {
-        char* err;
-        jvmti_env->GetErrorName(result2, &err);
-        printf("Failure running GetMethodName: %s\n", err);
-        jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
+      if (JvmtiErrorToException(env, result2)) {
         return nullptr;
       }
     }
@@ -134,11 +130,7 @@
   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));
+    if (JvmtiErrorToException(env, result)) {
       return nullptr;
     }
   }
@@ -148,17 +140,47 @@
 
 extern "C" JNIEXPORT jobjectArray JNICALL Java_AllTraces_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));
+    if (JvmtiErrorToException(env, result)) {
+      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;
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_ThreadListTraces_getThreadListStackTraces(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobjectArray jthreads, jint max) {
+  jint thread_count = env->GetArrayLength(jthreads);
+  std::unique_ptr<jthread[]> threads(new jthread[thread_count]);
+  for (jint i = 0; i != thread_count; ++i) {
+    threads[i] = env->GetObjectArrayElement(jthreads, i);
+  }
+
+  jvmtiStackInfo* stack_infos;
+  {
+    jvmtiError result = jvmti_env->GetThreadListStackTraces(thread_count,
+                                                            threads.get(),
+                                                            max,
+                                                            &stack_infos);
+    if (JvmtiErrorToException(env, result)) {
       return nullptr;
     }
   }