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