Never go to resolution while inspecting inlined frames.

Instead, do a manual inspection and decoding of the invoke
with the dex cache.

Also update oatdump to dump types in the dex cache.

bug:27858645
Change-Id: I7c0b612ee96e6865fa438c3a1d253686231337bd
test:run-test
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index bb35f8d..3f031a3 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1751,7 +1751,7 @@
         const auto& method_section = state->image_header_.GetMethodsSection();
         size_t num_methods = dex_cache->NumResolvedMethods();
         if (num_methods != 0u) {
-          os << "Methods (size=" << num_methods << "):";
+          os << "Methods (size=" << num_methods << "):\n";
           ScopedIndentation indent2(&state->vios_);
           auto* resolved_methods = dex_cache->GetResolvedMethods();
           for (size_t i = 0, length = dex_cache->NumResolvedMethods(); i < length; ++i) {
@@ -1760,10 +1760,12 @@
                                                              image_pointer_size);
             size_t run = 0;
             for (size_t j = i + 1;
-                j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_methods,
-                                                                           j,
-                                                                           image_pointer_size);
-                ++j, ++run) {}
+                 j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_methods,
+                                                                            j,
+                                                                            image_pointer_size);
+                 ++j) {
+              ++run;
+            }
             if (run == 0) {
               os << StringPrintf("%zd: ", i);
             } else {
@@ -1784,17 +1786,20 @@
         }
         size_t num_fields = dex_cache->NumResolvedFields();
         if (num_fields != 0u) {
-          os << "Fields (size=" << num_fields << "):";
+          os << "Fields (size=" << num_fields << "):\n";
           ScopedIndentation indent2(&state->vios_);
           auto* resolved_fields = dex_cache->GetResolvedFields();
           for (size_t i = 0, length = dex_cache->NumResolvedFields(); i < length; ++i) {
-            auto* elem = mirror::DexCache::GetElementPtrSize(resolved_fields, i, image_pointer_size);
+            auto* elem = mirror::DexCache::GetElementPtrSize(
+                resolved_fields, i, image_pointer_size);
             size_t run = 0;
             for (size_t j = i + 1;
-                j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_fields,
-                                                                           j,
-                                                                           image_pointer_size);
-                ++j, ++run) {}
+                 j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_fields,
+                                                                            j,
+                                                                            image_pointer_size);
+                 ++j) {
+              ++run;
+            }
             if (run == 0) {
               os << StringPrintf("%zd: ", i);
             } else {
@@ -1813,6 +1818,32 @@
             os << StringPrintf("%p   %s\n", elem, msg.c_str());
           }
         }
+        size_t num_types = dex_cache->NumResolvedTypes();
+        if (num_types != 0u) {
+          os << "Types (size=" << num_types << "):\n";
+          ScopedIndentation indent2(&state->vios_);
+          auto* resolved_types = dex_cache->GetResolvedTypes();
+          for (size_t i = 0; i < num_types; ++i) {
+            auto* elem = resolved_types[i].Read();
+            size_t run = 0;
+            for (size_t j = i + 1; j != num_types && elem == resolved_types[j].Read(); ++j) {
+              ++run;
+            }
+            if (run == 0) {
+              os << StringPrintf("%zd: ", i);
+            } else {
+              os << StringPrintf("%zd to %zd: ", i, i + run);
+              i = i + run;
+            }
+            std::string msg;
+            if (elem == nullptr) {
+              msg = "null";
+            } else {
+              msg = PrettyClass(elem);
+            }
+            os << StringPrintf("%p   %s\n", elem, msg.c_str());
+          }
+        }
       }
     }
     std::string temp;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index fe7448f..3ec8f21 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2536,6 +2536,10 @@
   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/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index fc62573..b3170fa 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -39,45 +39,83 @@
 
 namespace art {
 
-template <bool kResolve = true>
 inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method,
                                     const InlineInfo& inline_info,
                                     const InlineInfoEncoding& encoding,
                                     uint8_t inlining_depth)
