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/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,
};