java.lang.invoke: Add mirror types for MethodHandle / MethodType.
Bug: 30550796
Test: make test-art-host
Change-Id: I096160464bc6e84f7e5ad021306a7e462cf3b0c5
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