java.lang.invoke: Add mirror types for MethodHandle / MethodType.
Bug: 30550796
Test: make test-art-host
Change-Id: I096160464bc6e84f7e5ad021306a7e462cf3b0c5
diff --git a/runtime/Android.bp b/runtime/Android.bp
index fd9b5b9..31f2490 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -126,6 +126,8 @@
"mirror/executable.cc",
"mirror/field.cc",
"mirror/method.cc",
+ "mirror/method_handle_impl.cc",
+ "mirror/method_type.cc",
"mirror/object.cc",
"mirror/reference.cc",
"mirror/stack_trace_element.cc",
@@ -546,6 +548,7 @@
"mem_map_test.cc",
"memory_region_test.cc",
"mirror/dex_cache_test.cc",
+ "mirror/method_type_test.cc",
"mirror/object_test.cc",
"monitor_pool_test.cc",
"monitor_test.cc",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 48550f3..5106aec 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -73,6 +73,8 @@
#include "mirror/field.h"
#include "mirror/iftable-inl.h"
#include "mirror/method.h"
+#include "mirror/method_type.h"
+#include "mirror/method_handle_impl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/proxy.h"
@@ -636,6 +638,18 @@
SetClassRoot(kJavaLangReflectMethodArrayClass, class_root);
mirror::Method::SetArrayClass(class_root);
+ // Create java.lang.invoke.MethodType.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodType;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangInvokeMethodType, class_root);
+ mirror::MethodType::SetClass(class_root);
+
+ // Create java.lang.invoke.MethodHandleImpl.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandleImpl;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangInvokeMethodHandleImpl, class_root);
+ mirror::MethodHandleImpl::SetClass(class_root);
+
// java.lang.ref classes need to be specially flagged, but otherwise are normal classes
// finish initializing Reference class
mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self);
@@ -1032,6 +1046,8 @@
mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass));
mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass));
+ mirror::MethodType::SetClass(GetClassRoot(kJavaLangInvokeMethodType));
+ mirror::MethodHandleImpl::SetClass(GetClassRoot(kJavaLangInvokeMethodHandleImpl));
mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
@@ -2032,6 +2048,8 @@
mirror::IntArray::ResetArrayClass();
mirror::LongArray::ResetArrayClass();
mirror::ShortArray::ResetArrayClass();
+ mirror::MethodType::ResetClass();
+ mirror::MethodHandleImpl::ResetClass();
Thread* const self = Thread::Current();
for (const ClassLoaderData& data : class_loaders_) {
DeleteClassLoader(self, data);
@@ -8071,6 +8089,8 @@
"[Ljava/lang/reflect/Constructor;",
"[Ljava/lang/reflect/Field;",
"[Ljava/lang/reflect/Method;",
+ "Ljava/lang/invoke/MethodHandleImpl;",
+ "Ljava/lang/invoke/MethodType;",
"Ljava/lang/ClassLoader;",
"Ljava/lang/Throwable;",
"Ljava/lang/ClassNotFoundException;",
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 954af76..8f7051e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -51,6 +51,7 @@
class DexCachePointerArray;
class DexCacheTest_Open_Test;
class IfTable;
+ class MethodType;
template<class T> class ObjectArray;
class StackTraceElement;
} // namespace mirror
@@ -99,6 +100,8 @@
kJavaLangReflectConstructorArrayClass,
kJavaLangReflectFieldArrayClass,
kJavaLangReflectMethodArrayClass,
+ kJavaLangInvokeMethodHandleImpl,
+ kJavaLangInvokeMethodType,
kJavaLangClassLoader,
kJavaLangThrowable,
kJavaLangClassNotFoundException,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 7023081..4f73218 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -33,6 +33,8 @@
#include "mirror/dex_cache.h"
#include "mirror/executable.h"
#include "mirror/field.h"
+#include "mirror/method_type.h"
+#include "mirror/method_handle_impl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/proxy.h"
@@ -708,6 +710,27 @@
};
};
+struct MethodTypeOffsets : public CheckOffsets<mirror::MethodType> {
+ MethodTypeOffsets() : CheckOffsets<mirror::MethodType>(
+ false, "Ljava/lang/invoke/MethodType;") {
+ addOffset(OFFSETOF_MEMBER(mirror::MethodType, form_), "form");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodType, method_descriptor_), "methodDescriptor");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodType, p_types_), "ptypes");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodType, r_type_), "rtype");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodType, wrap_alt_), "wrapAlt");
+ }
+};
+
+struct MethodHandleImplOffsets : public CheckOffsets<mirror::MethodHandleImpl> {
+ MethodHandleImplOffsets() : CheckOffsets<mirror::MethodHandleImpl>(
+ false, "Ljava/lang/invoke/MethodHandle;") {
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, art_field_or_method_), "artFieldOrMethod");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, as_type_cache_), "asTypeCache");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, handle_kind_), "handleKind");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, method_type_), "type");
+ }
+};
+
// C++ fields must exactly match the fields in the Java classes. If this fails,
// reorder the fields in the C++ class. Managed class fields are ordered by
// ClassLinker::LinkFields.
@@ -726,6 +749,8 @@
EXPECT_TRUE(AccessibleObjectOffsets().Check());
EXPECT_TRUE(FieldOffsets().Check());
EXPECT_TRUE(ExecutableOffsets().Check());
+ EXPECT_TRUE(MethodTypeOffsets().Check());
+ EXPECT_TRUE(MethodHandleImplOffsets().Check());
}
TEST_F(ClassLinkerTest, FindClassNonexistent) {
diff --git a/runtime/mirror/method_handle_impl.cc b/runtime/mirror/method_handle_impl.cc
new file mode 100644
index 0000000..fdfaaa8
--- /dev/null
+++ b/runtime/mirror/method_handle_impl.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "method_handle_impl.h"
+
+#include "class-inl.h"
+#include "gc_root-inl.h"
+
+namespace art {
+namespace mirror {
+
+GcRoot<mirror::Class> MethodHandleImpl::static_class_;
+
+void MethodHandleImpl::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void MethodHandleImpl::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void MethodHandleImpl::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
new file mode 100644
index 0000000..a0aae3c
--- /dev/null
+++ b/runtime/mirror/method_handle_impl.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
+#define ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
+
+#include "class.h"
+#include "gc_root.h"
+#include "object.h"
+#include "method_type.h"
+
+namespace art {
+
+struct MethodHandleImplOffsets;
+
+namespace mirror {
+
+// C++ mirror of java.lang.invoke.MethodHandle
+class MANAGED MethodHandle : public Object {
+ public:
+ mirror::MethodType* GetMethodType() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetFieldObject<mirror::MethodType>(OFFSET_OF_OBJECT_MEMBER(MethodHandle, method_type_));
+ }
+
+ ArtMethod* GetTargetMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return reinterpret_cast<ArtMethod*>(
+ GetField64(OFFSET_OF_OBJECT_MEMBER(MethodHandle, art_field_or_method_)));
+ }
+
+ private:
+ HeapReference<mirror::Object> as_type_cache_;
+ HeapReference<mirror::MethodType> method_type_;
+ uint64_t art_field_or_method_;
+ uint32_t handle_kind_;
+
+ private:
+ static MemberOffset AsTypeCacheOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandle, as_type_cache_));
+ }
+ static MemberOffset MethodTypeOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandle, method_type_));
+ }
+ static MemberOffset ArtFieldOrMethodOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandle, art_field_or_method_));
+ }
+ static MemberOffset HandleKindOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandle, handle_kind_));
+ }
+
+ friend struct art::MethodHandleImplOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MethodHandle);
+};
+
+// C++ mirror of java.lang.invoke.MethodHandleImpl
+class MANAGED MethodHandleImpl : public MethodHandle {
+ public:
+ static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return static_class_.Read();
+ }
+
+ static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+ static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+ static GcRoot<mirror::Class> static_class_; // java.lang.invoke.MethodHandleImpl.class
+
+ friend struct art::MethodHandleImplOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MethodHandleImpl);
+};
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
diff --git a/runtime/mirror/method_type.cc b/runtime/mirror/method_type.cc
new file mode 100644
index 0000000..ba6ea5e
--- /dev/null
+++ b/runtime/mirror/method_type.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "method_type.h"
+
+#include "class-inl.h"
+#include "gc_root-inl.h"
+
+namespace art {
+namespace mirror {
+
+GcRoot<mirror::Class> MethodType::static_class_;
+
+mirror::MethodType* MethodType::Create(Thread* const self,
+ Handle<Class> return_type,
+ Handle<ObjectArray<Class>> param_types) {
+ StackHandleScope<1> hs(self);
+ Handle<mirror::MethodType> mt(
+ hs.NewHandle(static_cast<MethodType*>(StaticClass()->AllocObject(self))));
+
+ // TODO: Do we ever create a MethodType during a transaction ? There doesn't
+ // seem like a good reason to do a polymorphic invoke that results in the
+ // resolution of a method type in an unstarted runtime.
+ mt->SetFieldObject<false>(FormOffset(), nullptr);
+ mt->SetFieldObject<false>(MethodDescriptorOffset(), nullptr);
+ mt->SetFieldObject<false>(RTypeOffset(), return_type.Get());
+ mt->SetFieldObject<false>(PTypesOffset(), param_types.Get());
+ mt->SetFieldObject<false>(WrapAltOffset(), nullptr);
+
+ return mt.Get();
+}
+
+bool MethodType::IsExactMatch(mirror::MethodType* other) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (GetRType() != other->GetRType()) {
+ return false;
+ }
+
+ mirror::ObjectArray<Class>* const p_types = GetPTypes();
+ const int32_t params_length = p_types->GetLength();
+
+ mirror::ObjectArray<Class>* const other_p_types = other->GetPTypes();
+ if (params_length != other_p_types->GetLength()) {
+ return false;
+ }
+
+ for (int32_t i = 0; i < params_length; ++i) {
+ if (p_types->GetWithoutChecks(i) != other_p_types->GetWithoutChecks(i)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void MethodType::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void MethodType::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void MethodType::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/mirror/method_type.h b/runtime/mirror/method_type.h
new file mode 100644
index 0000000..5b50409
--- /dev/null
+++ b/runtime/mirror/method_type.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MIRROR_METHOD_TYPE_H_
+#define ART_RUNTIME_MIRROR_METHOD_TYPE_H_
+
+#include "object.h"
+#include "string.h"
+#include "mirror/object_array.h"
+#include "utils.h"
+
+namespace art {
+
+struct MethodTypeOffsets;
+
+namespace mirror {
+
+// C++ mirror of java.lang.invoke.MethodType
+class MANAGED MethodType : public Object {
+ public:
+ static mirror::MethodType* Create(Thread* const self,
+ Handle<Class> return_type,
+ Handle<ObjectArray<Class>> param_types)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
+ static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return static_class_.Read();
+ }
+
+ ObjectArray<Class>* GetPTypes() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetFieldObject<ObjectArray<Class>>(OFFSET_OF_OBJECT_MEMBER(MethodType, p_types_));
+ }
+
+ Class* GetRType() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(MethodType, r_type_));
+ }
+
+ static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+ static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Returns true iff. |other| is an exact match for this method type, i.e
+ // iff. they have the same return types and parameter types.
+ bool IsExactMatch(mirror::MethodType* other) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+ static MemberOffset FormOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodType, form_));
+ }
+
+ static MemberOffset MethodDescriptorOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodType, method_descriptor_));
+ }
+
+ static MemberOffset PTypesOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodType, p_types_));
+ }
+
+ static MemberOffset RTypeOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodType, r_type_));
+ }
+
+ static MemberOffset WrapAltOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodType, wrap_alt_));
+ }
+
+ HeapReference<mirror::Object> form_; // Unused in the runtime
+ HeapReference<mirror::String> method_descriptor_; // Unused in the runtime
+ HeapReference<ObjectArray<mirror::Class>> p_types_;
+ HeapReference<mirror::Class> r_type_;
+ HeapReference<mirror::Object> wrap_alt_; // Unused in the runtime
+
+ static GcRoot<mirror::Class> static_class_; // java.lang.invoke.MethodType.class
+
+ friend struct art::MethodTypeOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MethodType);
+};
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_METHOD_TYPE_H_
diff --git a/runtime/mirror/method_type_test.cc b/runtime/mirror/method_type_test.cc
new file mode 100644
index 0000000..a968bff
--- /dev/null
+++ b/runtime/mirror/method_type_test.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "method_type.h"
+
+#include <string>
+#include <vector>
+
+#include "class_linker.h"
+#include "common_runtime_test.h"
+#include "handle_scope-inl.h"
+#include "runtime/mirror/class.h"
+#include "runtime/mirror/class_loader.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+namespace mirror {
+
+class MethodTypeTest : public CommonRuntimeTest {};
+
+static std::string FullyQualifiedType(const std::string& shorthand) {
+ return "Ljava/lang/" + shorthand + ";";
+}
+
+static mirror::MethodType* CreateMethodType(const std::string& return_type,
+ const std::vector<std::string>& param_types) {
+ CHECK_LT(param_types.size(), 3u);
+
+ Runtime* const runtime = Runtime::Current();
+ ClassLinker* const class_linker = runtime->GetClassLinker();
+ Thread* const self = Thread::Current();
+
+ ScopedObjectAccess soa(self);
+ StackHandleScope<5> hs(soa.Self());
+
+ Handle<mirror::ClassLoader> boot_class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
+
+ Handle<mirror::Class> return_clazz = hs.NewHandle(class_linker->FindClass(
+ soa.Self(), FullyQualifiedType(return_type).c_str(), boot_class_loader));
+ CHECK(return_clazz.Get() != nullptr);
+
+ mirror::Class* class_type = mirror::Class::GetJavaLangClass();
+ mirror::Class* class_array_type = class_linker->FindArrayClass(self, &class_type);
+ Handle<mirror::ObjectArray<mirror::Class>> param_classes = hs.NewHandle(
+ mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, param_types.size()));
+
+ for (uint32_t i = 0; i < param_types.size(); ++i) {
+ Handle<mirror::Class> param = hs.NewHandle(class_linker->FindClass(
+ soa.Self(), FullyQualifiedType(param_types[i]).c_str(), boot_class_loader));
+ param_classes->Set(i, param.Get());
+ }
+
+ return mirror::MethodType::Create(self, return_clazz, param_classes);
+}
+
+
+TEST_F(MethodTypeTest, IsExactMatch) {
+ ScopedObjectAccess soa(Thread::Current());
+ {
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+ Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+ ASSERT_TRUE(mt1->IsExactMatch(mt2.Get()));
+ }
+
+ // Mismatched return type.
+ {
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+ Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("Integer", { "Integer" }));
+ ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
+ }
+
+ // Mismatched param types.
+ {
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+ Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "String" }));
+ ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
+ }
+
+ // Wrong number of param types.
+ {
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::MethodType> mt1 = hs.NewHandle(
+ CreateMethodType("String", { "String", "String" }));
+ Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "String" }));
+ ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
+ }
+}
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5bb38f5..65b894f 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -88,6 +88,8 @@
#include "mirror/class_loader.h"
#include "mirror/field.h"
#include "mirror/method.h"
+#include "mirror/method_handle_impl.h"
+#include "mirror/method_type.h"
#include "mirror/stack_trace_element.h"
#include "mirror/throwable.h"
#include "monitor.h"
@@ -1547,6 +1549,8 @@
mirror::String::VisitRoots(visitor);
mirror::Throwable::VisitRoots(visitor);
mirror::Field::VisitRoots(visitor);
+ mirror::MethodType::VisitRoots(visitor);
+ mirror::MethodHandleImpl::VisitRoots(visitor);
// Visit all the primitive array types classes.
mirror::PrimitiveArray<uint8_t>::VisitRoots(visitor); // BooleanArray
mirror::PrimitiveArray<int8_t>::VisitRoots(visitor); // ByteArray