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/art_method-inl.h b/runtime/art_method-inl.h
index 96976d9..9c20740 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -121,7 +121,7 @@
 inline uint32_t ArtMethod::GetDexMethodIndex() {
   DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsIdxLoaded() ||
          GetDeclaringClass()->IsErroneous());
-  return dex_method_index_;
+  return GetDexMethodIndexUnchecked();
 }
 
 inline ArtMethod** ArtMethod::GetDexCacheResolvedMethods(PointerSize pointer_size) {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 11dcc35..2c31f6c 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -322,6 +322,9 @@
   // Number of 32bit registers that would be required to hold all the arguments
   static size_t NumArgRegisters(const StringPiece& shorty);
 
+  ALWAYS_INLINE uint32_t GetDexMethodIndexUnchecked() {
+    return dex_method_index_;
+  }
   ALWAYS_INLINE uint32_t GetDexMethodIndex() REQUIRES_SHARED(Locks::mutator_lock_);
 
   void SetDexMethodIndex(uint32_t new_idx) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c9b2cc8..8220ba4 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2700,10 +2700,6 @@
   CHECK(h_new_class.Get() != nullptr) << descriptor;
   CHECK(h_new_class->IsResolved()) << descriptor;
 
-  // Update the dex cache of where the class is defined. Inlining depends on having
-  // this filled.
-  h_new_class->GetDexCache()->SetResolvedType(h_new_class->GetDexTypeIndex(), h_new_class.Get());
-
   // Instrumentation may have updated entrypoints for all methods of all
   // classes. However it could not update methods of this class while we
   // were loading it. Now the class is resolved, we can update entrypoints
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 42108d8..8518b08 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -899,7 +899,6 @@
   dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
   ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
   const DexFile& dex_file = klass->GetDexFile();
-  EXPECT_OBJ_PTR_EQ(dex_cache->GetResolvedType(type_idx), klass);
   EXPECT_OBJ_PTR_EQ(
       class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader.Get()),
       klass);
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;
 }
 
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index a7e7c21..9ebf9a7 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -18,8 +18,9 @@
 
 #include <stdint.h>
 
+#include "art_method.h"
 #include "indenter.h"
-#include "invoke_type.h"
+#include "scoped_thread_state_change-inl.h"
 
 namespace art {
 
@@ -106,7 +107,7 @@
       << "InlineInfoEncoding"
       << " (method_index_bit_offset=" << static_cast<uint32_t>(kMethodIndexBitOffset)
       << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
-      << ", invoke_type_bit_offset=" << static_cast<uint32_t>(invoke_type_bit_offset_)
+      << ", extra_data_bit_offset=" << static_cast<uint32_t>(extra_data_bit_offset_)
       << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
       << ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_)
       << ")\n";
@@ -230,12 +231,16 @@
     vios->Stream()
         << " At depth " << i
         << std::hex
-        << " (dex_pc=0x" << GetDexPcAtDepth(inline_info_encoding, i)
-        << std::dec
-        << ", method_index=" << GetMethodIndexAtDepth(inline_info_encoding, i)
-        << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(inline_info_encoding,
-                                                                            i))
-        << ")\n";
+        << " (dex_pc=0x" << GetDexPcAtDepth(inline_info_encoding, i);
+    if (EncodesArtMethodAtDepth(inline_info_encoding, i)) {
+      ScopedObjectAccess soa(Thread::Current());
+      vios->Stream() << ", method=" << GetArtMethodAtDepth(inline_info_encoding, i)->PrettyMethod();
+    } else {
+      vios->Stream()
+          << std::dec
+          << ", method_index=" << GetMethodIndexAtDepth(inline_info_encoding, i);
+    }
+    vios->Stream() << ")\n";
     if (HasDexRegisterMapAtDepth(inline_info_encoding, i) && (number_of_dex_registers != nullptr)) {
       CodeInfoEncoding encoding = code_info.ExtractEncoding();
       DexRegisterMap dex_register_map =
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 5e556be..15d7816 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -35,6 +35,7 @@
 // Size of Dex virtual registers.
 static constexpr size_t kVRegSize = 4;
 
+class ArtMethod;
 class CodeInfo;
 class StackMapEncoding;
 struct CodeInfoEncoding;
@@ -887,7 +888,7 @@
  public:
   void SetFromSizes(size_t method_index_max,
                     size_t dex_pc_max,
-                    size_t invoke_type_max,
+                    size_t extra_data_max,
                     size_t dex_register_map_size) {
     total_bit_size_ = kMethodIndexBitOffset;
     total_bit_size_ += MinimumBitsToStore(method_index_max);
@@ -899,8 +900,8 @@
       total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max);
     }
 
-    invoke_type_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
-    total_bit_size_ += MinimumBitsToStore(invoke_type_max);
+    extra_data_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
+    total_bit_size_ += MinimumBitsToStore(extra_data_max);
 
     // We also need +1 for kNoDexRegisterMap, but since the size is strictly
     // greater than any offset we might try to encode, we already implicitly have it.
@@ -912,10 +913,10 @@
     return FieldEncoding(kMethodIndexBitOffset, dex_pc_bit_offset_);
   }
   ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const {
-    return FieldEncoding(dex_pc_bit_offset_, invoke_type_bit_offset_, -1 /* min_value */);
+    return FieldEncoding(dex_pc_bit_offset_, extra_data_bit_offset_, -1 /* min_value */);
   }