-  SHARED_REQUIRES(Locks::mutator_lock_) {
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  // This method is being used by artQuickResolutionTrampoline, before it sets up
+  // the passed parameters in a GC friendly way. Therefore we must never be
+  // suspended while executing it.
+  ScopedAssertNoThreadSuspension sants(Thread::Current(), __FUNCTION__);
+
   uint32_t method_index = inline_info.GetMethodIndexAtDepth(encoding, inlining_depth);
   InvokeType invoke_type = static_cast<InvokeType>(
         inline_info.GetInvokeTypeAtDepth(encoding, inlining_depth));
-  ArtMethod* caller = outer_method->GetDexCacheResolvedMethod(method_index, sizeof(void*));
-  if (!caller->IsRuntimeMethod()) {
-    return caller;
-  }
-  if (!kResolve) {
-    return nullptr;
+  ArtMethod* inlined_method = outer_method->GetDexCacheResolvedMethod(method_index, sizeof(void*));
+  if (!inlined_method->IsRuntimeMethod()) {
+    return inlined_method;
   }
 
-  // The method in the dex cache can be the runtime method responsible for invoking
+  // 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 class loader of our caller. If it is the outer method, we can directly
-  // use its class loader. Otherwise, we also need to resolve our caller.
-  StackHandleScope<2> hs(Thread::Current());
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  MutableHandle<mirror::ClassLoader> class_loader(hs.NewHandle<mirror::Class>(nullptr));
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(outer_method->GetDexCache()));
-  if (inlining_depth == 0) {
-    class_loader.Assign(outer_method->GetClassLoader());
+  // 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.
+  ArtMethod* caller = outer_method;
+  if (inlining_depth != 0) {
+    caller = GetResolvedMethod(outer_method,
+                               inline_info,
+                               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", sizeof(void*));
   } else {
-    caller = GetResolvedMethod<kResolve>(outer_method,
-                                         inline_info,
-                                         encoding,
-                                         inlining_depth - 1);
-    class_loader.Assign(caller->GetClassLoader());
+    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, sizeof(void*));
+        break;
+      case kSuper:
+      case kVirtual:
+        inlined_method =
+            klass->FindVirtualMethod(klass->GetDexCache(), method_index, sizeof(void*));
+        break;
+      default:
+        LOG(FATAL) << "Unimplemented inlined invocation type: " << invoke_type;
+        UNREACHABLE();
+    }
   }
 
-  return class_linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
-      *outer_method->GetDexFile(), method_index, dex_cache, class_loader, nullptr, invoke_type);
+  // 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, sizeof(void*));
+  return inlined_method;
 }
 
 inline ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type)
diff --git a/runtime/gc/allocation_record.cc b/runtime/gc/allocation_record.cc
index d9f1507..6489a39 100644
--- a/runtime/gc/allocation_record.cc
+++ b/runtime/gc/allocation_record.cc
@@ -187,7 +187,7 @@
  public:
   AllocRecordStackVisitor(Thread* thread, size_t max_depth, AllocRecordStackTrace* trace_out)
       SHARED_REQUIRES(Locks::mutator_lock_)
-      : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFramesNoResolve),
+      : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
         max_depth_(max_depth),
         trace_(trace_out) {}
 
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 71c866f..396c946 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -220,7 +220,7 @@
 struct NthCallerWithDexPcVisitor FINAL : public StackVisitor {
   explicit NthCallerWithDexPcVisitor(Thread* thread, size_t frame)
       SHARED_REQUIRES(Locks::mutator_lock_)
-      : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFramesNoResolve),
+      : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
         method_(nullptr),
         dex_pc_(0),
         current_frame_number_(0),
diff --git a/runtime/stack.cc b/runtime/stack.cc
index a5ca527..1d913f2 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -131,16 +131,10 @@
       const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
       CodeInfoEncoding encoding = method_header->GetOptimizedCodeInfo().ExtractEncoding();
       DCHECK(walk_kind_ != StackWalkKind::kSkipInlinedFrames);
-      bool allow_resolve = walk_kind_ != StackWalkKind::kIncludeInlinedFramesNoResolve;
-      return allow_resolve
-          ? GetResolvedMethod<true>(*GetCurrentQuickFrame(),
-                                    inline_info,
-                                    encoding.inline_info_encoding,
-                                    depth_in_stack_map)
-          : GetResolvedMethod<false>(*GetCurrentQuickFrame(),
-                                     inline_info,
-                                     encoding.inline_info_encoding,
-                                     depth_in_stack_map);
+      return GetResolvedMethod(*GetCurrentQuickFrame(),
+                               inline_info,
+                               encoding.inline_info_encoding,
+                               depth_in_stack_map);
     } else {
       return *cur_quick_frame_;
     }
@@ -791,8 +785,7 @@
         cur_oat_quick_method_header_ = method->GetOatQuickMethodHeader(cur_quick_frame_pc_);
         SanityCheckFrame();
 
-        if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames ||
-             walk_kind_ == StackWalkKind::kIncludeInlinedFramesNoResolve)
+        if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames)
             && (cur_oat_quick_method_header_ != nullptr)
             && cur_oat_quick_method_header_->IsOptimized()) {
           CodeInfo code_info = cur_oat_quick_method_header_->GetOptimizedCodeInfo();
diff --git a/runtime/stack.h b/runtime/stack.h
index e77ab46..84b665e 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -568,7 +568,6 @@
   // when walking the stack.
   enum class StackWalkKind {
     kIncludeInlinedFrames,
-    kIncludeInlinedFramesNoResolve,
     kSkipInlinedFrames,
   };