Revert "Revert "Implement RetransformClasses""

This reverts commit 52a2db50b76f2b981d21d5508c3d9e8ab4c5fe93.

Reason for revert: Issue with RedefineClasses was resolved.

Test: ART_TEST_JNI_FORCECOPY=true mma -j40 test-art-host

Change-Id: I06f198df4fb40c48647b358d241710329e0812e9
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 6af51c4..2db8a40 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -242,14 +242,12 @@
   }
 }
 
-// TODO This should handle doing multiple classes at once so we need to do less cleanup when things
-// go wrong.
 jvmtiError Redefiner::RedefineClasses(ArtJvmTiEnv* env,
                                       art::Runtime* runtime,
                                       art::Thread* self,
                                       jint class_count,
                                       const jvmtiClassDefinition* definitions,
-                                      std::string* error_msg) {
+                                      /*out*/std::string* error_msg) {
   if (env == nullptr) {
     *error_msg = "env was null!";
     return ERR(INVALID_ENVIRONMENT);
@@ -263,46 +261,95 @@
     *error_msg = "null definitions!";
     return ERR(NULL_POINTER);
   }
+  std::vector<ArtClassDefinition> def_vector;
+  def_vector.reserve(class_count);
+  for (jint i = 0; i < class_count; i++) {
+    // We make a copy of the class_bytes to pass into the retransformation.
+    // This makes cleanup easier (since we unambiguously own the bytes) and also is useful since we
+    // will need to keep the original bytes around unaltered for subsequent RetransformClasses calls
+    // to get the passed in bytes.
+    // TODO Implement saving the original bytes.
+    unsigned char* class_bytes_copy = nullptr;
+    jvmtiError res = env->Allocate(definitions[i].class_byte_count, &class_bytes_copy);
+    if (res != OK) {
+      return res;
+    }
+    memcpy(class_bytes_copy, definitions[i].class_bytes, definitions[i].class_byte_count);
+
+    ArtClassDefinition def;
+    def.dex_len = definitions[i].class_byte_count;
+    def.dex_data = MakeJvmtiUniquePtr(env, class_bytes_copy);
+    // We are definitely modified.
+    def.modified = true;
+    res = Transformer::FillInTransformationData(env, definitions[i].klass, &def);
+    if (res != OK) {
+      return res;
+    }
+    def_vector.push_back(std::move(def));
+  }
+  // Call all the transformation events.
+  jvmtiError res = Transformer::RetransformClassesDirect(env,
+                                                         self,
+                                                         &def_vector);
+  if (res != OK) {
+    // Something went wrong with transformation!
+    return res;
+  }
+  return RedefineClassesDirect(env, runtime, self, def_vector, error_msg);
+}
+
+jvmtiError Redefiner::RedefineClassesDirect(ArtJvmTiEnv* env,
+                                            art::Runtime* runtime,
+                                            art::Thread* self,
+                                            const std::vector<ArtClassDefinition>& definitions,
+                                            std::string* error_msg) {
+  DCHECK(env != nullptr);
+  if (definitions.size() == 0) {
+    // We don't actually need to do anything. Just return OK.
+    return OK;
+  }
   // Stop JIT for the duration of this redefine since the JIT might concurrently compile a method we
   // are going to redefine.
   art::jit::ScopedJitSuspend suspend_jit;
   // Get shared mutator lock so we can lock all the classes.
   art::ScopedObjectAccess soa(self);
   std::vector<Redefiner::ClassRedefinition> redefinitions;
-  redefinitions.reserve(class_count);
+  redefinitions.reserve(definitions.size());
   Redefiner r(runtime, self, error_msg);
-  for (jint i = 0; i < class_count; i++) {
-    jvmtiError res = r.AddRedefinition(env, definitions[i]);
-    if (res != OK) {
-      return res;
+  for (const ArtClassDefinition& def : definitions) {
+    // Only try to transform classes that have been modified.
+    if (def.modified) {
+      jvmtiError res = r.AddRedefinition(env, def);
+      if (res != OK) {
+        return res;
+      }
     }
   }
   return r.Run();
 }
 
-jvmtiError Redefiner::AddRedefinition(ArtJvmTiEnv* env, const jvmtiClassDefinition& def) {
+jvmtiError Redefiner::AddRedefinition(ArtJvmTiEnv* env, const ArtClassDefinition& def) {
   std::string original_dex_location;
   jvmtiError ret = OK;
   if ((ret = GetClassLocation(env, def.klass, &original_dex_location))) {
     *error_msg_ = "Unable to get original dex file location!";
     return ret;
   }
-  std::unique_ptr<art::MemMap> map(MoveDataToMemMap(original_dex_location,
-                                                    def.class_byte_count,
-                                                    def.class_bytes,
-                                                    error_msg_));
-  std::ostringstream os;
   char* generic_ptr_unused = nullptr;
   char* signature_ptr = nullptr;
-  if (env->GetClassSignature(def.klass, &signature_ptr, &generic_ptr_unused) != OK) {
-    *error_msg_ = "A jclass passed in does not seem to be valid";
-    return ERR(INVALID_CLASS);
+  if ((ret = env->GetClassSignature(def.klass, &signature_ptr, &generic_ptr_unused)) != OK) {
+    *error_msg_ = "Unable to get class signature!";
+    return ret;
   }
-  // These will make sure we deallocate the signature.
-  JvmtiUniquePtr sig_unique_ptr(MakeJvmtiUniquePtr(env, signature_ptr));
   JvmtiUniquePtr generic_unique_ptr(MakeJvmtiUniquePtr(env, generic_ptr_unused));
+  JvmtiUniquePtr signature_unique_ptr(MakeJvmtiUniquePtr(env, signature_ptr));
+  std::unique_ptr<art::MemMap> map(MoveDataToMemMap(original_dex_location,
+                                                    def.dex_len,
+                                                    def.dex_data.get(),
+                                                    error_msg_));
+  std::ostringstream os;
   if (map.get() == nullptr) {
-    os << "Failed to create anonymous mmap for modified dex file of class " << signature_ptr
+    os << "Failed to create anonymous mmap for modified dex file of class " << def.name
        << "in dex file " << original_dex_location << " because: " << *error_msg_;
     *error_msg_ = os.str();
     return ERR(OUT_OF_MEMORY);
@@ -319,7 +366,7 @@
                                                                   /*verify_checksum*/true,
                                                                   error_msg_));
   if (dex_file.get() == nullptr) {
-    os << "Unable to load modified dex file for " << signature_ptr << ": " << *error_msg_;
+    os << "Unable to load modified dex file for " << def.name << ": " << *error_msg_;
     *error_msg_ = os.str();
     return ERR(INVALID_CLASS_FORMAT);
   }
@@ -989,17 +1036,16 @@
 // Performs updates to class that will allow us to verify it.
 void Redefiner::ClassRedefinition::UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
                                                art::ObjPtr<art::mirror::DexCache> new_dex_cache) {
-  const art::DexFile::ClassDef* class_def = art::OatFile::OatDexFile::FindClassDef(
-      *dex_file_, class_sig_.c_str(), art::ComputeModifiedUtf8Hash(class_sig_.c_str()));
-  DCHECK(class_def != nullptr);
-  UpdateMethods(mclass, new_dex_cache, *class_def);
+  DCHECK_EQ(dex_file_->NumClassDefs(), 1u);
+  const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(0);
+  UpdateMethods(mclass, new_dex_cache, class_def);
   UpdateFields(mclass);
 
   // Update the class fields.
   // Need to update class last since the ArtMethod gets its DexFile from the class (which is needed
   // to call GetReturnTypeDescriptor and GetParameterTypeList above).
   mclass->SetDexCache(new_dex_cache.Ptr());
-  mclass->SetDexClassDefIndex(dex_file_->GetIndexForClassDef(*class_def));
+  mclass->SetDexClassDefIndex(dex_file_->GetIndexForClassDef(class_def));
   mclass->SetDexTypeIndex(dex_file_->GetIndexForTypeId(*dex_file_->FindTypeId(class_sig_.c_str())));
 }