ART: Rewrite JvmtiUniquePtr

Templatize it over the stored type. Add convenience function for
allocation.

Bug: 31455788
Test: m test-art-host
Change-Id: Idaf0a9170e95141e7a9878923aa93a0dbc80819c
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index a815a60..77ca9ce 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -1188,13 +1188,13 @@
     ENSURE_NON_NULL(name_ptr);
     switch (error) {
 #define ERROR_CASE(e) case (JVMTI_ERROR_ ## e) : do { \
-          jvmtiError res = CopyString(env, \
-                                      "JVMTI_ERROR_"#e, \
-                                      reinterpret_cast<unsigned char**>(name_ptr)); \
-          if (res != OK) { \
+          jvmtiError res; \
+          JvmtiUniquePtr<char[]> copy = CopyString(env, "JVMTI_ERROR_"#e, &res); \
+          if (copy == nullptr) { \
             *name_ptr = nullptr; \
             return res; \
           } else { \
+            *name_ptr = copy.release(); \
             return OK; \
           } \
         } while (false)
@@ -1248,13 +1248,13 @@
       ERROR_CASE(INVALID_ENVIRONMENT);
 #undef ERROR_CASE
       default: {
-        jvmtiError res = CopyString(env,
-                                    "JVMTI_ERROR_UNKNOWN",
-                                    reinterpret_cast<unsigned char**>(name_ptr));
-        if (res != OK) {
+        jvmtiError res;
+        JvmtiUniquePtr<char[]> copy = CopyString(env, "JVMTI_ERROR_UNKNOWN", &res);
+        if (copy == nullptr) {
           *name_ptr = nullptr;
           return res;
         } else {
+          *name_ptr = copy.release();
           return ERR(ILLEGAL_ARGUMENT);
         }
       }
diff --git a/runtime/openjdkjvmti/art_jvmti.h b/runtime/openjdkjvmti/art_jvmti.h
index 106165c..99139a1 100644
--- a/runtime/openjdkjvmti/art_jvmti.h
+++ b/runtime/openjdkjvmti/art_jvmti.h
@@ -33,6 +33,7 @@
 #define ART_RUNTIME_OPENJDKJVMTI_ART_JVMTI_H_
 
 #include <memory>
+#include <type_traits>
 
 #include <jni.h>
 
@@ -86,6 +87,7 @@
   return ret_value;
 }
 
+template <typename T>
 class JvmtiDeleter {
  public:
   JvmtiDeleter() : env_(nullptr) {}
@@ -95,9 +97,9 @@
   JvmtiDeleter(JvmtiDeleter&&) = default;
   JvmtiDeleter& operator=(const JvmtiDeleter&) = default;
 
-  void operator()(unsigned char* ptr) const {
+  void operator()(T* ptr) const {
     CHECK(env_ != nullptr);
-    jvmtiError ret = env_->Deallocate(ptr);
+    jvmtiError ret = env_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
     CHECK(ret == ERR(NONE));
   }
 
@@ -105,12 +107,65 @@
   mutable jvmtiEnv* env_;
 };
 
-using JvmtiUniquePtr = std::unique_ptr<unsigned char, JvmtiDeleter>;
+template <typename T>
+class JvmtiDeleter<T[]> {
+  public:
+  JvmtiDeleter() : env_(nullptr) {}
+  explicit JvmtiDeleter(jvmtiEnv* env) : env_(env) {}
+
+  JvmtiDeleter(JvmtiDeleter&) = default;
+  JvmtiDeleter(JvmtiDeleter&&) = default;
+  JvmtiDeleter& operator=(const JvmtiDeleter&) = default;
+
+  template <typename U>
+  void operator()(U* ptr) const {
+    CHECK(env_ != nullptr);
+    jvmtiError ret = env_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
+    CHECK(ret == ERR(NONE));
+  }
+
+ private:
+  mutable jvmtiEnv* env_;
+};
+
+template <typename T>
+using JvmtiUniquePtr = std::unique_ptr<T, JvmtiDeleter<T>>;
 
 template <typename T>
 ALWAYS_INLINE
-static inline JvmtiUniquePtr MakeJvmtiUniquePtr(jvmtiEnv* env, T* mem) {
-  return JvmtiUniquePtr(reinterpret_cast<unsigned char*>(mem), JvmtiDeleter(env));
+static inline JvmtiUniquePtr<T> MakeJvmtiUniquePtr(jvmtiEnv* env, T* mem) {
+  return JvmtiUniquePtr<T>(mem, JvmtiDeleter<T>(env));
+}
+
+template <typename T>
+ALWAYS_INLINE
+static inline JvmtiUniquePtr<T> MakeJvmtiUniquePtr(jvmtiEnv* env, unsigned char* mem) {
+  return JvmtiUniquePtr<T>(reinterpret_cast<T*>(mem), JvmtiDeleter<T>(env));
+}
+
+template <typename T>
+ALWAYS_INLINE
+static inline JvmtiUniquePtr<T> AllocJvmtiUniquePtr(jvmtiEnv* env, jvmtiError* error) {
+  unsigned char* tmp;
+  *error = env->Allocate(sizeof(T), &tmp);
+  if (*error != ERR(NONE)) {
+    return JvmtiUniquePtr<T>();
+  }
+  return JvmtiUniquePtr<T>(tmp, JvmtiDeleter<T>(env));
+}
+
+template <typename T>
+ALWAYS_INLINE
+static inline JvmtiUniquePtr<T> AllocJvmtiUniquePtr(jvmtiEnv* env,
+                                                    size_t count,
+                                                    jvmtiError* error) {
+  unsigned char* tmp;
+  *error = env->Allocate(sizeof(typename std::remove_extent<T>::type) * count, &tmp);
+  if (*error != ERR(NONE)) {
+    return JvmtiUniquePtr<T>();
+  }
+  return JvmtiUniquePtr<T>(reinterpret_cast<typename std::remove_extent<T>::type*>(tmp),
+                           JvmtiDeleter<T>(env));
 }
 
 ALWAYS_INLINE
@@ -129,15 +184,12 @@
 }
 
 ALWAYS_INLINE
-static inline jvmtiError CopyString(jvmtiEnv* env, const char* src, unsigned char** copy) {
+static inline JvmtiUniquePtr<char[]> CopyString(jvmtiEnv* env, const char* src, jvmtiError* error) {
   size_t len = strlen(src) + 1;
-  unsigned char* buf;
-  jvmtiError ret = env->Allocate(len, &buf);
-  if (ret != ERR(NONE)) {
-    return ret;
+  JvmtiUniquePtr<char[]> ret = AllocJvmtiUniquePtr<char[]>(env, len, error);
+  if (ret != nullptr) {
+    strcpy(ret.get(), src);
   }
-  strcpy(reinterpret_cast<char*>(buf), src);
-  *copy = buf;
   return ret;
 }
 
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index a8a0ded..4282e38 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -673,18 +673,17 @@
     return ERR(INVALID_CLASS);
   }
 
-  JvmtiUniquePtr sig_copy;
+  JvmtiUniquePtr<char[]> sig_copy;
   if (signature_ptr != nullptr) {
     std::string storage;
     const char* descriptor = klass->GetDescriptor(&storage);
 
-    unsigned char* tmp;
-    jvmtiError ret = CopyString(env, descriptor, &tmp);
-    if (ret != ERR(NONE)) {
+    jvmtiError ret;
+    sig_copy = CopyString(env, descriptor, &ret);
+    if (sig_copy == nullptr) {
       return ret;
     }
-    sig_copy = MakeJvmtiUniquePtr(env, tmp);
-    *signature_ptr = reinterpret_cast<char*>(tmp);
+    *signature_ptr = sig_copy.get();
   }
 
   if (generic_ptr != nullptr) {
@@ -700,12 +699,12 @@
           oss << str_array->Get(i)->ToModifiedUtf8();
         }
         std::string output_string = oss.str();
-        unsigned char* tmp;
-        jvmtiError ret = CopyString(env, output_string.c_str(), &tmp);
-        if (ret != ERR(NONE)) {
+        jvmtiError ret;
+        JvmtiUniquePtr<char[]> copy = CopyString(env, output_string.c_str(), &ret);
+        if (copy == nullptr) {
           return ret;
         }
-        *generic_ptr = reinterpret_cast<char*>(tmp);
+        *generic_ptr = copy.release();
       } else if (soa.Self()->IsExceptionPending()) {
         // TODO: Should we report an error here?
         soa.Self()->ClearException();
diff --git a/runtime/openjdkjvmti/ti_class_definition.h b/runtime/openjdkjvmti/ti_class_definition.h
index dbe5da2..3c251d4 100644
--- a/runtime/openjdkjvmti/ti_class_definition.h
+++ b/runtime/openjdkjvmti/ti_class_definition.h
@@ -46,7 +46,7 @@
   std::string name;
   jobject protection_domain;
   jint dex_len;
-  JvmtiUniquePtr dex_data;
+  JvmtiUniquePtr<unsigned char> dex_data;
   art::ArraySlice<const unsigned char> original_dex_file;
 
   ArtClassDefinition() = default;
diff --git a/runtime/openjdkjvmti/ti_field.cc b/runtime/openjdkjvmti/ti_field.cc
index 131e6c3..8c3f2ff 100644
--- a/runtime/openjdkjvmti/ti_field.cc
+++ b/runtime/openjdkjvmti/ti_field.cc
@@ -63,31 +63,29 @@
   art::ScopedObjectAccess soa(art::Thread::Current());
   art::ArtField* art_field = art::jni::DecodeArtField(field);
 
-  JvmtiUniquePtr name_copy;
+  JvmtiUniquePtr<char[]> name_copy;
   if (name_ptr != nullptr) {
     const char* field_name = art_field->GetName();
     if (field_name == nullptr) {
       field_name = "<error>";
     }
-    unsigned char* tmp;
-    jvmtiError ret = CopyString(env, field_name, &tmp);
-    if (ret != ERR(NONE)) {
+    jvmtiError ret;
+    name_copy = CopyString(env, field_name, &ret);
+    if (name_copy == nullptr) {
       return ret;
     }
-    name_copy = MakeJvmtiUniquePtr(env, tmp);
-    *name_ptr = reinterpret_cast<char*>(tmp);
+    *name_ptr = name_copy.get();
   }
 
-  JvmtiUniquePtr signature_copy;
+  JvmtiUniquePtr<char[]> signature_copy;
   if (signature_ptr != nullptr) {
     const char* sig = art_field->GetTypeDescriptor();
-    unsigned char* tmp;
-    jvmtiError ret = CopyString(env, sig, &tmp);
-    if (ret != ERR(NONE)) {
+    jvmtiError ret;
+    signature_copy = CopyString(env, sig, &ret);
+    if (signature_copy == nullptr) {
       return ret;
     }
-    signature_copy = MakeJvmtiUniquePtr(env, tmp);
-    *signature_ptr = reinterpret_cast<char*>(tmp);
+    *signature_ptr = signature_copy.get();
   }
 
   // TODO: Support generic signature.
@@ -102,12 +100,12 @@
           oss << str_array->Get(i)->ToModifiedUtf8();
         }
         std::string output_string = oss.str();
-        unsigned char* tmp;
-        jvmtiError ret = CopyString(env, output_string.c_str(), &tmp);
-        if (ret != ERR(NONE)) {
+        jvmtiError ret;
+        JvmtiUniquePtr<char[]> copy = CopyString(env, output_string.c_str(), &ret);
+        if (copy == nullptr) {
           return ret;
         }
-        *generic_ptr = reinterpret_cast<char*>(tmp);
+        *generic_ptr = copy.release();
       } else if (soa.Self()->IsExceptionPending()) {
         // TODO: Should we report an error here?
         soa.Self()->ClearException();
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index a6cfcc1..bc73029 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -110,35 +110,32 @@
   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
   art_method = art_method->GetInterfaceMethodIfProxy(art::kRuntimePointerSize);
 
-  JvmtiUniquePtr name_copy;
+  JvmtiUniquePtr<char[]> name_copy;
   if (name_ptr != nullptr) {
     const char* method_name = art_method->GetName();
     if (method_name == nullptr) {
       method_name = "<error>";
     }
-    unsigned char* tmp;
-    jvmtiError ret = CopyString(env, method_name, &tmp);
-    if (ret != ERR(NONE)) {
+    jvmtiError ret;
+    name_copy = CopyString(env, method_name, &ret);
+    if (name_copy == nullptr) {
       return ret;
     }
-    name_copy = MakeJvmtiUniquePtr(env, tmp);
-    *name_ptr = reinterpret_cast<char*>(tmp);
+    *name_ptr = name_copy.get();
   }
 
-  JvmtiUniquePtr signature_copy;
+  JvmtiUniquePtr<char[]> signature_copy;
   if (signature_ptr != nullptr) {
     const art::Signature sig = art_method->GetSignature();
     std::string str = sig.ToString();
-    unsigned char* tmp;
-    jvmtiError ret = CopyString(env, str.c_str(), &tmp);
-    if (ret != ERR(NONE)) {
+    jvmtiError ret;
+    signature_copy = CopyString(env, str.c_str(), &ret);
+    if (signature_copy == nullptr) {
       return ret;
     }
-    signature_copy = MakeJvmtiUniquePtr(env, tmp);
-    *signature_ptr = reinterpret_cast<char*>(tmp);
+    *signature_ptr = signature_copy.get();
   }
 
-  // TODO: Support generic signature.
   if (generic_ptr != nullptr) {
     *generic_ptr = nullptr;
     if (!art_method->GetDeclaringClass()->IsProxyClass()) {
@@ -150,12 +147,12 @@
           oss << str_array->Get(i)->ToModifiedUtf8();
         }
         std::string output_string = oss.str();
-        unsigned char* tmp;
-        jvmtiError ret = CopyString(env, output_string.c_str(), &tmp);
-        if (ret != ERR(NONE)) {
+        jvmtiError ret;
+        JvmtiUniquePtr<char[]> generic_copy = CopyString(env, output_string.c_str(), &ret);
+        if (generic_copy == nullptr) {
           return ret;
         }
-        *generic_ptr = reinterpret_cast<char*>(tmp);
+        *generic_ptr = generic_copy.release();
       } else if (soa.Self()->IsExceptionPending()) {
         // TODO: Should we report an error here?
         soa.Self()->ClearException();
diff --git a/runtime/openjdkjvmti/ti_properties.cc b/runtime/openjdkjvmti/ti_properties.cc
index 46b9e71..4f4f013 100644
--- a/runtime/openjdkjvmti/ti_properties.cc
+++ b/runtime/openjdkjvmti/ti_properties.cc
@@ -82,71 +82,69 @@
 static constexpr const char* kPropertyLibraryPath = "java.library.path";
 static constexpr const char* kPropertyClassPath = "java.class.path";
 
-static jvmtiError Copy(jvmtiEnv* env, const char* in, char** out) {
-  unsigned char* data = nullptr;
-  jvmtiError result = CopyString(env, in, &data);
-  *out = reinterpret_cast<char*>(data);
-  return result;
-}
-
 jvmtiError PropertiesUtil::GetSystemProperties(jvmtiEnv* env,
                                                jint* count_ptr,
                                                char*** property_ptr) {
   if (count_ptr == nullptr || property_ptr == nullptr) {
     return ERR(NULL_POINTER);
   }
-  unsigned char* array_data;
-  jvmtiError array_alloc_result = env->Allocate((kPropertiesSize + 2) * sizeof(char*), &array_data);
-  if (array_alloc_result != ERR(NONE)) {
+  jvmtiError array_alloc_result;
+  JvmtiUniquePtr<char*[]> array_data_ptr = AllocJvmtiUniquePtr<char*[]>(env,
+                                                                        kPropertiesSize + 2,
+                                                                        &array_alloc_result);
+  if (array_data_ptr == nullptr) {
     return array_alloc_result;
   }
-  JvmtiUniquePtr array_data_ptr = MakeJvmtiUniquePtr(env, array_data);
-  char** array = reinterpret_cast<char**>(array_data);
 
-  std::vector<JvmtiUniquePtr> property_copies;
+  std::vector<JvmtiUniquePtr<char[]>> property_copies;
 
   {
-    char* libpath_data;
-    jvmtiError libpath_result = Copy(env, kPropertyLibraryPath, &libpath_data);
-    if (libpath_result != ERR(NONE)) {
+    jvmtiError libpath_result;
+    JvmtiUniquePtr<char[]> libpath_data = CopyString(env, kPropertyLibraryPath, &libpath_result);
+    if (libpath_data == nullptr) {
       return libpath_result;
     }
-    array[0] = libpath_data;
-    property_copies.push_back(MakeJvmtiUniquePtr(env, libpath_data));
+    array_data_ptr.get()[0] = libpath_data.get();
+    property_copies.push_back(std::move(libpath_data));
   }
 
   {
-    char* classpath_data;
-    jvmtiError classpath_result = Copy(env, kPropertyClassPath, &classpath_data);
-    if (classpath_result != ERR(NONE)) {
+    jvmtiError classpath_result;
+    JvmtiUniquePtr<char[]> classpath_data = CopyString(env, kPropertyClassPath, &classpath_result);
+    if (classpath_data == nullptr) {
       return classpath_result;
     }
-    array[1] = classpath_data;
-    property_copies.push_back(MakeJvmtiUniquePtr(env, classpath_data));
+    array_data_ptr.get()[1] = classpath_data.get();
+    property_copies.push_back(std::move(classpath_data));
   }
 
   for (size_t i = 0; i != kPropertiesSize; ++i) {
-    char* data;
-    jvmtiError data_result = Copy(env, kProperties[i][0], &data);
-    if (data_result != ERR(NONE)) {
+    jvmtiError data_result;
+    JvmtiUniquePtr<char[]> data = CopyString(env, kProperties[i][0], &data_result);
+    if (data == nullptr) {
       return data_result;
     }
-    array[i + 2] = data;
-    property_copies.push_back(MakeJvmtiUniquePtr(env, data));
+    array_data_ptr.get()[i + 2] = data.get();
+    property_copies.push_back(std::move(data));
   }
 
   // Everything is OK, release the data.
-  array_data_ptr.release();
+  *count_ptr = kPropertiesSize + 2;
+  *property_ptr = array_data_ptr.release();
   for (auto& uptr : property_copies) {
     uptr.release();
   }
 
-  *count_ptr = kPropertiesSize + 2;
-  *property_ptr = array;
-
   return ERR(NONE);
 }
 
+static jvmtiError Copy(jvmtiEnv* env, const char* in, char** out) {
+  jvmtiError result;
+  JvmtiUniquePtr<char[]> data = CopyString(env, in, &result);
+  *out = data.release();
+  return result;
+}
+
 jvmtiError PropertiesUtil::GetSystemProperty(jvmtiEnv* env,
                                              const char* property,
                                              char** value_ptr) {
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 8436045..dcf999e 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -396,8 +396,8 @@
     *error_msg_ = "Unable to get class signature!";
     return ret;
   }
-  JvmtiUniquePtr generic_unique_ptr(MakeJvmtiUniquePtr(env, generic_ptr_unused));
-  JvmtiUniquePtr signature_unique_ptr(MakeJvmtiUniquePtr(env, signature_ptr));
+  JvmtiUniquePtr<char> generic_unique_ptr(MakeJvmtiUniquePtr(env, generic_ptr_unused));
+  JvmtiUniquePtr<char> signature_unique_ptr(MakeJvmtiUniquePtr(env, signature_ptr));
   std::unique_ptr<art::MemMap> map(MoveDataToMemMap(original_dex_location,
                                                     def.dex_len,
                                                     def.dex_data.get(),
diff --git a/runtime/openjdkjvmti/ti_thread.cc b/runtime/openjdkjvmti/ti_thread.cc
index f8f8fa6..788ac30 100644
--- a/runtime/openjdkjvmti/ti_thread.cc
+++ b/runtime/openjdkjvmti/ti_thread.cc
@@ -186,17 +186,17 @@
     return ERR(INVALID_THREAD);
   }
 
-  JvmtiUniquePtr name_uptr;
+  JvmtiUniquePtr<char[]> name_uptr;
   if (self != nullptr) {
     // Have a native thread object, this thread is alive.
     std::string name;
     self->GetThreadName(name);
-    jvmtiError name_result = CopyString(
-        env, name.c_str(), reinterpret_cast<unsigned char**>(&info_ptr->name));
-    if (name_result != ERR(NONE)) {
+    jvmtiError name_result;
+    name_uptr = CopyString(env, name.c_str(), &name_result);
+    if (name_uptr == nullptr) {
       return name_result;
     }
-    name_uptr = MakeJvmtiUniquePtr(env, info_ptr->name);
+    info_ptr->name = name_uptr.get();
 
     info_ptr->priority = self->GetNativePriority();
 
@@ -239,12 +239,12 @@
       } else {
         name_cstr = "";
       }
-      jvmtiError name_result = CopyString(
-          env, name_cstr, reinterpret_cast<unsigned char**>(&info_ptr->name));
-      if (name_result != ERR(NONE)) {
+      jvmtiError name_result;
+      name_uptr = CopyString(env, name_cstr, &name_result);
+      if (name_uptr == nullptr) {
         return name_result;
       }
-      name_uptr = MakeJvmtiUniquePtr(env, info_ptr->name);
+      info_ptr->name = name_uptr.get();
     }
 
     // Priority.
diff --git a/runtime/openjdkjvmti/ti_threadgroup.cc b/runtime/openjdkjvmti/ti_threadgroup.cc
index 1423874..df14333 100644
--- a/runtime/openjdkjvmti/ti_threadgroup.cc
+++ b/runtime/openjdkjvmti/ti_threadgroup.cc
@@ -116,11 +116,12 @@
       tmp_str = name_obj->ToModifiedUtf8();
       tmp_cstr = tmp_str.c_str();
     }
-    jvmtiError result =
-        CopyString(env, tmp_cstr, reinterpret_cast<unsigned char**>(&info_ptr->name));
-    if (result != ERR(NONE)) {
+    jvmtiError result;
+    JvmtiUniquePtr<char[]> copy = CopyString(env, tmp_cstr, &result);
+    if (copy == nullptr) {
       return result;
     }
+    info_ptr->name = copy.release();
   }
 
   // Parent.
@@ -239,45 +240,38 @@
   std::vector<art::ObjPtr<art::mirror::Object>> thread_groups;
   GetChildThreadGroups(thread_group, &thread_groups);
 
-  jthread* thread_data = nullptr;
-  JvmtiUniquePtr peers_uptr;
+  JvmtiUniquePtr<jthread[]> peers_uptr;
   if (!thread_peers.empty()) {
-    unsigned char* data;
-    jvmtiError res = env->Allocate(sizeof(jthread) * thread_peers.size(), &data);
-    if (res != ERR(NONE)) {
+    jvmtiError res;
+    peers_uptr = AllocJvmtiUniquePtr<jthread[]>(env, thread_peers.size(), &res);
+    if (peers_uptr == nullptr) {
       return res;
     }
-    thread_data = reinterpret_cast<jthread*>(data);
-    peers_uptr = MakeJvmtiUniquePtr(env, data);
   }
 
-  jthreadGroup* group_data = nullptr;
+  JvmtiUniquePtr<jthreadGroup[]> group_uptr;
   if (!thread_groups.empty()) {
-    unsigned char* data;
-    jvmtiError res = env->Allocate(sizeof(jthreadGroup) * thread_groups.size(), &data);
-    if (res != ERR(NONE)) {
+    jvmtiError res;
+    group_uptr = AllocJvmtiUniquePtr<jthreadGroup[]>(env, thread_groups.size(), &res);
+    if (group_uptr == nullptr) {
       return res;
     }
-    group_data = reinterpret_cast<jthreadGroup*>(data);
   }
 
   // Can't fail anymore from here on.
 
   // Copy data into out buffers.
   for (size_t i = 0; i != thread_peers.size(); ++i) {
-    thread_data[i] = soa.AddLocalReference<jthread>(thread_peers[i]);
+    peers_uptr[i] = soa.AddLocalReference<jthread>(thread_peers[i]);
   }
   for (size_t i = 0; i != thread_groups.size(); ++i) {
-    group_data[i] = soa.AddLocalReference<jthreadGroup>(thread_groups[i]);
+    group_uptr[i] = soa.AddLocalReference<jthreadGroup>(thread_groups[i]);
   }
 
   *thread_count_ptr = static_cast<jint>(thread_peers.size());
-  *threads_ptr = thread_data;
+  *threads_ptr = peers_uptr.release();
   *group_count_ptr = static_cast<jint>(thread_groups.size());
-  *groups_ptr = group_data;
-
-  // Everything's fine.
-  peers_uptr.release();
+  *groups_ptr = group_uptr.release();
 
   return ERR(NONE);
 }