summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/instruction_builder.cc74
-rw-r--r--runtime/class_linker-inl.h17
-rw-r--r--runtime/class_linker.h6
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc7
4 files changed, 51 insertions, 53 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 12cb826395..126e856da8 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -662,6 +662,16 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass()));
+ // We fetch the referenced class eagerly (that is, the class pointed by in the MethodId
+ // at method_idx), as `CanAccessResolvedMethod` expects it be be in the dex cache.
+ Handle<mirror::Class> methods_class(hs.NewHandle(class_linker->ResolveReferencedClassOfMethod(
+ method_idx, dex_compilation_unit_->GetDexCache(), class_loader)));
+
+ if (UNLIKELY(methods_class.Get() == nullptr)) {
+ // Clean up any exception left by type resolution.
+ soa.Self()->ClearException();
+ return nullptr;
+ }
ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(
*dex_compilation_unit_->GetDexFile(),
@@ -700,47 +710,33 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in
DCHECK(Runtime::Current()->IsAotCompiler());
return nullptr;
}
- ArtMethod* current_method = graph_->GetArtMethod();
- DCHECK(current_method != nullptr);
- Handle<mirror::Class> methods_class(hs.NewHandle(
- dex_compilation_unit_->GetClassLinker()->ResolveReferencedClassOfMethod(Thread::Current(),
- method_idx,
- current_method)));
- if (methods_class.Get() == nullptr) {
- // Invoking a super method requires knowing the actual super class. If we did not resolve
- // the compiling method's declaring class (which only happens for ahead of time
- // compilation), bail out.
- DCHECK(Runtime::Current()->IsAotCompiler());
- return nullptr;
+ ArtMethod* actual_method;
+ if (methods_class->IsInterface()) {
+ actual_method = methods_class->FindVirtualMethodForInterfaceSuper(
+ resolved_method, class_linker->GetImagePointerSize());
} else {
- ArtMethod* actual_method;
- if (methods_class->IsInterface()) {
- actual_method = methods_class->FindVirtualMethodForInterfaceSuper(
- resolved_method, class_linker->GetImagePointerSize());
- } else {
- uint16_t vtable_index = resolved_method->GetMethodIndex();
- actual_method = compiling_class->GetSuperClass()->GetVTableEntry(
- vtable_index, class_linker->GetImagePointerSize());
- }
- if (actual_method != resolved_method &&
- !IsSameDexFile(*actual_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) {
- // The back-end code generator relies on this check in order to ensure that it will not
- // attempt to read the dex_cache with a dex_method_index that is not from the correct
- // dex_file. If we didn't do this check then the dex_method_index will not be updated in the
- // builder, which means that the code-generator (and compiler driver during sharpening and
- // inliner, maybe) might invoke an incorrect method.
- // TODO: The actual method could still be referenced in the current dex file, so we
- // could try locating it.
- // TODO: Remove the dex_file restriction.
- return nullptr;
- }
- if (!actual_method->IsInvokable()) {
- // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub
- // could resolve the callee to the wrong method.
- return nullptr;
- }
- resolved_method = actual_method;
+ uint16_t vtable_index = resolved_method->GetMethodIndex();
+ actual_method = compiling_class->GetSuperClass()->GetVTableEntry(
+ vtable_index, class_linker->GetImagePointerSize());
+ }
+ if (actual_method != resolved_method &&
+ !IsSameDexFile(*actual_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) {
+ // The back-end code generator relies on this check in order to ensure that it will not
+ // attempt to read the dex_cache with a dex_method_index that is not from the correct
+ // dex_file. If we didn't do this check then the dex_method_index will not be updated in the
+ // builder, which means that the code-generator (and compiler driver during sharpening and
+ // inliner, maybe) might invoke an incorrect method.
+ // TODO: The actual method could still be referenced in the current dex file, so we
+ // could try locating it.
+ // TODO: Remove the dex_file restriction.
+ return nullptr;
+ }
+ if (!actual_method->IsInvokable()) {
+ // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub
+ // could resolve the callee to the wrong method.
+ return nullptr;
}
+ resolved_method = actual_method;
}
// Check for incompatible class changes. The class linker has a fast path for
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 7e8a4a4fcd..f3e260be56 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -116,9 +116,10 @@ inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod*
return resolved_method;
}
-inline mirror::Class* ClassLinker::ResolveReferencedClassOfMethod(Thread* self,
- uint32_t method_idx,
- ArtMethod* referrer) {
+inline mirror::Class* ClassLinker::ResolveReferencedClassOfMethod(
+ uint32_t method_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader) {
// NB: We cannot simply use `GetResolvedMethod(method_idx, ...)->GetDeclaringClass()`. This is
// because if we did so than an invoke-super could be incorrectly dispatched in cases where
// GetMethodId(method_idx).class_idx_ refers to a non-interface, non-direct-superclass
@@ -127,15 +128,11 @@ inline mirror::Class* ClassLinker::ResolveReferencedClassOfMethod(Thread* self,
// interface (either miranda, default or conflict) we would incorrectly assume that is what we
// want to invoke on, instead of the 'concrete' implementation that the direct superclass
// contains.
- mirror::Class* declaring_class = referrer->GetDeclaringClass();
- StackHandleScope<2> hs(self);
- Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
- const DexFile* dex_file = h_dex_cache->GetDexFile();
+ const DexFile* dex_file = dex_cache->GetDexFile();
const DexFile::MethodId& method = dex_file->GetMethodId(method_idx);
- mirror::Class* resolved_type = h_dex_cache->GetResolvedType(method.class_idx_);
+ mirror::Class* resolved_type = dex_cache->GetResolvedType(method.class_idx_);
if (UNLIKELY(resolved_type == nullptr)) {
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
- resolved_type = ResolveType(*dex_file, method.class_idx_, h_dex_cache, class_loader);
+ resolved_type = ResolveType(*dex_file, method.class_idx_, dex_cache, class_loader);
}
return resolved_type;
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 5de502b540..97a10367fe 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -310,9 +310,9 @@ class ClassLinker {
// This returns the class referred to by GetMethodId(method_idx).class_idx_. This might be
// different then the declaring class of the resolved method due to copied
// miranda/default/conflict methods.
- mirror::Class* ResolveReferencedClassOfMethod(Thread* self,
- uint32_t method_idx,
- ArtMethod* referrer)
+ mirror::Class* ResolveReferencedClassOfMethod(uint32_t method_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader)
SHARED_REQUIRES(Locks::mutator_lock_)
REQUIRES(!dex_lock_, !Roles::uninterruptible_);
template <ResolveMode kResolveMode>
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index f3e8dbadbe..da6af724ac 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1038,9 +1038,14 @@ extern "C" const void* artQuickResolutionTrampoline(
} else {
DCHECK_EQ(invoke_type, kSuper);
CHECK(caller != nullptr) << invoke_type;
+ StackHandleScope<2> hs(self);
+ Handle<mirror::DexCache> dex_cache(
+ hs.NewHandle(caller->GetDeclaringClass()->GetDexCache()));
+ Handle<mirror::ClassLoader> class_loader(
+ hs.NewHandle(caller->GetDeclaringClass()->GetClassLoader()));
// TODO Maybe put this into a mirror::Class function.
mirror::Class* ref_class = linker->ResolveReferencedClassOfMethod(
- self, called_method.dex_method_index, caller);
+ called_method.dex_method_index, dex_cache, class_loader);
if (ref_class->IsInterface()) {
called = ref_class->FindVirtualMethodForInterfaceSuper(called, sizeof(void*));
} else {