Introduce FindSuperMethodToCall to find the target of a super call.
And use it across compiler/runtime/nterp. This also fixes an issue in
nterp when handling an obsolete method.
Also move FindMethodFast and FindFieldFast next to their only use.
Test: test.py
Bug: 214328881
Change-Id: If64849575ae342324e30026e29d285eca6e61263
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index f8bf126..aabc433 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -28,6 +28,7 @@
#include "dex/dex_instruction-inl.h"
#include "driver/dex_compilation_unit.h"
#include "driver/compiler_options.h"
+#include "entrypoints/entrypoint_utils-inl.h"
#include "imtable-inl.h"
#include "intrinsics.h"
#include "intrinsics_utils.h"
@@ -932,36 +933,18 @@
// make this an invoke-unresolved to handle cross-dex invokes or abstract super methods, both of
// which require runtime handling.
if (*invoke_type == kSuper) {
- ObjPtr<mirror::Class> compiling_class = dex_compilation_unit.GetCompilingClass().Get();
- if (compiling_class == nullptr) {
+ if (referrer == nullptr) {
// We could not determine the method's class we need to wait until runtime.
DCHECK(Runtime::Current()->IsAotCompiler());
return nullptr;
}
- ObjPtr<mirror::Class> referenced_class = class_linker->LookupResolvedType(
- dex_compilation_unit.GetDexFile()->GetMethodId(method_idx).class_idx_,
- dex_compilation_unit.GetDexCache().Get(),
- class_loader.Get());
- DCHECK(referenced_class != nullptr); // We have already resolved a method from this class.
- if (!referenced_class->IsAssignableFrom(compiling_class)) {
- // We cannot statically determine the target method. The runtime will throw a
- // NoSuchMethodError on this one.
+ ArtMethod* actual_method = FindSuperMethodToCall</*access_check=*/true>(
+ method_idx, resolved_method, referrer, soa.Self());
+ if (actual_method == nullptr) {
+ // Clean up any exception left by method resolution.
+ soa.Self()->ClearException();
return nullptr;
}
- ArtMethod* actual_method;
- if (referenced_class->IsInterface()) {
- actual_method = referenced_class->FindVirtualMethodForInterfaceSuper(
- resolved_method, class_linker->GetImagePointerSize());
- } else {
- uint16_t vtable_index = resolved_method->GetMethodIndex();
- if (vtable_index >= static_cast<uint32_t>(
- compiling_class->GetSuperClass()->GetVTableLength())) {
- // No super method. The runtime will throw a NoSuchMethodError.
- return nullptr;
- }
- actual_method = compiling_class->GetSuperClass()->GetVTableEntry(
- vtable_index, class_linker->GetImagePointerSize());
- }
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.
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 853ded0..c6e7cfb 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -257,8 +257,10 @@
// IncompatibleClassChangeError
-void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type,
- ArtMethod* method, ArtMethod* referrer) {
+void ThrowIncompatibleClassChangeError(InvokeType expected_type,
+ InvokeType found_type,
+ ArtMethod* method,
+ ArtMethod* referrer) {
std::ostringstream msg;
msg << "The method '" << ArtMethod::PrettyMethod(method) << "' was expected to be of type "
<< expected_type << " but instead was found to be of type " << found_type;
@@ -267,24 +269,6 @@
msg.str().c_str());
}
-void ThrowIncompatibleClassChangeErrorClassForInterfaceSuper(ArtMethod* method,
- ObjPtr<mirror::Class> target_class,
- ObjPtr<mirror::Object> this_object,
- ArtMethod* referrer) {
- // Referrer is calling interface_method on this_object, however, the interface_method isn't
- // implemented by this_object.
- CHECK(this_object != nullptr);
- std::ostringstream msg;
- msg << "Class '" << mirror::Class::PrettyDescriptor(this_object->GetClass())
- << "' does not implement interface '" << mirror::Class::PrettyDescriptor(target_class)
- << "' in call to '"
- << ArtMethod::PrettyMethod(method) << "'";
- DumpB77342775DebugData(target_class, this_object->GetClass());
- ThrowException("Ljava/lang/IncompatibleClassChangeError;",
- referrer != nullptr ? referrer->GetDeclaringClass() : nullptr,
- msg.str().c_str());
-}
-
void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(ArtMethod* interface_method,
ObjPtr<mirror::Object> this_object,
ArtMethod* referrer) {
@@ -302,7 +286,8 @@
msg.str().c_str());
}
-void ThrowIncompatibleClassChangeErrorField(ArtField* resolved_field, bool is_static,
+void ThrowIncompatibleClassChangeErrorField(ArtField* resolved_field,
+ bool is_static,
ArtMethod* referrer) {
std::ostringstream msg;
msg << "Expected '" << ArtField::PrettyField(resolved_field) << "' to be a "
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index 832eac6..3a723f7 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -134,12 +134,6 @@
ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
-void ThrowIncompatibleClassChangeErrorClassForInterfaceSuper(ArtMethod* method,
- ObjPtr<mirror::Class> target_class,
- ObjPtr<mirror::Object> this_object,
- ArtMethod* referrer)
- REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
-
void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(ArtMethod* interface_method,
ObjPtr<mirror::Object> this_object,
ArtMethod* referrer)
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index b36c5c3..4ee1013 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -486,6 +486,66 @@
#undef EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL
#undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
+template<bool access_check>
+ALWAYS_INLINE ArtMethod* FindSuperMethodToCall(uint32_t method_idx,
+ ArtMethod* resolved_method,
+ ArtMethod* referrer,
+ Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ // TODO This lookup is quite slow.
+ // NB This is actually quite tricky to do any other way. We cannot use GetDeclaringClass since
+ // that will actually not be what we want in some cases where there are miranda methods or
+ // defaults. What we actually need is a GetContainingClass that says which classes virtuals
+ // this method is coming from.
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ dex::TypeIndex type_idx = referrer->GetDexFile()->GetMethodId(method_idx).class_idx_;
+ ObjPtr<mirror::Class> referenced_class = linker->ResolveType(type_idx, referrer);
+ if (UNLIKELY(referenced_class == nullptr)) {
+ DCHECK(self->IsExceptionPending());
+ return nullptr;
+ }
+
+ if (access_check) {
+ if (!referenced_class->IsAssignableFrom(referrer->GetDeclaringClass())) {
+ ThrowNoSuchMethodError(kSuper,
+ resolved_method->GetDeclaringClass(),
+ resolved_method->GetName(),
+ resolved_method->GetSignature());
+ return nullptr;
+ }
+ }
+
+ if (referenced_class->IsInterface()) {
+ // TODO We can do better than this for a (compiled) fastpath.
+ ArtMethod* found_method = referenced_class->FindVirtualMethodForInterfaceSuper(
+ resolved_method, linker->GetImagePointerSize());
+ DCHECK(found_method != nullptr);
+ return found_method;
+ }
+
+ DCHECK(resolved_method->IsCopied() ||
+ !resolved_method->GetDeclaringClass()->IsInterface());
+
+ uint16_t vtable_index = resolved_method->GetMethodIndex();
+ ObjPtr<mirror::Class> super_class = referrer->GetDeclaringClass()->GetSuperClass();
+ if (access_check) {
+ DCHECK(super_class == nullptr || super_class->HasVTable());
+ // Check existence of super class.
+ if (super_class == nullptr ||
+ vtable_index >= static_cast<uint32_t>(super_class->GetVTableLength())) {
+ // Behavior to agree with that of the verifier.
+ ThrowNoSuchMethodError(kSuper,
+ resolved_method->GetDeclaringClass(),
+ resolved_method->GetName(),
+ resolved_method->GetSignature());
+ return nullptr; // Failure.
+ }
+ }
+ DCHECK(super_class != nullptr);
+ DCHECK(super_class->HasVTable());
+ return super_class->GetVTableEntry(vtable_index, linker->GetImagePointerSize());
+}
+
// Follow virtual/interface indirections if applicable.
// Will throw null-pointer exception the if the object is null.
template<InvokeType type, bool access_check>
@@ -531,67 +591,7 @@
return klass->GetVTableEntry(vtable_index, class_linker->GetImagePointerSize());
}
case kSuper: {
- // TODO This lookup is quite slow.
- // NB This is actually quite tricky to do any other way. We cannot use GetDeclaringClass since
- // that will actually not be what we want in some cases where there are miranda methods or
- // defaults. What we actually need is a GetContainingClass that says which classes virtuals
- // this method is coming from.
- StackHandleScope<2> hs2(self);
- HandleWrapperObjPtr<mirror::Object> h_this(hs2.NewHandleWrapper(this_object));
- Handle<mirror::Class> h_referring_class(hs2.NewHandle(referrer->GetDeclaringClass()));
- const dex::TypeIndex method_type_idx =
- referrer->GetDexFile()->GetMethodId(method_idx).class_idx_;
- ObjPtr<mirror::Class> method_reference_class =
- class_linker->ResolveType(method_type_idx, referrer);
- if (UNLIKELY(method_reference_class == nullptr)) {
- // Bad type idx.
- CHECK(self->IsExceptionPending());
- return nullptr;
- } else if (!method_reference_class->IsInterface()) {
- // It is not an interface. If the referring class is in the class hierarchy of the
- // referenced class in the bytecode, we use its super class. Otherwise, we throw
- // a NoSuchMethodError.
- ObjPtr<mirror::Class> super_class = nullptr;
- if (method_reference_class->IsAssignableFrom(h_referring_class.Get())) {
- super_class = h_referring_class->GetSuperClass();
- }
- uint16_t vtable_index = resolved_method->GetMethodIndex();
- if (access_check) {
- // Check existence of super class.
- if (super_class == nullptr ||
- !super_class->HasVTable() ||
- vtable_index >= static_cast<uint32_t>(super_class->GetVTableLength())) {
- // Behavior to agree with that of the verifier.
- ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
- resolved_method->GetName(), resolved_method->GetSignature());
- return nullptr; // Failure.
- }
- }
- DCHECK(super_class != nullptr);
- DCHECK(super_class->HasVTable());
- return super_class->GetVTableEntry(vtable_index, class_linker->GetImagePointerSize());
- } else {
- // It is an interface.
- if (access_check) {
- if (!method_reference_class->IsAssignableFrom(h_this->GetClass())) {
- ThrowIncompatibleClassChangeErrorClassForInterfaceSuper(resolved_method,
- method_reference_class,
- h_this.Get(),
- referrer);
- return nullptr; // Failure.
- }
- }
- // TODO We can do better than this for a (compiled) fastpath.
- ArtMethod* result = method_reference_class->FindVirtualMethodForInterfaceSuper(
- resolved_method, class_linker->GetImagePointerSize());
- // Throw an NSME if nullptr;
- if (result == nullptr) {
- ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
- resolved_method->GetName(), resolved_method->GetSignature());
- }
- return result;
- }
- UNREACHABLE();
+ return FindSuperMethodToCall<access_check>(method_idx, resolved_method, referrer, self);
}
case kInterface: {
size_t imt_index = resolved_method->GetImtIndex();
@@ -670,100 +670,6 @@
#undef EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL
#undef EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL
-// Fast path field resolution that can't initialize classes or throw exceptions.
-inline ArtField* FindFieldFast(uint32_t field_idx, ArtMethod* referrer, FindFieldType type,
- size_t expected_size) {
- ScopedAssertNoThreadSuspension ants(__FUNCTION__);
- ArtField* resolved_field = referrer->GetDexCache()->GetResolvedField(field_idx);
- if (UNLIKELY(resolved_field == nullptr)) {
- return nullptr;
- }
- // Check for incompatible class change.
- const bool is_primitive = (type & FindFieldFlags::PrimitiveBit) != 0;
- const bool is_set = (type & FindFieldFlags::WriteBit) != 0;
- const bool is_static = (type & FindFieldFlags::StaticBit) != 0;
- if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
- // Incompatible class change.
- return nullptr;
- }
- ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
- if (is_static) {
- // Check class is initialized else fail so that we can contend to initialize the class with
- // other threads that may be racing to do this.
- if (UNLIKELY(!fields_class->IsVisiblyInitialized())) {
- return nullptr;
- }
- }
- ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
- if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
- !referring_class->CanAccessMember(fields_class, resolved_field->GetAccessFlags()) ||
- (is_set && !resolved_field->CanBeChangedBy(referrer)))) {
- // Illegal access.
- return nullptr;
- }
- if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
- resolved_field->FieldSize() != expected_size)) {
- return nullptr;
- }
- return resolved_field;
-}
-
-// Fast path method resolution that can't throw exceptions.
-template <InvokeType type, bool access_check>
-inline ArtMethod* FindMethodFast(uint32_t method_idx,
- ObjPtr<mirror::Object> this_object,
- ArtMethod* referrer) {
- ScopedAssertNoThreadSuspension ants(__FUNCTION__);
- if (UNLIKELY(this_object == nullptr && type != kStatic)) {
- return nullptr;
- }
- ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
- ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
- constexpr ClassLinker::ResolveMode resolve_mode = access_check
- ? ClassLinker::ResolveMode::kCheckICCEAndIAE
- : ClassLinker::ResolveMode::kNoChecks;
- ClassLinker* linker = Runtime::Current()->GetClassLinker();
- ArtMethod* resolved_method = linker->GetResolvedMethod<type, resolve_mode>(method_idx, referrer);
- if (UNLIKELY(resolved_method == nullptr)) {
- return nullptr;
- }
- if (type == kInterface) { // Most common form of slow path dispatch.
- return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method,
- kRuntimePointerSize);
- } else if (type == kStatic || type == kDirect) {
- return resolved_method;
- } else if (type == kSuper) {
- // TODO This lookup is rather slow.
- dex::TypeIndex method_type_idx = dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
- ObjPtr<mirror::Class> method_reference_class = linker->LookupResolvedType(
- method_type_idx, dex_cache, referrer->GetClassLoader());
- if (method_reference_class == nullptr) {
- // Need to do full type resolution...
- return nullptr;
- } else if (!method_reference_class->IsInterface()) {
- // It is not an interface. If the referring class is in the class hierarchy of the
- // referenced class in the bytecode, we use its super class. Otherwise, we cannot
- // resolve the method.
- if (!method_reference_class->IsAssignableFrom(referring_class)) {
- return nullptr;
- }
- ObjPtr<mirror::Class> super_class = referring_class->GetSuperClass();
- if (resolved_method->GetMethodIndex() >= super_class->GetVTableLength()) {
- // The super class does not have the method.
- return nullptr;
- }
- return super_class->GetVTableEntry(resolved_method->GetMethodIndex(), kRuntimePointerSize);
- } else {
- return method_reference_class->FindVirtualMethodForInterfaceSuper(
- resolved_method, kRuntimePointerSize);
- }
- } else {
- DCHECK(type == kVirtual);
- return this_object->GetClass()->GetVTableEntry(
- resolved_method->GetMethodIndex(), kRuntimePointerSize);
- }
-}
-
inline ObjPtr<mirror::Class> ResolveVerifyAndClinit(dex::TypeIndex type_idx,
ArtMethod* referrer,
Thread* self,
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 4731a86..5faf387 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -128,6 +128,13 @@
StaticPrimitiveWrite = StaticBit | PrimitiveBit | WriteBit,
};
+template<bool access_check>
+inline ArtMethod* FindSuperMethodToCall(uint32_t method_idx,
+ ArtMethod* resolved_method,
+ ArtMethod* referrer,
+ Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
template<FindFieldType type, bool access_check>
inline ArtField* FindFieldFromCode(uint32_t field_idx,
ArtMethod* referrer,
@@ -144,20 +151,6 @@
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
-// Fast path field resolution that can't initialize classes or throw exceptions.
-inline ArtField* FindFieldFast(uint32_t field_idx,
- ArtMethod* referrer,
- FindFieldType type,
- size_t expected_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
-// Fast path method resolution that can't throw exceptions.
-template <InvokeType type, bool access_check>
-inline ArtMethod* FindMethodFast(uint32_t method_idx,
- ObjPtr<mirror::Object> this_object,
- ArtMethod* referrer)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
inline ObjPtr<mirror::Class> ResolveVerifyAndClinit(dex::TypeIndex type_idx,
ArtMethod* referrer,
Thread* self,
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index bfe015f..618f763 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -28,6 +28,48 @@
namespace art {
+// Fast path field resolution that can't initialize classes or throw exceptions.
+inline ArtField* FindFieldFast(uint32_t field_idx,
+ ArtMethod* referrer,
+ FindFieldType type,
+ size_t expected_size)
+ REQUIRES(!Roles::uninterruptible_)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ScopedAssertNoThreadSuspension ants(__FUNCTION__);
+ ArtField* resolved_field = referrer->GetDexCache()->GetResolvedField(field_idx);
+ if (UNLIKELY(resolved_field == nullptr)) {
+ return nullptr;
+ }
+ // Check for incompatible class change.
+ const bool is_primitive = (type & FindFieldFlags::PrimitiveBit) != 0;
+ const bool is_set = (type & FindFieldFlags::WriteBit) != 0;
+ const bool is_static = (type & FindFieldFlags::StaticBit) != 0;
+ if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
+ // Incompatible class change.
+ return nullptr;
+ }
+ ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
+ if (is_static) {
+ // Check class is initialized else fail so that we can contend to initialize the class with
+ // other threads that may be racing to do this.
+ if (UNLIKELY(!fields_class->IsVisiblyInitialized())) {
+ return nullptr;
+ }
+ }
+ ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
+ if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
+ !referring_class->CanAccessMember(fields_class, resolved_field->GetAccessFlags()) ||
+ (is_set && !resolved_field->CanBeChangedBy(referrer)))) {
+ // Illegal access.
+ return nullptr;
+ }
+ if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
+ resolved_field->FieldSize() != expected_size)) {
+ return nullptr;
+ }
+ return resolved_field;
+}
+
// Helper function to do a null check after trying to resolve the field. Not for statics since obj
// does not exist there. There is a suspend check, object is a double pointer to update the value
// in the caller in case it moves.
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 926d534..b5bd6ef 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2198,13 +2198,75 @@
return GenericJniMethodEnd(self, cookie, result, result_f, called);
}
+// Fast path method resolution that can't throw exceptions.
+template <InvokeType type>
+inline ArtMethod* FindMethodFast(uint32_t method_idx,
+ ObjPtr<mirror::Object> this_object,
+ ArtMethod* referrer)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_) {
+ ScopedAssertNoThreadSuspension ants(__FUNCTION__);
+ if (UNLIKELY(this_object == nullptr && type != kStatic)) {
+ return nullptr;
+ }
+ ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
+ ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
+ constexpr ClassLinker::ResolveMode resolve_mode = ClassLinker::ResolveMode::kCheckICCEAndIAE;
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ ArtMethod* resolved_method = linker->GetResolvedMethod<type, resolve_mode>(method_idx, referrer);
+ if (UNLIKELY(resolved_method == nullptr)) {
+ return nullptr;
+ }
+ if (type == kInterface) { // Most common form of slow path dispatch.
+ return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method,
+ kRuntimePointerSize);
+ }
+ if (type == kStatic || type == kDirect) {
+ return resolved_method;
+ }
+
+ if (type == kSuper) {
+ // TODO This lookup is rather slow.
+ dex::TypeIndex method_type_idx = dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
+ ObjPtr<mirror::Class> method_reference_class = linker->LookupResolvedType(
+ method_type_idx, dex_cache, referrer->GetClassLoader());
+ if (method_reference_class == nullptr) {
+ // Need to do full type resolution...
+ return nullptr;
+ }
+
+ // If the referring class is in the class hierarchy of the
+ // referenced class in the bytecode, we use its super class. Otherwise, we cannot
+ // resolve the method.
+ if (!method_reference_class->IsAssignableFrom(referring_class)) {
+ return nullptr;
+ }
+
+ if (method_reference_class->IsInterface()) {
+ return method_reference_class->FindVirtualMethodForInterfaceSuper(
+ resolved_method, kRuntimePointerSize);
+ }
+
+ ObjPtr<mirror::Class> super_class = referring_class->GetSuperClass();
+ if (resolved_method->GetMethodIndex() >= super_class->GetVTableLength()) {
+ // The super class does not have the method.
+ return nullptr;
+ }
+ return super_class->GetVTableEntry(resolved_method->GetMethodIndex(), kRuntimePointerSize);
+ }
+
+ DCHECK(type == kVirtual);
+ return this_object->GetClass()->GetVTableEntry(
+ resolved_method->GetMethodIndex(), kRuntimePointerSize);
+}
+
// We use TwoWordReturn to optimize scalar returns. We use the hi value for code, and the lo value
// for the method pointer.
//
// It is valid to use this, as at the usage points here (returns from C functions) we are assuming
// to hold the mutator lock (see REQUIRES_SHARED(Locks::mutator_lock_) annotations).
-template <InvokeType type, bool access_check>
+template <InvokeType type>
static TwoWordReturn artInvokeCommon(uint32_t method_idx,
ObjPtr<mirror::Object> this_object,
Thread* self,
@@ -2212,7 +2274,7 @@
ScopedQuickEntrypointChecks sqec(self);
DCHECK_EQ(*sp, Runtime::Current()->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs));
ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
- ArtMethod* method = FindMethodFast<type, access_check>(method_idx, this_object, caller_method);
+ ArtMethod* method = FindMethodFast<type>(method_idx, this_object, caller_method);
if (UNLIKELY(method == nullptr)) {
const DexFile* dex_file = caller_method->GetDexFile();
uint32_t shorty_len;
@@ -2222,10 +2284,8 @@
ScopedObjectAccessUnchecked soa(self->GetJniEnv());
RememberForGcArgumentVisitor visitor(sp, type == kStatic, shorty, shorty_len, &soa);
visitor.VisitArguments();
- method = FindMethodFromCode<type, access_check>(method_idx,
- &this_object,
- caller_method,
- self);
+ method = FindMethodFromCode<type, /*access_check=*/true>(
+ method_idx, &this_object, caller_method, self);
visitor.FixupReferences();
}
@@ -2247,34 +2307,29 @@
}
// Explicit artInvokeCommon template function declarations to please analysis tool.
-#define EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(type, access_check) \
- template REQUIRES_SHARED(Locks::mutator_lock_) \
- TwoWordReturn artInvokeCommon<type, access_check>( \
+#define EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(type) \
+ template REQUIRES_SHARED(Locks::mutator_lock_) \
+ TwoWordReturn artInvokeCommon<type>( \
uint32_t method_idx, ObjPtr<mirror::Object> his_object, Thread* self, ArtMethod** sp)
-EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kVirtual, false);
-EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kVirtual, true);
-EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kInterface, false);
-EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kInterface, true);
-EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kDirect, false);
-EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kDirect, true);
-EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kStatic, false);
-EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kStatic, true);
-EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kSuper, false);
-EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kSuper, true);
+EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kVirtual);
+EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kInterface);
+EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kDirect);
+EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kStatic);
+EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL(kSuper);
#undef EXPLICIT_INVOKE_COMMON_TEMPLATE_DECL
// See comments in runtime_support_asm.S
extern "C" TwoWordReturn artInvokeInterfaceTrampolineWithAccessCheck(
uint32_t method_idx, mirror::Object* this_object, Thread* self, ArtMethod** sp)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return artInvokeCommon<kInterface, true>(method_idx, this_object, self, sp);
+ return artInvokeCommon<kInterface>(method_idx, this_object, self, sp);
}
extern "C" TwoWordReturn artInvokeDirectTrampolineWithAccessCheck(
uint32_t method_idx, mirror::Object* this_object, Thread* self, ArtMethod** sp)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return artInvokeCommon<kDirect, true>(method_idx, this_object, self, sp);
+ return artInvokeCommon<kDirect>(method_idx, this_object, self, sp);
}
extern "C" TwoWordReturn artInvokeStaticTrampolineWithAccessCheck(
@@ -2284,19 +2339,19 @@
ArtMethod** sp) REQUIRES_SHARED(Locks::mutator_lock_) {
// For static, this_object is not required and may be random garbage. Don't pass it down so that
// it doesn't cause ObjPtr alignment failure check.
- return artInvokeCommon<kStatic, true>(method_idx, nullptr, self, sp);
+ return artInvokeCommon<kStatic>(method_idx, nullptr, self, sp);
}
extern "C" TwoWordReturn artInvokeSuperTrampolineWithAccessCheck(
uint32_t method_idx, mirror::Object* this_object, Thread* self, ArtMethod** sp)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return artInvokeCommon<kSuper, true>(method_idx, this_object, self, sp);
+ return artInvokeCommon<kSuper>(method_idx, this_object, self, sp);
}
extern "C" TwoWordReturn artInvokeVirtualTrampolineWithAccessCheck(
uint32_t method_idx, mirror::Object* this_object, Thread* self, ArtMethod** sp)
REQUIRES_SHARED(Locks::mutator_lock_) {
- return artInvokeCommon<kVirtual, true>(method_idx, this_object, self, sp);
+ return artInvokeCommon<kVirtual>(method_idx, this_object, self, sp);
}
// Determine target of interface dispatch. The interface method and this object are known non-null.
diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc
index 7719b5f..34c971c 100644
--- a/runtime/interpreter/mterp/nterp.cc
+++ b/runtime/interpreter/mterp/nterp.cc
@@ -330,43 +330,14 @@
return 0;
}
- // ResolveMethod returns the method based on the method_id. For super invokes
- // we must use the executing class's context to find the right method.
if (invoke_type == kSuper) {
- ObjPtr<mirror::Class> executing_class = caller->GetDeclaringClass();
- ObjPtr<mirror::Class> referenced_class = class_linker->LookupResolvedType(
- executing_class->GetDexFile().GetMethodId(method_index).class_idx_,
- executing_class->GetDexCache(),
- executing_class->GetClassLoader());
- DCHECK(referenced_class != nullptr); // We have already resolved a method from this class.
- if (!referenced_class->IsAssignableFrom(executing_class)) {
- // We cannot determine the target method.
- ThrowNoSuchMethodError(invoke_type,
- resolved_method->GetDeclaringClass(),
- resolved_method->GetName(),
- resolved_method->GetSignature());
+ resolved_method = caller->SkipAccessChecks()
+ ? FindSuperMethodToCall</*access_check=*/false>(method_index, resolved_method, caller, self)
+ : FindSuperMethodToCall</*access_check=*/true>(method_index, resolved_method, caller, self);
+ if (resolved_method == nullptr) {
+ DCHECK(self->IsExceptionPending());
return 0;
}
- if (referenced_class->IsInterface()) {
- resolved_method = referenced_class->FindVirtualMethodForInterfaceSuper(
- resolved_method, class_linker->GetImagePointerSize());
- } else {
- uint16_t vtable_index = resolved_method->GetMethodIndex();
- ObjPtr<mirror::Class> super_class = executing_class->GetSuperClass();
- if (super_class == nullptr ||
- !super_class->HasVTable() ||
- vtable_index >= static_cast<uint32_t>(super_class->GetVTableLength())) {
- // Behavior to agree with that of the verifier.
- ThrowNoSuchMethodError(invoke_type,
- resolved_method->GetDeclaringClass(),
- resolved_method->GetName(),
- resolved_method->GetSignature());
- return 0;
- } else {
- resolved_method = executing_class->GetSuperClass()->GetVTableEntry(
- vtable_index, class_linker->GetImagePointerSize());
- }
- }
}
if (invoke_type == kInterface) {