summaryrefslogtreecommitdiff
path: root/runtime/entrypoints/entrypoint_utils-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/entrypoints/entrypoint_utils-inl.h')
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h216
1 files changed, 61 insertions, 155 deletions
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index b36c5c3c96..4ee1013816 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -486,6 +486,66 @@ EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveWrite);
#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 @@ ALWAYS_INLINE ArtMethod* FindMethodToCall(uint32_t method_idx,
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 @@ EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kInterface);
#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,