Infrastructure for obsolete methods

This adds some of the structures and functions needed to eventually
support obsolete methods. Specifically this adds the code to create
and iterate through the obsolete dex-cache maps of classes and
re-organizes the redefinition code to be more sensible and extensible.

Bug: 32369913
Test: ./test/run-test --host 902
Test: mma -j40 test-art-host

Change-Id: I93d60fa66e7512e8b059cdf42af8a56e93ef4bd7
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index 7bb5205..f7b8b92 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -29,8 +29,12 @@
  * questions.
  */
 
+#include <unordered_map>
+#include <unordered_set>
+
 #include "transform.h"
 
+#include "art_method.h"
 #include "class_linker.h"
 #include "dex_file.h"
 #include "dex_file_types.h"
@@ -46,6 +50,7 @@
 #include "mirror/string-inl.h"
 #include "oat_file.h"
 #include "scoped_thread_state_change-inl.h"
+#include "stack.h"
 #include "thread_list.h"
 #include "transform.h"
 #include "utf.h"
@@ -53,196 +58,7 @@
 
 namespace openjdkjvmti {
 
-static bool ReadChecksum(jint data_len, const unsigned char* dex, /*out*/uint32_t* res) {
-  if (data_len < static_cast<jint>(sizeof(art::DexFile::Header))) {
-    return false;
-  }
-  *res = reinterpret_cast<const art::DexFile::Header*>(dex)->checksum_;
-  return true;
-}
-
-static std::unique_ptr<art::MemMap> MoveDataToMemMap(const std::string& original_location,
-                                                      jint data_len,
-                                                      unsigned char* dex_data) {
-  std::string error_msg;
-  std::unique_ptr<art::MemMap> map(art::MemMap::MapAnonymous(
-      art::StringPrintf("%s-transformed", original_location.c_str()).c_str(),
-      nullptr,
-      data_len,
-      PROT_READ|PROT_WRITE,
-      /*low_4gb*/false,
-      /*reuse*/false,
-      &error_msg));
-  if (map == nullptr) {
-    return map;
-  }
-  memcpy(map->Begin(), dex_data, data_len);
-  map->Protect(PROT_READ);
-  return map;
-}
-
-static void InvalidateExistingMethods(art::Thread* self,
-                                      art::Handle<art::mirror::Class> klass,
-                                      art::Handle<art::mirror::DexCache> cache,
-                                      const art::DexFile* dex_file)
-    REQUIRES_SHARED(art::Locks::mutator_lock_) {
-  // Create new DexCache with new DexFile.
-  // reset dex_class_def_idx_
-  // for each method reset entry_point_from_quick_compiled_code_ to bridge
-  // for each method reset dex_code_item_offset_
-  // for each method reset dex_method_index_
-  // for each method set dex_cache_resolved_methods_ to new DexCache
-  // for each method set dex_cache_resolved_types_ to new DexCache
-  auto* runtime = art::Runtime::Current();
-  art::ClassLinker* linker = runtime->GetClassLinker();
-  art::PointerSize image_pointer_size = linker->GetImagePointerSize();
-  std::string descriptor_storage;
-  const char* descriptor = klass->GetDescriptor(&descriptor_storage);
-  // Get the new class def
-  const art::DexFile::ClassDef* class_def = art::OatFile::OatDexFile::FindClassDef(
-      *dex_file, descriptor, art::ComputeModifiedUtf8Hash(descriptor));
-  CHECK(class_def != nullptr);
-  const art::DexFile::TypeId& declaring_class_id = dex_file->GetTypeId(class_def->class_idx_);
-  art::StackHandleScope<6> hs(self);
-  const art::DexFile& old_dex_file = klass->GetDexFile();
-  for (art::ArtMethod& method : klass->GetMethods(image_pointer_size)) {
-    // Find the code_item for the method then find the dex_method_index and dex_code_item_offset to
-    // set.
-    const art::DexFile::StringId* new_name_id = dex_file->FindStringId(method.GetName());
-    art::dex::TypeIndex method_return_idx =
-        dex_file->GetIndexForTypeId(*dex_file->FindTypeId(method.GetReturnTypeDescriptor()));
-    const auto* old_type_list = method.GetParameterTypeList();
-    std::vector<art::dex::TypeIndex> new_type_list;
-    for (uint32_t i = 0; old_type_list != nullptr && i < old_type_list->Size(); i++) {
-      new_type_list.push_back(
-          dex_file->GetIndexForTypeId(
-              *dex_file->FindTypeId(
-                  old_dex_file.GetTypeDescriptor(
-                      old_dex_file.GetTypeId(
-                          old_type_list->GetTypeItem(i).type_idx_)))));
-    }
-    const art::DexFile::ProtoId* proto_id = dex_file->FindProtoId(method_return_idx,
-                                                                  new_type_list);
-    CHECK(proto_id != nullptr || old_type_list == nullptr);
-    const art::DexFile::MethodId* method_id = dex_file->FindMethodId(declaring_class_id,
-                                                                      *new_name_id,
-                                                                      *proto_id);
-    CHECK(method_id != nullptr);
-    uint32_t dex_method_idx = dex_file->GetIndexForMethodId(*method_id);
-    method.SetDexMethodIndex(dex_method_idx);
-    linker->SetEntryPointsToInterpreter(&method);
-    method.SetCodeItemOffset(dex_file->FindCodeItemOffset(*class_def, dex_method_idx));
-    method.SetDexCacheResolvedMethods(cache->GetResolvedMethods(), image_pointer_size);
-    method.SetDexCacheResolvedTypes(cache->GetResolvedTypes(), image_pointer_size);
-  }
-
-  // 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).
-  klass->SetDexCache(cache.Get());
-  klass->SetDexCacheStrings(cache->GetStrings());
-  klass->SetDexClassDefIndex(dex_file->GetIndexForClassDef(*class_def));
-  klass->SetDexTypeIndex(dex_file->GetIndexForTypeId(*dex_file->FindTypeId(descriptor)));
-}
-
-// Adds the dex file.
-static art::mirror::LongArray* InsertDexFileIntoArray(art::Thread* self,
-                                                      const art::DexFile* dex,
-                                                      art::Handle<art::mirror::LongArray>& orig)
-    REQUIRES_SHARED(art::Locks::mutator_lock_) {
-  art::StackHandleScope<1> hs(self);
-  CHECK_GE(orig->GetLength(), 1);
-  art::Handle<art::mirror::LongArray> ret(
-      hs.NewHandle(art::mirror::LongArray::Alloc(self, orig->GetLength() + 1)));
-  CHECK(ret.Get() != nullptr);
-  // Copy the oat-dex.
-  // TODO Should I clear the oatdex element?
-  ret->SetWithoutChecks<false>(0, orig->GetWithoutChecks(0));
-  ret->SetWithoutChecks<false>(1, static_cast<int64_t>(reinterpret_cast<intptr_t>(dex)));
-  ret->Memcpy(2, orig.Get(), 1, orig->GetLength() - 1);
-  return ret.Get();
-}
-
-// TODO Handle all types of class loaders.
-static bool FindDalvikSystemDexFileAndLoaderForClass(
-    art::Handle<art::mirror::Class> klass,
-    /*out*/art::mirror::Object** dex_file,
-    /*out*/art::mirror::ClassLoader** loader)
-      REQUIRES_SHARED(art::Locks::mutator_lock_) {
-  const char* dex_path_list_element_array_name = "[Ldalvik/system/DexPathList$Element;";
-  const char* dex_path_list_element_name = "Ldalvik/system/DexPathList$Element;";
-  const char* dex_file_name = "Ldalvik/system/DexFile;";
-  const char* dex_path_list_name = "Ldalvik/system/DexPathList;";
-  const char* dex_class_loader_name = "Ldalvik/system/BaseDexClassLoader;";
-
-  art::Thread* self = art::Thread::Current();
-  CHECK(!self->IsExceptionPending());
-  art::StackHandleScope<11> hs(self);
-  art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
-
-  art::Handle<art::mirror::ClassLoader> null_loader(hs.NewHandle<art::mirror::ClassLoader>(
-      nullptr));
-  art::Handle<art::mirror::Class> base_dex_loader_class(hs.NewHandle(class_linker->FindClass(
-      self, dex_class_loader_name, null_loader)));
-
-  art::ArtField* path_list_field = base_dex_loader_class->FindDeclaredInstanceField(
-      "pathList", dex_path_list_name);
-  CHECK(path_list_field != nullptr);
-
-  art::ArtField* dex_path_list_element_field =
-      class_linker->FindClass(self, dex_path_list_name, null_loader)
-        ->FindDeclaredInstanceField("dexElements", dex_path_list_element_array_name);
-  CHECK(dex_path_list_element_field != nullptr);
-
-  art::ArtField* element_dex_file_field =
-      class_linker->FindClass(self, dex_path_list_element_name, null_loader)
-        ->FindDeclaredInstanceField("dexFile", dex_file_name);
-  CHECK(element_dex_file_field != nullptr);
-
-  art::Handle<art::mirror::ClassLoader> h_class_loader(hs.NewHandle(klass->GetClassLoader()));
-  art::Handle<art::mirror::Class> loader_class(hs.NewHandle(h_class_loader->GetClass()));
-  // Check if loader is a BaseDexClassLoader
-  if (!loader_class->IsSubClass(base_dex_loader_class.Get())) {
-    LOG(ERROR) << "The classloader is not a BaseDexClassLoader which is currently the only "
-               << "supported class loader type!";
-    return false;
-  }
-  art::Handle<art::mirror::Object> path_list(
-      hs.NewHandle(path_list_field->GetObject(h_class_loader.Get())));
-  CHECK(path_list.Get() != nullptr);
-  CHECK(!self->IsExceptionPending());
-  art::Handle<art::mirror::ObjectArray<art::mirror::Object>> dex_elements_list(hs.NewHandle(
-      dex_path_list_element_field->GetObject(path_list.Get())->
-      AsObjectArray<art::mirror::Object>()));
-  CHECK(!self->IsExceptionPending());
-  CHECK(dex_elements_list.Get() != nullptr);
-  size_t num_elements = dex_elements_list->GetLength();
-  art::MutableHandle<art::mirror::Object> current_element(
-      hs.NewHandle<art::mirror::Object>(nullptr));
-  art::MutableHandle<art::mirror::Object> first_dex_file(
-      hs.NewHandle<art::mirror::Object>(nullptr));
-  for (size_t i = 0; i < num_elements; i++) {
-    current_element.Assign(dex_elements_list->Get(i));
-    CHECK(current_element.Get() != nullptr);
-    CHECK(!self->IsExceptionPending());
-    CHECK(dex_elements_list.Get() != nullptr);
-    CHECK_EQ(current_element->GetClass(), class_linker->FindClass(self,
-                                                                  dex_path_list_element_name,
-                                                                  null_loader));
-    // TODO It would be cleaner to put the art::DexFile into the dalvik.system.DexFile the class
-    // comes from but it is more annoying because we would need to find this class. It is not
-    // necessary for proper function since we just need to be in front of the classes old dex file
-    // in the path.
-    first_dex_file.Assign(element_dex_file_field->GetObject(current_element.Get()));
-    if (first_dex_file.Get() != nullptr) {
-      *dex_file = first_dex_file.Get();
-      *loader = h_class_loader.Get();
-      return true;
-    }
-  }
-  return false;
-}
-
+// TODO Move this function somewhere more appropriate.
 // Gets the data surrounding the given class.
 jvmtiError GetTransformationData(ArtJvmTiEnv* env,
                                  jclass klass,
@@ -281,83 +97,4 @@
   return OK;
 }
 
-// Install the new dex file.
-// TODO do error checks for bad state (method in a stack, changes to number of methods/fields/etc).
-jvmtiError MoveTransformedFileIntoRuntime(jclass jklass,
-                                          const std::string& original_location,
-                                          jint data_len,
-                                          unsigned char* dex_data) {
-  const char* dex_file_name = "Ldalvik/system/DexFile;";
-  art::Thread* self = art::Thread::Current();
-  art::Runtime* runtime = art::Runtime::Current();
-  art::ThreadList* threads = runtime->GetThreadList();
-  art::ClassLinker* class_linker = runtime->GetClassLinker();
-  uint32_t checksum = 0;
-  if (!ReadChecksum(data_len, dex_data, &checksum)) {
-    return ERR(INVALID_CLASS_FORMAT);
-  }
-
-  std::unique_ptr<art::MemMap> map(MoveDataToMemMap(original_location, data_len, dex_data));
-  if (map.get() == nullptr) {
-    return ERR(INTERNAL);
-  }
-  std::string error_msg;
-  // Load the new dex_data in memory (mmap it, etc)
-  std::unique_ptr<const art::DexFile> new_dex_file = art::DexFile::Open(map->GetName(),
-                                                                        checksum,
-                                                                        std::move(map),
-                                                                        /*verify*/ true,
-                                                                        /*verify_checksum*/ true,
-                                                                        &error_msg);
-  CHECK(new_dex_file.get() != nullptr) << "Unable to load dex file! " << error_msg;
-
-  // Get mutator lock. We need the lifetimes of these variables (hs, the classes, etc.) to be longer
-  // then current lock (since there isn't upgrading of the lock) so we don't use soa.
-  art::ThreadState old_state = self->TransitionFromSuspendedToRunnable();
-  // This scope is needed to make sure that the HandleScope dies with mutator_lock_ since we need to
-  // upgrade the mutator_lock during the execution.
-  {
-    art::StackHandleScope<11> hs(self);
-    art::Handle<art::mirror::ClassLoader> null_loader(
-        hs.NewHandle<art::mirror::ClassLoader>(nullptr));
-    CHECK(null_loader.Get() == nullptr);
-    art::ArtField* dex_file_cookie_field = class_linker->
-        FindClass(self, dex_file_name, null_loader)->
-        FindDeclaredInstanceField("mCookie", "Ljava/lang/Object;");
-    art::ArtField* dex_file_internal_cookie_field =
-        class_linker->FindClass(self, dex_file_name, null_loader)
-          ->FindDeclaredInstanceField("mInternalCookie", "Ljava/lang/Object;");
-    CHECK(dex_file_cookie_field != nullptr);
-    art::Handle<art::mirror::Class> klass(hs.NewHandle(self->DecodeJObject(jklass)->AsClass()));
-    art::mirror::Object* dex_file_ptr = nullptr;
-    art::mirror::ClassLoader* class_loader_ptr = nullptr;
-    // Find dalvik.system.DexFile that represents the dex file we are changing.
-    if (!FindDalvikSystemDexFileAndLoaderForClass(klass, &dex_file_ptr, &class_loader_ptr)) {
-      self->TransitionFromRunnableToSuspended(old_state);
-      LOG(ERROR) << "Could not find DexFile.";
-      return ERR(INTERNAL);
-    }
-    art::Handle<art::mirror::Object> dex_file_obj(hs.NewHandle(dex_file_ptr));
-    art::Handle<art::mirror::ClassLoader> class_loader(hs.NewHandle(class_loader_ptr));
-    art::Handle<art::mirror::LongArray> art_dex_array(
-        hs.NewHandle<art::mirror::LongArray>(
-            dex_file_cookie_field->GetObject(dex_file_obj.Get())->AsLongArray()));
-    art::Handle<art::mirror::LongArray> new_art_dex_array(
-        hs.NewHandle<art::mirror::LongArray>(
-            InsertDexFileIntoArray(self, new_dex_file.get(), art_dex_array)));
-    art::Handle<art::mirror::DexCache> cache(
-        hs.NewHandle(class_linker->RegisterDexFile(*new_dex_file.get(), class_loader.Get())));
-    self->TransitionFromRunnableToSuspended(old_state);
-
-    threads->SuspendAll("moving dex file into runtime", /*long_suspend*/true);
-    // Change the mCookie field. Old value will be GC'd as normal.
-    dex_file_cookie_field->SetObject<false>(dex_file_obj.Get(), new_art_dex_array.Get());
-    dex_file_internal_cookie_field->SetObject<false>(dex_file_obj.Get(), new_art_dex_array.Get());
-    // Invalidate existing methods.
-    InvalidateExistingMethods(self, klass, cache, new_dex_file.release());
-  }
-  threads->ResumeAll();
-  return OK;
-}
-
 }  // namespace openjdkjvmti