Merge "ART: Refactor some TI test code for reuse"
diff --git a/test/907-get-loaded-classes/get_loaded_classes.cc b/test/907-get-loaded-classes/get_loaded_classes.cc
index 0e09d1b..ce929a6 100644
--- a/test/907-get-loaded-classes/get_loaded_classes.cc
+++ b/test/907-get-loaded-classes/get_loaded_classes.cc
@@ -27,6 +27,7 @@
 #include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 
+#include "ti-agent/common_helper.h"
 #include "ti-agent/common_load.h"
 
 namespace art {
@@ -50,28 +51,14 @@
     return nullptr;
   }
 
-  ScopedLocalRef<jclass> obj_class(env, env->FindClass("java/lang/String"));
-  if (obj_class.get() == nullptr) {
-    return nullptr;
-  }
-
-  jobjectArray ret = env->NewObjectArray(count, obj_class.get(), nullptr);
-  if (ret == nullptr) {
-    return ret;
-  }
-
-  for (size_t i = 0; i < static_cast<size_t>(count); ++i) {
+  auto callback = [&](jint i) {
     jstring class_name = GetClassName(env, classes[i]);
-    env->SetObjectArrayElement(ret, static_cast<jint>(i), class_name);
-    env->DeleteLocalRef(class_name);
-  }
-
-  // Need to:
-  // 1) Free the local references.
-  // 2) Deallocate.
-  for (size_t i = 0; i < static_cast<size_t>(count); ++i) {
     env->DeleteLocalRef(classes[i]);
-  }
+    return class_name;
+  };
+  jobjectArray ret = CreateObjectArray(env, count, "java/lang/String", callback);
+
+  // Need to Deallocate.
   jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(classes));
 
   return ret;
diff --git a/test/910-methods/methods.cc b/test/910-methods/methods.cc
index cc6ad67..005cba6 100644
--- a/test/910-methods/methods.cc
+++ b/test/910-methods/methods.cc
@@ -23,6 +23,7 @@
 #include "openjdkjvmti/jvmti.h"
 #include "ScopedLocalRef.h"
 
+#include "ti-agent/common_helper.h"
 #include "ti-agent/common_load.h"
 
 namespace art {
@@ -43,23 +44,16 @@
     return nullptr;
   }
 
-  ScopedLocalRef<jclass> obj_class(env, env->FindClass("java/lang/String"));
-  if (obj_class.get() == nullptr) {
-    return nullptr;
-  }
-
-  jobjectArray ret = env->NewObjectArray(3, obj_class.get(), nullptr);
-  if (ret == nullptr) {
-    return ret;
-  }
-
-  ScopedLocalRef<jstring> name_str(env, name == nullptr ? nullptr : env->NewStringUTF(name));
-  ScopedLocalRef<jstring> sig_str(env, sig == nullptr ? nullptr : env->NewStringUTF(sig));
-  ScopedLocalRef<jstring> gen_str(env, gen == nullptr ? nullptr : env->NewStringUTF(gen));
-
-  env->SetObjectArrayElement(ret, 0, name_str.get());
-  env->SetObjectArrayElement(ret, 1, sig_str.get());
-  env->SetObjectArrayElement(ret, 2, gen_str.get());
+  auto callback = [&](jint i) {
+    if (i == 0) {
+      return name == nullptr ? nullptr : env->NewStringUTF(name);
+    } else if (i == 1) {
+      return sig == nullptr ? nullptr : env->NewStringUTF(sig);
+    } else {
+      return gen == nullptr ? nullptr : env->NewStringUTF(gen);
+    }
+  };
+  jobjectArray ret = CreateObjectArray(env, 3, "java/lang/String", callback);
 
   // Need to deallocate the strings.
   if (name != nullptr) {
diff --git a/test/911-get-stack-trace/stack_trace.cc b/test/911-get-stack-trace/stack_trace.cc
index da649cf..a30416d 100644
--- a/test/911-get-stack-trace/stack_trace.cc
+++ b/test/911-get-stack-trace/stack_trace.cc
@@ -23,6 +23,7 @@
 #include "jni.h"
 #include "openjdkjvmti/jvmti.h"
 #include "ScopedLocalRef.h"
+#include "ti-agent/common_helper.h"
 #include "ti-agent/common_load.h"
 
 namespace art {
@@ -33,39 +34,36 @@
   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);
-    return nullptr;
+  {
+    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);
+      return nullptr;
+    }
   }
 
