ART: invoke-custom support
Adds invoke-custom instruction to the interpreter.
Bug: 33191717,30550796
Test: art/test/run-test --host 952
Change-Id: I3b754128649a8b3a00ade79ba2518d0e377f3a1e
diff --git a/runtime/mirror/call_site.cc b/runtime/mirror/call_site.cc
new file mode 100644
index 0000000..eb613df
--- /dev/null
+++ b/runtime/mirror/call_site.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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 "call_site.h"
+
+#include "class-inl.h"
+#include "gc_root-inl.h"
+
+namespace art {
+namespace mirror {
+
+GcRoot<mirror::Class> CallSite::static_class_;
+
+mirror::CallSite* CallSite::Create(Thread* const self, Handle<MethodHandle> target) {
+ StackHandleScope<1> hs(self);
+ Handle<mirror::CallSite> cs(
+ hs.NewHandle(ObjPtr<CallSite>::DownCast(StaticClass()->AllocObject(self))));
+ CHECK(!Runtime::Current()->IsActiveTransaction());
+ cs->SetFieldObject<false>(TargetOffset(), target.Get());
+ return cs.Get();
+}
+
+void CallSite::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void CallSite::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void CallSite::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/mirror/call_site.h b/runtime/mirror/call_site.h
new file mode 100644
index 0000000..db244a5
--- /dev/null
+++ b/runtime/mirror/call_site.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 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_CALL_SITE_H_
+#define ART_RUNTIME_MIRROR_CALL_SITE_H_
+
+#include "mirror/method_handle_impl.h"
+#include "utils.h"
+
+namespace art {
+
+struct CallSiteOffsets;
+
+namespace mirror {
+
+// C++ mirror of java.lang.invoke.CallSite
+class MANAGED CallSite : public Object {
+ public:
+ static mirror::CallSite* Create(Thread* const self,
+ Handle<MethodHandle> method_handle)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
+ static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return static_class_.Read();
+ }
+
+ MethodHandle* GetTarget() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetFieldObject<MethodHandle>(TargetOffset());
+ }
+
+ 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 inline MemberOffset TargetOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(CallSite, target_));
+ }
+
+ HeapReference<mirror::MethodHandle> target_;
+
+ static GcRoot<mirror::Class> static_class_; // java.lang.invoke.CallSite.class
+
+ friend struct art::CallSiteOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CallSite);
+};
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_CALL_SITE_H_
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index a59bb7b..973c8ed 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -26,6 +26,7 @@
#include "base/logging.h"
#include "gc_root.h"
#include "mirror/class.h"
+#include "mirror/call_site.h"
#include "mirror/method_type.h"
#include "runtime.h"
#include "obj_ptr.h"
@@ -106,6 +107,35 @@
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
}
+inline CallSite* DexCache::GetResolvedCallSite(uint32_t call_site_idx) {
+ DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+ DCHECK_LT(call_site_idx, GetDexFile()->NumCallSiteIds());
+ GcRoot<mirror::CallSite>& target = GetResolvedCallSites()[call_site_idx];
+ Atomic<GcRoot<mirror::CallSite>>& ref =
+ reinterpret_cast<Atomic<GcRoot<mirror::CallSite>>&>(target);
+ return ref.LoadSequentiallyConsistent().Read();
+}
+
+inline CallSite* DexCache::SetResolvedCallSite(uint32_t call_site_idx, CallSite* call_site) {
+ DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+ DCHECK_LT(call_site_idx, GetDexFile()->NumCallSiteIds());
+
+ GcRoot<mirror::CallSite> null_call_site(nullptr);
+ GcRoot<mirror::CallSite> candidate(call_site);
+ GcRoot<mirror::CallSite>& target = GetResolvedCallSites()[call_site_idx];
+
+ // The first assignment for a given call site wins.
+ Atomic<GcRoot<mirror::CallSite>>& ref =
+ reinterpret_cast<Atomic<GcRoot<mirror::CallSite>>&>(target);
+ if (ref.CompareExchangeStrongSequentiallyConsistent(null_call_site, candidate)) {
+ // TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
+ Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
+ return call_site;
+ } else {
+ return target.Read();
+ }
+}
+
inline ArtField* DexCache::GetResolvedField(uint32_t field_idx, PointerSize ptr_size) {
DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), ptr_size);
DCHECK_LT(field_idx, NumResolvedFields()); // NOTE: Unchecked, i.e. not throwing AIOOB.
@@ -208,6 +238,11 @@
VisitDexCachePairs<mirror::MethodType, kReadBarrierOption, Visitor>(
GetResolvedMethodTypes(), NumResolvedMethodTypes(), visitor);
+
+ GcRoot<mirror::CallSite>* resolved_call_sites = GetResolvedCallSites();
+ for (size_t i = 0, num_call_sites = NumResolvedCallSites(); i != num_call_sites; ++i) {
+ visitor.VisitRootIfNonNull(resolved_call_sites[i].AddressWithoutBarrier());
+ }
}
}
@@ -246,6 +281,17 @@
}
}
+template <ReadBarrierOption kReadBarrierOption, typename Visitor>
+inline void DexCache::FixupResolvedCallSites(GcRoot<mirror::CallSite>* dest,
+ const Visitor& visitor) {
+ GcRoot<mirror::CallSite>* src = GetResolvedCallSites();
+ for (size_t i = 0, count = NumResolvedCallSites(); i < count; ++i) {
+ mirror::CallSite* source = src[i].Read<kReadBarrierOption>();
+ mirror::CallSite* new_source = visitor(source);
+ dest[i] = GcRoot<mirror::CallSite>(new_source);
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index 741cf3b..0f6acab 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -90,6 +90,10 @@
raw_arrays + layout.MethodTypesOffset());
}
+ GcRoot<mirror::CallSite>* call_sites = (dex_file->NumCallSiteIds() == 0)
+ ? nullptr
+ : reinterpret_cast<GcRoot<mirror::CallSite>*>(raw_arrays + layout.CallSitesOffset());
+
DCHECK_ALIGNED(raw_arrays, alignof(mirror::StringDexCacheType)) <<
"Expected raw_arrays to align to StringDexCacheType.";
DCHECK_ALIGNED(layout.StringsOffset(), alignof(mirror::StringDexCacheType)) <<
@@ -117,6 +121,9 @@
CHECK_EQ(method_types[i].load(std::memory_order_relaxed).index, 0u);
CHECK(method_types[i].load(std::memory_order_relaxed).object.IsNull());
}
+ for (size_t i = 0; i < dex_file->NumCallSiteIds(); ++i) {
+ CHECK(call_sites[i].IsNull());
+ }
}
if (strings != nullptr) {
mirror::StringDexCachePair::Initialize(strings);
@@ -136,6 +143,8 @@
dex_file->NumFieldIds(),
method_types,
num_method_types,
+ call_sites,
+ dex_file->NumCallSiteIds(),
image_pointer_size);
}
@@ -151,6 +160,8 @@
uint32_t num_resolved_fields,
MethodTypeDexCacheType* resolved_method_types,
uint32_t num_resolved_method_types,
+ GcRoot<CallSite>* resolved_call_sites,
+ uint32_t num_resolved_call_sites,
PointerSize pointer_size) {
CHECK(dex_file != nullptr);
CHECK(location != nullptr);
@@ -159,6 +170,7 @@
CHECK_EQ(num_resolved_methods != 0u, resolved_methods != nullptr);
CHECK_EQ(num_resolved_fields != 0u, resolved_fields != nullptr);
CHECK_EQ(num_resolved_method_types != 0u, resolved_method_types != nullptr);
+ CHECK_EQ(num_resolved_call_sites != 0u, resolved_call_sites != nullptr);
SetDexFile(dex_file);
SetLocation(location);
@@ -167,11 +179,13 @@
SetResolvedMethods(resolved_methods);
SetResolvedFields(resolved_fields);
SetResolvedMethodTypes(resolved_method_types);
+ SetResolvedCallSites(resolved_call_sites);
SetField32<false>(NumStringsOffset(), num_strings);
SetField32<false>(NumResolvedTypesOffset(), num_resolved_types);
SetField32<false>(NumResolvedMethodsOffset(), num_resolved_methods);
SetField32<false>(NumResolvedFieldsOffset(), num_resolved_fields);
SetField32<false>(NumResolvedMethodTypesOffset(), num_resolved_method_types);
+ SetField32<false>(NumResolvedCallSitesOffset(), num_resolved_call_sites);
Runtime* const runtime = Runtime::Current();
if (runtime->HasResolutionMethod()) {
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 6f88cc5..10bb5aa 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -36,6 +36,7 @@
namespace mirror {
+class CallSite;
class MethodType;
class String;
@@ -163,6 +164,10 @@
void FixupResolvedMethodTypes(MethodTypeDexCacheType* dest, const Visitor& visitor)
REQUIRES_SHARED(Locks::mutator_lock_);
+ template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor>
+ void FixupResolvedCallSites(GcRoot<mirror::CallSite>* dest, const Visitor& visitor)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
String* GetLocation() REQUIRES_SHARED(Locks::mutator_lock_) {
return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_));
}
@@ -191,6 +196,10 @@
return OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_method_types_);
}
+ static MemberOffset ResolvedCallSitesOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_call_sites_);
+ }
+
static MemberOffset NumStringsOffset() {
return OFFSET_OF_OBJECT_MEMBER(DexCache, num_strings_);
}
@@ -211,6 +220,10 @@
return OFFSET_OF_OBJECT_MEMBER(DexCache, num_resolved_method_types_);
}
+ static MemberOffset NumResolvedCallSitesOffset() {
+ return OFFSET_OF_OBJECT_MEMBER(DexCache, num_resolved_call_sites_);
+ }
+
mirror::String* GetResolvedString(dex::StringIndex string_idx) ALWAYS_INLINE
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -244,7 +257,18 @@
MethodType* GetResolvedMethodType(uint32_t proto_idx) REQUIRES_SHARED(Locks::mutator_lock_);
- void SetResolvedMethodType(uint32_t proto_idx, MethodType* resolved) REQUIRES_SHARED(Locks::mutator_lock_);
+ void SetResolvedMethodType(uint32_t proto_idx, MethodType* resolved)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ CallSite* GetResolvedCallSite(uint32_t call_site_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Attempts to bind |call_site_idx| to the call site |resolved|. The
+ // caller must use the return value in place of |resolved|. This is
+ // because multiple threads can invoke the bootstrap method each
+ // producing a call site, but the method handle invocation on the
+ // call site must be on a common agreed value.
+ CallSite* SetResolvedCallSite(uint32_t call_site_idx, CallSite* resolved) WARN_UNUSED
+ REQUIRES_SHARED(Locks::mutator_lock_);
StringDexCacheType* GetStrings() ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) {
return GetFieldPtr64<StringDexCacheType*>(StringsOffset());
@@ -295,6 +319,18 @@
SetFieldPtr<false>(ResolvedMethodTypesOffset(), resolved_method_types);
}
+ GcRoot<CallSite>* GetResolvedCallSites()
+ ALWAYS_INLINE
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetFieldPtr<GcRoot<CallSite>*>(ResolvedCallSitesOffset());
+ }
+
+ void SetResolvedCallSites(GcRoot<CallSite>* resolved_call_sites)
+ ALWAYS_INLINE
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ SetFieldPtr<false>(ResolvedCallSitesOffset(), resolved_call_sites);
+ }
+
size_t NumStrings() REQUIRES_SHARED(Locks::mutator_lock_) {
return GetField32(NumStringsOffset());
}
@@ -315,6 +351,10 @@
return GetField32(NumResolvedMethodTypesOffset());
}
+ size_t NumResolvedCallSites() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetField32(NumResolvedCallSitesOffset());
+ }
+
const DexFile* GetDexFile() ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) {
return GetFieldPtr<const DexFile*>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_));
}
@@ -346,8 +386,10 @@
uint32_t num_resolved_methods,
ArtField** resolved_fields,
uint32_t num_resolved_fields,
- MethodTypeDexCacheType* resolved_methodtypes,
- uint32_t num_resolved_methodtypes,
+ MethodTypeDexCacheType* resolved_method_types,
+ uint32_t num_resolved_method_types,
+ GcRoot<CallSite>* resolved_call_sites,
+ uint32_t num_resolved_call_sites,
PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -362,6 +404,8 @@
HeapReference<Object> dex_;
HeapReference<String> location_;
uint64_t dex_file_; // const DexFile*
+ uint64_t resolved_call_sites_; // GcRoot<CallSite>* array with num_resolved_call_sites_
+ // elements.
uint64_t resolved_fields_; // ArtField*, array with num_resolved_fields_ elements.
uint64_t resolved_method_types_; // std::atomic<MethodTypeDexCachePair>* array with
// num_resolved_method_types_ elements.
@@ -370,6 +414,7 @@
uint64_t strings_; // std::atomic<StringDexCachePair>*, array with num_strings_
// elements.
+ uint32_t num_resolved_call_sites_; // Number of elements in the call_sites_ array.
uint32_t num_resolved_fields_; // Number of elements in the resolved_fields_ array.
uint32_t num_resolved_method_types_; // Number of elements in the resolved_method_types_ array.
uint32_t num_resolved_methods_; // Number of elements in the resolved_methods_ array.
diff --git a/runtime/mirror/method_handle_impl.cc b/runtime/mirror/method_handle_impl.cc
index 4f1c448..fa4d25a 100644
--- a/runtime/mirror/method_handle_impl.cc
+++ b/runtime/mirror/method_handle_impl.cc
@@ -28,6 +28,18 @@
return klass;
}
+void MethodHandle::Initialize(uintptr_t art_field_or_method,
+ Kind kind,
+ Handle<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ CHECK(!Runtime::Current()->IsActiveTransaction());
+ SetFieldObject<false>(CachedSpreadInvokerOffset(), nullptr);
+ SetFieldObject<false>(NominalTypeOffset(), nullptr);
+ SetFieldObject<false>(MethodTypeOffset(), method_type.Get());
+ SetField32<false>(HandleKindOffset(), static_cast<uint32_t>(kind));
+ SetField64<false>(ArtFieldOrMethodOffset(), art_field_or_method);
+}
+
GcRoot<mirror::Class> MethodHandleImpl::static_class_;
void MethodHandleImpl::SetClass(Class* klass) {
@@ -45,5 +57,17 @@
static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
}
+mirror::MethodHandleImpl* MethodHandleImpl::Create(Thread* const self,
+ uintptr_t art_field_or_method,
+ MethodHandle::Kind kind,
+ Handle<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) {
+ StackHandleScope<1> hs(self);
+ Handle<mirror::MethodHandleImpl> mh(
+ hs.NewHandle(ObjPtr<MethodHandleImpl>::DownCast(StaticClass()->AllocObject(self))));
+ mh->Initialize(art_field_or_method, kind, method_type);
+ return mh.Get();
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index 53d267b..9938af8 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -17,10 +17,11 @@
#ifndef ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
#define ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
+#include "art_field.h"
+#include "art_method.h"
#include "class.h"
#include "gc_root.h"
#include "object-inl.h"
-#include "method_handles.h"
#include "method_type.h"
namespace art {
@@ -82,10 +83,19 @@
GetField64(OFFSET_OF_OBJECT_MEMBER(MethodHandle, art_field_or_method_)));
}
+ ObjPtr<mirror::Class> GetTargetClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+ Kind kind = GetHandleKind();
+ return (kind <= kLastValidKind) ?
+ GetTargetMethod()->GetDeclaringClass() : GetTargetField()->GetDeclaringClass();
+ }
+
static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ protected:
+ void Initialize(uintptr_t art_field_or_method, Kind kind, Handle<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
- // NOTE: cached_spread_invoker_ isn't used by the runtime.
HeapReference<mirror::MethodHandle> cached_spread_invoker_;
HeapReference<mirror::MethodType> nominal_type_;
HeapReference<mirror::MethodType> method_type_;
@@ -93,6 +103,9 @@
uint64_t art_field_or_method_;
private:
+ static MemberOffset CachedSpreadInvokerOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandle, cached_spread_invoker_));
+ }
static MemberOffset NominalTypeOffset() {
return MemberOffset(OFFSETOF_MEMBER(MethodHandle, nominal_type_));
}
@@ -113,6 +126,12 @@
// C++ mirror of java.lang.invoke.MethodHandleImpl
class MANAGED MethodHandleImpl : public MethodHandle {
public:
+ static mirror::MethodHandleImpl* Create(Thread* const self,
+ uintptr_t art_field_or_method,
+ MethodHandle::Kind kind,
+ Handle<MethodType> method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
return static_class_.Read();
}
diff --git a/runtime/mirror/method_handles_lookup.cc b/runtime/mirror/method_handles_lookup.cc
new file mode 100644
index 0000000..c758e54
--- /dev/null
+++ b/runtime/mirror/method_handles_lookup.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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_handles_lookup.h"
+
+#include "class.h"
+#include "gc_root-inl.h"
+#include "object-inl.h"
+#include "handle_scope.h"
+#include "modifiers.h"
+
+namespace art {
+namespace mirror {
+
+GcRoot<mirror::Class> MethodHandlesLookup::static_class_;
+
+void MethodHandlesLookup::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void MethodHandlesLookup::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void MethodHandlesLookup::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+MethodHandlesLookup* MethodHandlesLookup::Create(Thread* const self, Handle<Class> lookup_class)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) {
+ static constexpr uint32_t kAllModes = kAccPublic | kAccPrivate | kAccProtected | kAccStatic;
+
+ StackHandleScope<1> hs(self);
+ Handle<MethodHandlesLookup> mhl(
+ hs.NewHandle(ObjPtr<MethodHandlesLookup>::DownCast(StaticClass()->AllocObject(self))));
+ mhl->SetFieldObject<false>(LookupClassOffset(), lookup_class.Get());
+ mhl->SetField32<false>(AllowedModesOffset(), kAllModes);
+ return mhl.Get();
+}
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/mirror/method_handles_lookup.h b/runtime/mirror/method_handles_lookup.h
new file mode 100644
index 0000000..63eb428
--- /dev/null
+++ b/runtime/mirror/method_handles_lookup.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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_HANDLES_LOOKUP_H_
+#define ART_RUNTIME_MIRROR_METHOD_HANDLES_LOOKUP_H_
+
+#include "obj_ptr.h"
+#include "gc_root.h"
+#include "object.h"
+#include "handle.h"
+#include "utils.h"
+
+namespace art {
+
+struct MethodHandlesLookupOffsets;
+class RootVisitor;
+
+namespace mirror {
+
+// C++ mirror of java.lang.invoke.MethodHandles.Lookup
+class MANAGED MethodHandlesLookup : public Object {
+ public:
+ static mirror::MethodHandlesLookup* Create(Thread* const self,
+ Handle<Class> lookup_class)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
+ 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 MemberOffset AllowedModesOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandlesLookup, allowed_modes_));
+ }
+
+ static MemberOffset LookupClassOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandlesLookup, lookup_class_));
+ }
+
+ HeapReference<mirror::Class> lookup_class_;
+
+ int32_t allowed_modes_;
+
+ static GcRoot<mirror::Class> static_class_; // java.lang.invoke.MethodHandles.Lookup.class
+
+ friend struct art::MethodHandlesLookupOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MethodHandlesLookup);
+};
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_METHOD_HANDLES_LOOKUP_H_
diff --git a/runtime/mirror/method_type.cc b/runtime/mirror/method_type.cc
index 5d77a16..4b8dfac 100644
--- a/runtime/mirror/method_type.cc
+++ b/runtime/mirror/method_type.cc
@@ -44,6 +44,22 @@
return mt.Get();
}
+size_t MethodType::NumberOfVRegs() REQUIRES_SHARED(Locks::mutator_lock_) {
+ mirror::ObjectArray<Class>* const p_types = GetPTypes();
+ const int32_t p_types_length = p_types->GetLength();
+
+ // Initialize |num_vregs| with number of parameters and only increment it for
+ // types requiring a second vreg.
+ size_t num_vregs = static_cast<size_t>(p_types_length);
+ for (int32_t i = 0; i < p_types_length; ++i) {
+ mirror::Class* klass = p_types->GetWithoutChecks(i);
+ if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
+ ++num_vregs;
+ }
+ }
+ return num_vregs;
+}
+
bool MethodType::IsExactMatch(mirror::MethodType* target) REQUIRES_SHARED(Locks::mutator_lock_) {
mirror::ObjectArray<Class>* const p_types = GetPTypes();
const int32_t params_length = p_types->GetLength();
diff --git a/runtime/mirror/method_type.h b/runtime/mirror/method_type.h
index 9a98143..374bbe5 100644
--- a/runtime/mirror/method_type.h
+++ b/runtime/mirror/method_type.h
@@ -44,6 +44,10 @@
return GetFieldObject<ObjectArray<Class>>(OFFSET_OF_OBJECT_MEMBER(MethodType, p_types_));
}
+ // Number of virtual registers required to hold the parameters for
+ // this method type.
+ size_t NumberOfVRegs() REQUIRES_SHARED(Locks::mutator_lock_);
+
Class* GetRType() REQUIRES_SHARED(Locks::mutator_lock_) {
return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(MethodType, r_type_));
}