summaryrefslogtreecommitdiff
path: root/runtime/mirror/class.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/mirror/class.cc')
-rw-r--r--runtime/mirror/class.cc84
1 files changed, 84 insertions, 0 deletions
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 9190e44144..7900eac4e0 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -1054,5 +1054,89 @@ uint32_t Class::FindTypeIndexInOtherDexFile(const DexFile& dex_file) {
return (type_id == nullptr) ? DexFile::kDexNoIndex : dex_file.GetIndexForTypeId(*type_id);
}
+template <bool kTransactionActive>
+mirror::Method* Class::GetDeclaredMethodInternal(Thread* self,
+ mirror::Class* klass,
+ mirror::String* name,
+ mirror::ObjectArray<mirror::Class>* args) {
+ // Covariant return types permit the class to define multiple
+ // methods with the same name and parameter types. Prefer to
+ // return a non-synthetic method in such situations. We may
+ // still return a synthetic method to handle situations like
+ // escalated visibility. We never return miranda methods that
+ // were synthesized by the runtime.
+ constexpr uint32_t kSkipModifiers = kAccMiranda | kAccSynthetic;
+ StackHandleScope<3> hs(self);
+ auto h_method_name = hs.NewHandle(name);
+ if (UNLIKELY(h_method_name.Get() == nullptr)) {
+ ThrowNullPointerException("name == null");
+ return nullptr;
+ }
+ auto h_args = hs.NewHandle(args);
+ Handle<mirror::Class> h_klass = hs.NewHandle(klass);
+ ArtMethod* result = nullptr;
+ const size_t pointer_size = kTransactionActive
+ ? Runtime::Current()->GetClassLinker()->GetImagePointerSize()
+ : sizeof(void*);
+ for (auto& m : h_klass->GetDeclaredVirtualMethods(pointer_size)) {
+ auto* np_method = m.GetInterfaceMethodIfProxy(pointer_size);
+ // May cause thread suspension.
+ mirror::String* np_name = np_method->GetNameAsString(self);
+ if (!np_name->Equals(h_method_name.Get()) || !np_method->EqualParameters(h_args)) {
+ if (UNLIKELY(self->IsExceptionPending())) {
+ return nullptr;
+ }
+ continue;
+ }
+ auto modifiers = m.GetAccessFlags();
+ if ((modifiers & kSkipModifiers) == 0) {
+ return mirror::Method::CreateFromArtMethod<kTransactionActive>(self, &m);
+ }
+ if ((modifiers & kAccMiranda) == 0) {
+ result = &m; // Remember as potential result if it's not a miranda method.
+ }
+ }
+ if (result == nullptr) {
+ for (auto& m : h_klass->GetDirectMethods(pointer_size)) {
+ auto modifiers = m.GetAccessFlags();
+ if ((modifiers & kAccConstructor) != 0) {
+ continue;
+ }
+ auto* np_method = m.GetInterfaceMethodIfProxy(pointer_size);
+ // May cause thread suspension.
+ mirror::String* np_name = np_method->GetNameAsString(self);
+ if (np_name == nullptr) {
+ self->AssertPendingException();
+ return nullptr;
+ }
+ if (!np_name->Equals(h_method_name.Get()) || !np_method->EqualParameters(h_args)) {
+ if (UNLIKELY(self->IsExceptionPending())) {
+ return nullptr;
+ }
+ continue;
+ }
+ if ((modifiers & kSkipModifiers) == 0) {
+ return mirror::Method::CreateFromArtMethod<kTransactionActive>(self, &m);
+ }
+ // Direct methods cannot be miranda methods, so this potential result must be synthetic.
+ result = &m;
+ }
+ }
+ return result != nullptr
+ ? mirror::Method::CreateFromArtMethod<kTransactionActive>(self, result)
+ : nullptr;
+}
+
+template
+mirror::Method* Class::GetDeclaredMethodInternal<false>(Thread* self,
+ mirror::Class* klass,
+ mirror::String* name,
+ mirror::ObjectArray<mirror::Class>* args);
+template
+mirror::Method* Class::GetDeclaredMethodInternal<true>(Thread* self,
+ mirror::Class* klass,
+ mirror::String* name,
+ mirror::ObjectArray<mirror::Class>* args);
+
} // namespace mirror
} // namespace art