-  ScopedLocalRef<jclass> obj_class(env, env->FindClass("java/lang/String"));
-  if (obj_class.get() == nullptr) {
-    return nullptr;
-  }
-
-  jobjectArray ret = env->NewObjectArray(2 * count, obj_class.get(), nullptr);
-  if (ret == nullptr) {
-    return ret;
-  }
-
-  for (size_t i = 0; i < static_cast<size_t>(count); ++i) {
+  auto callback = [&](jint i) -> jstring {
+    size_t method_index = static_cast<size_t>(i) / 2;
     char* name;
     char* sig;
     char* gen;
-    jvmtiError result2 = jvmti_env->GetMethodName(frames[i].method, &name, &sig, &gen);
-    if (result2 != JVMTI_ERROR_NONE) {
-      char* err;
-      jvmti_env->GetErrorName(result, &err);
-      printf("Failure running GetMethodName: %s\n", err);
-      return nullptr;
+    {
+      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);
+        return nullptr;
+      }
     }
-    ScopedLocalRef<jstring> trace_name(env, name == nullptr ? nullptr : env->NewStringUTF(name));
-    ScopedLocalRef<jstring> trace_sig(env, sig == nullptr ? nullptr : env->NewStringUTF(sig));
-    env->SetObjectArrayElement(ret, static_cast<jint>(2 * i), trace_name.get());
-    env->SetObjectArrayElement(ret, static_cast<jint>(2 * i + 1), trace_sig.get());
+    jstring callback_result;
+    if (i % 2 == 0) {
+      callback_result = name == nullptr ? nullptr : env->NewStringUTF(name);
+    } else {
+      callback_result = sig == nullptr ? nullptr : env->NewStringUTF(sig);
+    }
 
     if (name != nullptr) {
       jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(name));
@@ -76,9 +74,9 @@
     if (gen != nullptr) {
       jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(gen));
     }
-  }
-
-  return ret;
+    return callback_result;
+  };
+  return CreateObjectArray(env, 2 * count, "java/lang/String", callback);
 }
 
 // Don't do anything
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index 4bf329c..fbf3259 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -23,6 +23,7 @@
 #include "openjdkjvmti/jvmti.h"
 #include "ScopedLocalRef.h"
 
+#include "ti-agent/common_helper.h"
 #include "ti-agent/common_load.h"
 
 namespace art {
@@ -40,21 +41,14 @@
     return nullptr;
   }
 
-  ScopedLocalRef<jclass> obj_class(env, env->FindClass("java/lang/String"));
-  if (obj_class.get() == nullptr) {
-    return nullptr;
-  }
-
-  jobjectArray ret = env->NewObjectArray(2, obj_class.get(), nullptr);
-  if (ret == nullptr) {
-    return ret;
-  }
-
-  ScopedLocalRef<jstring> sig_str(env, sig == nullptr ? nullptr : env->NewStringUTF(sig));
-  ScopedLocalRef<jstring> gen_str(env, gen == nullptr ? nullptr : env->NewStringUTF(gen));
-
-  env->SetObjectArrayElement(ret, 0, sig_str.get());
-  env->SetObjectArrayElement(ret, 1, gen_str.get());
+  auto callback = [&](jint i) {
+    if (i == 0) {
+      return sig == nullptr ? nullptr : env->NewStringUTF(sig);
+    } else {
+      return gen == nullptr ? nullptr : env->NewStringUTF(gen);
+    }
+  };
+  jobjectArray ret = CreateObjectArray(env, 2, "java/lang/String", callback);
 
   // Need to deallocate the strings.
   if (sig != nullptr) {
diff --git a/test/ti-agent/common_helper.h b/test/ti-agent/common_helper.h
new file mode 100644
index 0000000..9aeb98c
--- /dev/null
+++ b/test/ti-agent/common_helper.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_TEST_TI_AGENT_COMMON_HELPER_H_
+#define ART_TEST_TI_AGENT_COMMON_HELPER_H_
+
+#include "jni.h"
+#include "ScopedLocalRef.h"
+
+namespace art {
+
+template <typename T>
+static jobjectArray CreateObjectArray(JNIEnv* env,
+                                      jint length,
+                                      const char* component_type_descriptor,
+                                      T src) {
+  if (length < 0) {
+    return nullptr;
+  }
+
+  ScopedLocalRef<jclass> obj_class(env, env->FindClass(component_type_descriptor));
+  if (obj_class.get() == nullptr) {
+    return nullptr;
+  }
+
+  ScopedLocalRef<jobjectArray> ret(env, env->NewObjectArray(length, obj_class.get(), nullptr));
+  if (ret.get() == nullptr) {
+    return nullptr;
+  }
+
+  for (jint i = 0; i < length; ++i) {
+    jobject element = src(i);
+    env->SetObjectArrayElement(ret.get(), static_cast<jint>(i), element);
+    env->DeleteLocalRef(element);
+    if (env->ExceptionCheck()) {
+      return nullptr;
+    }
+  }
+
+  return ret.release();
+}
+
+}  // namespace art
+
+#endif  // ART_TEST_TI_AGENT_COMMON_HELPER_H_