-  ALWAYS_INLINE FieldEncoding GetInvokeTypeEncoding() const {
-    return FieldEncoding(invoke_type_bit_offset_, dex_register_map_bit_offset_);
+  ALWAYS_INLINE FieldEncoding GetExtraDataEncoding() const {
+    return FieldEncoding(extra_data_bit_offset_, dex_register_map_bit_offset_);
   }
   ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const {
     return FieldEncoding(dex_register_map_bit_offset_, total_bit_size_, -1 /* min_value */);
@@ -930,7 +931,7 @@
   static constexpr uint8_t kIsLastBitOffset = 0;
   static constexpr uint8_t kMethodIndexBitOffset = 1;
   uint8_t dex_pc_bit_offset_;
-  uint8_t invoke_type_bit_offset_;
+  uint8_t extra_data_bit_offset_;
   uint8_t dex_register_map_bit_offset_;
   uint8_t total_bit_size_;
 };
@@ -938,7 +939,11 @@
 /**
  * Inline information for a specific PC. The information is of the form:
  *
- *   [is_last, method_index, dex_pc, invoke_type, dex_register_map_offset]+.
+ *   [is_last,
+ *    method_index (or ArtMethod high bits),
+ *    dex_pc,
+ *    extra_data (ArtMethod low bits or 1),
+ *    dex_register_map_offset]+.
  */
 class InlineInfo {
  public:
@@ -960,6 +965,7 @@
 
   ALWAYS_INLINE uint32_t GetMethodIndexAtDepth(const InlineInfoEncoding& encoding,
                                                uint32_t depth) const {
+    DCHECK(!EncodesArtMethodAtDepth(encoding, depth));
     return encoding.GetMethodIndexEncoding().Load(GetRegionAtDepth(encoding, depth));
   }
 
@@ -980,15 +986,28 @@
     encoding.GetDexPcEncoding().Store(GetRegionAtDepth(encoding, depth), dex_pc);
   }
 
-  ALWAYS_INLINE uint32_t GetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
-                                              uint32_t depth) const {
-    return encoding.GetInvokeTypeEncoding().Load(GetRegionAtDepth(encoding, depth));
+  ALWAYS_INLINE bool EncodesArtMethodAtDepth(const InlineInfoEncoding& encoding,
+                                             uint32_t depth) const {
+    return (encoding.GetExtraDataEncoding().Load(GetRegionAtDepth(encoding, depth)) & 1) == 0;
   }
 
-  ALWAYS_INLINE void SetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
-                                          uint32_t depth,
-                                          uint32_t invoke_type) {
-    encoding.GetInvokeTypeEncoding().Store(GetRegionAtDepth(encoding, depth), invoke_type);
+  ALWAYS_INLINE void SetExtraDataAtDepth(const InlineInfoEncoding& encoding,
+                                         uint32_t depth,
+                                         uint32_t extra_data) {
+    encoding.GetExtraDataEncoding().Store(GetRegionAtDepth(encoding, depth), extra_data);
+  }
+
+  ALWAYS_INLINE ArtMethod* GetArtMethodAtDepth(const InlineInfoEncoding& encoding,
+                                               uint32_t depth) const {
+    uint32_t low_bits = encoding.GetExtraDataEncoding().Load(GetRegionAtDepth(encoding, depth));
+    uint32_t high_bits = encoding.GetMethodIndexEncoding().Load(GetRegionAtDepth(encoding, depth));
+    if (high_bits == 0) {
+      return reinterpret_cast<ArtMethod*>(low_bits);
+    } else {
+      uint64_t address = high_bits;
+      address = address << 32;
+      return reinterpret_cast<ArtMethod*>(address | low_bits);
+    }
   }
 
   ALWAYS_INLINE uint32_t GetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding,
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index a5b275c..507ea16 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -103,6 +103,7 @@
 jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke;
 jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad;
 jmethodID WellKnownClasses::java_lang_Short_valueOf;
+jmethodID WellKnownClasses::java_lang_String_charAt;
 jmethodID WellKnownClasses::java_lang_System_runFinalization = nullptr;
 jmethodID WellKnownClasses::java_lang_Thread_dispatchUncaughtException;
 jmethodID WellKnownClasses::java_lang_Thread_init;
@@ -337,6 +338,7 @@
   java_lang_ref_ReferenceQueue_add = CacheMethod(env, java_lang_ref_ReferenceQueue.get(), true, "add", "(Ljava/lang/ref/Reference;)V");
 
   java_lang_reflect_Parameter_init = CacheMethod(env, java_lang_reflect_Parameter, false, "<init>", "(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V");
+  java_lang_String_charAt = CacheMethod(env, java_lang_String, false, "charAt", "(I)C");
   java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");
   java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
   java_lang_Thread_run = CacheMethod(env, java_lang_Thread, false, "run", "()V");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 371be61..b3ce3d1 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -113,6 +113,7 @@
   static jmethodID java_lang_reflect_Proxy_invoke;
   static jmethodID java_lang_Runtime_nativeLoad;
   static jmethodID java_lang_Short_valueOf;
+  static jmethodID java_lang_String_charAt;
   static jmethodID java_lang_System_runFinalization;
   static jmethodID java_lang_Thread_dispatchUncaughtException;
   static jmethodID java_lang_Thread_init;