Put inlined ArtMethod pointer in stack maps.

Currently done for JIT. Can be extended for AOT and inlined boot
image methods.

Also refactor the lookup of a inlined method at runtime to not
rely on the dex cache, but look at the class loader tables.

bug: 30933338
test: test-art-host, test-art-target
Change-Id: I58bd4d763b82ab8ca3023742835ac388671d1794
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 14c9c21..72dad0c 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -52,21 +52,19 @@
   // suspended while executing it.
   ScopedAssertNoThreadSuspension sants(__FUNCTION__);
 
+  if (inline_info.EncodesArtMethodAtDepth(encoding, inlining_depth)) {
+    return inline_info.GetArtMethodAtDepth(encoding, inlining_depth);
+  }
+
   uint32_t method_index = inline_info.GetMethodIndexAtDepth(encoding, inlining_depth);
-  InvokeType invoke_type = static_cast<InvokeType>(
-        inline_info.GetInvokeTypeAtDepth(encoding, inlining_depth));
-  ArtMethod* inlined_method = outer_method->GetDexCacheResolvedMethod(method_index,
-                                                                      kRuntimePointerSize);
-  if (!inlined_method->IsRuntimeMethod()) {
+  if (inline_info.GetDexPcAtDepth(encoding, inlining_depth) == static_cast<uint32_t>(-1)) {
+    // "charAt" special case. It is the only non-leaf method we inline across dex files.
+    ArtMethod* inlined_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt);
+    DCHECK_EQ(inlined_method->GetDexMethodIndex(), method_index);
     return inlined_method;
   }
 
-  // The method in the dex cache is the runtime method responsible for invoking
-  // the stub that will then update the dex cache. Therefore, we need to do the
-  // resolution ourselves.
-
-  // We first find the dex cache of our caller. If it is the outer method, we can directly
-  // use its dex cache. Otherwise, we also need to resolve our caller.
+  // Find which method did the call in the inlining hierarchy.
   ArtMethod* caller = outer_method;
   if (inlining_depth != 0) {
     caller = GetResolvedMethod(outer_method,
@@ -74,51 +72,38 @@
                                encoding,
                                inlining_depth - 1);
   }
-  DCHECK_EQ(caller->GetDexCache(), outer_method->GetDexCache())
-      << "Compiler only supports inlining calls within the same dex cache";
-  const DexFile* dex_file = outer_method->GetDexFile();
-  const DexFile::MethodId& method_id = dex_file->GetMethodId(method_index);
 
-  if (inline_info.GetDexPcAtDepth(encoding, inlining_depth) == static_cast<uint32_t>(-1)) {
-    // "charAt" special case. It is the only non-leaf method we inline across dex files.
-    if (kIsDebugBuild) {
-      const char* name = dex_file->StringDataByIdx(method_id.name_idx_);
-      DCHECK_EQ(std::string(name), "charAt");
-      DCHECK_EQ(std::string(dex_file->GetMethodShorty(method_id)), "CI")
-          << std::string(dex_file->GetMethodShorty(method_id));
-      DCHECK_EQ(std::string(dex_file->StringByTypeIdx(method_id.class_idx_)), "Ljava/lang/String;")
-          << std::string(dex_file->StringByTypeIdx(method_id.class_idx_));
-    }
-    mirror::Class* cls =
-        Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kJavaLangString);
-    // Update the dex cache for future lookups.
-    caller->GetDexCache()->SetResolvedType(method_id.class_idx_, cls);
-    inlined_method = cls->FindVirtualMethod("charAt", "(I)C", kRuntimePointerSize);
-  } else {
-    mirror::Class* klass = caller->GetDexCache()->GetResolvedType(method_id.class_idx_);
-    DCHECK_EQ(klass->GetDexCache(), caller->GetDexCache())
-        << "Compiler only supports inlining calls within the same dex cache";
-    switch (invoke_type) {
-      case kDirect:
-      case kStatic:
-        inlined_method =
-            klass->FindDirectMethod(klass->GetDexCache(), method_index, kRuntimePointerSize);
-        break;
-      case kSuper:
-      case kVirtual:
-        inlined_method =
-            klass->FindVirtualMethod(klass->GetDexCache(), method_index, kRuntimePointerSize);
-        break;
-      default:
-        LOG(FATAL) << "Unimplemented inlined invocation type: " << invoke_type;
-        UNREACHABLE();
+  // Lookup the declaring class of the inlined method.
+  const DexFile* dex_file = caller->GetDexFile();
+  const DexFile::MethodId& method_id = dex_file->GetMethodId(method_index);
+  const char* descriptor = dex_file->StringByTypeIdx(method_id.class_idx_);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Thread* self = Thread::Current();
+  mirror::ClassLoader* class_loader = caller->GetDeclaringClass()->GetClassLoader();
+  mirror::Class* klass = class_linker->LookupClass(self, descriptor, class_loader);
+  if (klass == nullptr) {
+      LOG(FATAL) << "Could not find an inlined method from an .oat file: "
+                 << "the class " << descriptor << " was not found in the class loader of "
+                 << caller->PrettyMethod() << ". "
+                 << "This must be due to playing wrongly with class loaders";
+  }
+
+  // Lookup the method.
+  const char* method_name = dex_file->GetMethodName(method_id);
+  const Signature signature = dex_file->GetMethodSignature(method_id);
+
+  ArtMethod* inlined_method =
+      klass->FindDeclaredDirectMethod(method_name, signature, kRuntimePointerSize);
+  if (inlined_method == nullptr) {
+    inlined_method = klass->FindDeclaredVirtualMethod(method_name, signature, kRuntimePointerSize);
+    if (inlined_method == nullptr) {
+      LOG(FATAL) << "Could not find an inlined method from an .oat file: "
+                 << "the class " << descriptor << " does not have "
+                 << method_name << signature << " declared. "
+                 << "This must be due to duplicate classes or playing wrongly with class loaders";
     }
   }
 
-  // Update the dex cache for future lookups. Note that for static methods, this is safe
-  // when the class is being initialized, as the entrypoint for the ArtMethod is at
-  // this point still the resolution trampoline.
-  outer_method->SetDexCacheResolvedMethod(method_index, inlined_method, kRuntimePointerSize);
   return inlined_method;
 }