Merge "ART: Add mirror classes for VarHandles"
diff --git a/runtime/Android.bp b/runtime/Android.bp
index afc7d27..ff5ae9f 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -153,6 +153,7 @@
"mirror/stack_trace_element.cc",
"mirror/string.cc",
"mirror/throwable.cc",
+ "mirror/var_handle.cc",
"monitor.cc",
"native_bridge_art_interface.cc",
"native_stack_dump.cc",
@@ -599,6 +600,7 @@
"mirror/dex_cache_test.cc",
"mirror/method_type_test.cc",
"mirror/object_test.cc",
+ "mirror/var_handle_test.cc",
"monitor_pool_test.cc",
"monitor_test.cc",
"oat_file_test.cc",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index b199933..5435c11 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -98,6 +98,7 @@
#include "mirror/reference-inl.h"
#include "mirror/stack_trace_element.h"
#include "mirror/string-inl.h"
+#include "mirror/var_handle.h"
#include "native/dalvik_system_DexFile.h"
#include "nativehelper/scoped_local_ref.h"
#include "oat.h"
@@ -698,6 +699,12 @@
SetClassRoot(kJavaLangReflectMethodArrayClass, class_root);
mirror::Method::SetArrayClass(class_root);
+ // Create java.lang.invoke.CallSite.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/CallSite;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangInvokeCallSite, class_root);
+ mirror::CallSite::SetClass(class_root);
+
// Create java.lang.invoke.MethodType.class root
class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodType;");
CHECK(class_root != nullptr);
@@ -716,11 +723,35 @@
SetClassRoot(kJavaLangInvokeMethodHandlesLookup, class_root);
mirror::MethodHandlesLookup::SetClass(class_root);
- // Create java.lang.invoke.CallSite.class root
- class_root = FindSystemClass(self, "Ljava/lang/invoke/CallSite;");
+ // Create java.lang.invoke.VarHandle.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/VarHandle;");
CHECK(class_root != nullptr);
- SetClassRoot(kJavaLangInvokeCallSite, class_root);
- mirror::CallSite::SetClass(class_root);
+ SetClassRoot(kJavaLangInvokeVarHandle, class_root);
+ mirror::VarHandle::SetClass(class_root);
+
+ // Create java.lang.invoke.FieldVarHandle.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/FieldVarHandle;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangInvokeFieldVarHandle, class_root);
+ mirror::FieldVarHandle::SetClass(class_root);
+
+ // Create java.lang.invoke.ArrayElementVarHandle.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/ArrayElementVarHandle;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangInvokeArrayElementVarHandle, class_root);
+ mirror::ArrayElementVarHandle::SetClass(class_root);
+
+ // Create java.lang.invoke.ByteArrayViewVarHandle.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/ByteArrayViewVarHandle;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangInvokeByteArrayViewVarHandle, class_root);
+ mirror::ByteArrayViewVarHandle::SetClass(class_root);
+
+ // Create java.lang.invoke.ByteBufferViewVarHandle.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/ByteBufferViewVarHandle;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangInvokeByteBufferViewVarHandle, class_root);
+ mirror::ByteBufferViewVarHandle::SetClass(class_root);
class_root = FindSystemClass(self, "Ldalvik/system/EmulatedStackFrame;");
CHECK(class_root != nullptr);
@@ -988,10 +1019,15 @@
mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass));
mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass));
- mirror::MethodType::SetClass(GetClassRoot(kJavaLangInvokeMethodType));
+ mirror::CallSite::SetClass(GetClassRoot(kJavaLangInvokeCallSite));
mirror::MethodHandleImpl::SetClass(GetClassRoot(kJavaLangInvokeMethodHandleImpl));
mirror::MethodHandlesLookup::SetClass(GetClassRoot(kJavaLangInvokeMethodHandlesLookup));
- mirror::CallSite::SetClass(GetClassRoot(kJavaLangInvokeCallSite));
+ mirror::MethodType::SetClass(GetClassRoot(kJavaLangInvokeMethodType));
+ mirror::VarHandle::SetClass(GetClassRoot(kJavaLangInvokeVarHandle));
+ mirror::FieldVarHandle::SetClass(GetClassRoot(kJavaLangInvokeFieldVarHandle));
+ mirror::ArrayElementVarHandle::SetClass(GetClassRoot(kJavaLangInvokeArrayElementVarHandle));
+ mirror::ByteArrayViewVarHandle::SetClass(GetClassRoot(kJavaLangInvokeByteArrayViewVarHandle));
+ mirror::ByteBufferViewVarHandle::SetClass(GetClassRoot(kJavaLangInvokeByteBufferViewVarHandle));
mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
@@ -2083,10 +2119,15 @@
mirror::IntArray::ResetArrayClass();
mirror::LongArray::ResetArrayClass();
mirror::ShortArray::ResetArrayClass();
+ mirror::CallSite::ResetClass();
mirror::MethodType::ResetClass();
mirror::MethodHandleImpl::ResetClass();
mirror::MethodHandlesLookup::ResetClass();
- mirror::CallSite::ResetClass();
+ mirror::VarHandle::ResetClass();
+ mirror::FieldVarHandle::ResetClass();
+ mirror::ArrayElementVarHandle::ResetClass();
+ mirror::ByteArrayViewVarHandle::ResetClass();
+ mirror::ByteBufferViewVarHandle::ResetClass();
mirror::EmulatedStackFrame::ResetClass();
Thread* const self = Thread::Current();
for (const ClassLoaderData& data : class_loaders_) {
@@ -8484,6 +8525,11 @@
"Ljava/lang/invoke/MethodHandleImpl;",
"Ljava/lang/invoke/MethodHandles$Lookup;",
"Ljava/lang/invoke/MethodType;",
+ "Ljava/lang/invoke/VarHandle;",
+ "Ljava/lang/invoke/FieldVarHandle;",
+ "Ljava/lang/invoke/ArrayElementVarHandle;",
+ "Ljava/lang/invoke/ByteArrayViewVarHandle;",
+ "Ljava/lang/invoke/ByteBufferViewVarHandle;",
"Ljava/lang/ClassLoader;",
"Ljava/lang/Throwable;",
"Ljava/lang/ClassNotFoundException;",
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index eba2022..2d9ec5a 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -120,6 +120,11 @@
kJavaLangInvokeMethodHandleImpl,
kJavaLangInvokeMethodHandlesLookup,
kJavaLangInvokeMethodType,
+ kJavaLangInvokeVarHandle,
+ kJavaLangInvokeFieldVarHandle,
+ kJavaLangInvokeArrayElementVarHandle,
+ kJavaLangInvokeByteArrayViewVarHandle,
+ kJavaLangInvokeByteBufferViewVarHandle,
kJavaLangClassLoader,
kJavaLangThrowable,
kJavaLangClassNotFoundException,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 3e92317..4d92826 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -48,6 +48,7 @@
#include "mirror/reference.h"
#include "mirror/stack_trace_element.h"
#include "mirror/string-inl.h"
+#include "mirror/var_handle.h"
#include "scoped_thread_state_change-inl.h"
#include "standard_dex_file.h"
#include "thread-current-inl.h"
@@ -777,6 +778,39 @@
}
};
+struct VarHandleOffsets : public CheckOffsets<mirror::VarHandle> {
+ VarHandleOffsets() : CheckOffsets<mirror::VarHandle>(
+ false, "Ljava/lang/invoke/VarHandle;") {
+ addOffset(OFFSETOF_MEMBER(mirror::VarHandle, access_modes_bit_mask_), "accessModesBitMask");
+ addOffset(OFFSETOF_MEMBER(mirror::VarHandle, coordinate_type0_), "coordinateType0");
+ addOffset(OFFSETOF_MEMBER(mirror::VarHandle, coordinate_type1_), "coordinateType1");
+ addOffset(OFFSETOF_MEMBER(mirror::VarHandle, var_type_), "varType");
+ }
+};
+
+struct FieldVarHandleOffsets : public CheckOffsets<mirror::FieldVarHandle> {
+ FieldVarHandleOffsets() : CheckOffsets<mirror::FieldVarHandle>(
+ false, "Ljava/lang/invoke/FieldVarHandle;") {
+ addOffset(OFFSETOF_MEMBER(mirror::FieldVarHandle, art_field_), "artField");
+ }
+};
+
+struct ByteArrayViewVarHandleOffsets : public CheckOffsets<mirror::ByteArrayViewVarHandle> {
+ ByteArrayViewVarHandleOffsets() : CheckOffsets<mirror::ByteArrayViewVarHandle>(
+ false, "Ljava/lang/invoke/ByteArrayViewVarHandle;") {
+ addOffset(OFFSETOF_MEMBER(mirror::ByteArrayViewVarHandle, native_byte_order_),
+ "nativeByteOrder");
+ }
+};
+
+struct ByteBufferViewVarHandleOffsets : public CheckOffsets<mirror::ByteBufferViewVarHandle> {
+ ByteBufferViewVarHandleOffsets() : CheckOffsets<mirror::ByteBufferViewVarHandle>(
+ false, "Ljava/lang/invoke/ByteBufferViewVarHandle;") {
+ addOffset(OFFSETOF_MEMBER(mirror::ByteBufferViewVarHandle, native_byte_order_),
+ "nativeByteOrder");
+ }
+};
+
// 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.
@@ -802,6 +836,10 @@
EXPECT_TRUE(MethodHandlesLookupOffsets().Check());
EXPECT_TRUE(EmulatedStackFrameOffsets().Check());
EXPECT_TRUE(CallSiteOffsets().Check());
+ EXPECT_TRUE(VarHandleOffsets().Check());
+ EXPECT_TRUE(FieldVarHandleOffsets().Check());
+ EXPECT_TRUE(ByteArrayViewVarHandleOffsets().Check());
+ EXPECT_TRUE(ByteBufferViewVarHandleOffsets().Check());
}
TEST_F(ClassLinkerTest, FindClassNonexistent) {
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
new file mode 100644
index 0000000..e7eac1a
--- /dev/null
+++ b/runtime/mirror/var_handle.cc
@@ -0,0 +1,399 @@
+/*
+ * 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 "var_handle.h"
+
+#include "class-inl.h"
+#include "class_linker.h"
+#include "gc_root-inl.h"
+#include "method_type.h"
+
+namespace art {
+namespace mirror {
+
+namespace {
+
+// Enumeration for describing the parameter and return types of an AccessMode.
+enum class AccessModeTemplate : uint32_t {
+ kGet, // T Op(C0..CN)
+ kSet, // void Op(C0..CN, T)
+ kCompareAndSet, // boolean Op(C0..CN, T, T)
+ kCompareAndExchange, // T Op(C0..CN, T, T)
+ kGetAndUpdate, // T Op(C0..CN, T)
+};
+
+// Look up the AccessModeTemplate for a given VarHandle
+// AccessMode. This simplifies finding the correct signature for a
+// VarHandle accessor method.
+AccessModeTemplate GetAccessModeTemplate(VarHandle::AccessMode access_mode) {
+ switch (access_mode) {
+ case VarHandle::AccessMode::kGet:
+ return AccessModeTemplate::kGet;
+ case VarHandle::AccessMode::kSet:
+ return AccessModeTemplate::kSet;
+ case VarHandle::AccessMode::kGetVolatile:
+ return AccessModeTemplate::kGet;
+ case VarHandle::AccessMode::kSetVolatile:
+ return AccessModeTemplate::kSet;
+ case VarHandle::AccessMode::kGetAcquire:
+ return AccessModeTemplate::kGet;
+ case VarHandle::AccessMode::kSetRelease:
+ return AccessModeTemplate::kSet;
+ case VarHandle::AccessMode::kGetOpaque:
+ return AccessModeTemplate::kGet;
+ case VarHandle::AccessMode::kSetOpaque:
+ return AccessModeTemplate::kSet;
+ case VarHandle::AccessMode::kCompareAndSet:
+ return AccessModeTemplate::kCompareAndSet;
+ case VarHandle::AccessMode::kCompareAndExchange:
+ return AccessModeTemplate::kCompareAndExchange;
+ case VarHandle::AccessMode::kCompareAndExchangeAcquire:
+ return AccessModeTemplate::kCompareAndExchange;
+ case VarHandle::AccessMode::kCompareAndExchangeRelease:
+ return AccessModeTemplate::kCompareAndExchange;
+ case VarHandle::AccessMode::kWeakCompareAndSetPlain:
+ return AccessModeTemplate::kCompareAndSet;
+ case VarHandle::AccessMode::kWeakCompareAndSet:
+ return AccessModeTemplate::kCompareAndSet;
+ case VarHandle::AccessMode::kWeakCompareAndSetAcquire:
+ return AccessModeTemplate::kCompareAndSet;
+ case VarHandle::AccessMode::kWeakCompareAndSetRelease:
+ return AccessModeTemplate::kCompareAndSet;
+ case VarHandle::AccessMode::kGetAndSet:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndSetAcquire:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndSetRelease:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndAdd:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndAddAcquire:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndAddRelease:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndBitwiseOr:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndBitwiseOrRelease:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndBitwiseOrAcquire:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndBitwiseAnd:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndBitwiseAndRelease:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndBitwiseAndAcquire:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndBitwiseXor:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndBitwiseXorRelease:
+ return AccessModeTemplate::kGetAndUpdate;
+ case VarHandle::AccessMode::kGetAndBitwiseXorAcquire:
+ return AccessModeTemplate::kGetAndUpdate;
+ }
+}
+
+// Returns the number of parameters associated with an
+// AccessModeTemplate and the supplied coordinate types.
+int32_t GetParameterCount(AccessModeTemplate access_mode_template,
+ ObjPtr<Class> coordinateType0,
+ ObjPtr<Class> coordinateType1) {
+ int32_t index = 0;
+ if (!coordinateType0.IsNull()) {
+ index++;
+ if (!coordinateType1.IsNull()) {
+ index++;
+ }
+ }
+
+ switch (access_mode_template) {
+ case AccessModeTemplate::kGet:
+ return index;
+ case AccessModeTemplate::kSet:
+ case AccessModeTemplate::kGetAndUpdate:
+ return index + 1;
+ case AccessModeTemplate::kCompareAndSet:
+ case AccessModeTemplate::kCompareAndExchange:
+ return index + 2;
+ }
+ UNREACHABLE();
+}
+
+// Writes the parameter types associated with the AccessModeTemplate
+// into an array. The parameter types are derived from the specified
+// variable type and coordinate types. Returns the number of
+// parameters written.
+int32_t BuildParameterArray(ObjPtr<Class> (¶meters)[VarHandle::kMaxAccessorParameters],
+ AccessModeTemplate access_mode_template,
+ ObjPtr<Class> varType,
+ ObjPtr<Class> coordinateType0,
+ ObjPtr<Class> coordinateType1)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(varType != nullptr);
+ int32_t index = 0;
+ if (!coordinateType0.IsNull()) {
+ parameters[index++] = coordinateType0;
+ if (!coordinateType1.IsNull()) {
+ parameters[index++] = coordinateType1;
+ }
+ } else {
+ DCHECK(coordinateType1.IsNull());
+ }
+
+ switch (access_mode_template) {
+ case AccessModeTemplate::kCompareAndExchange:
+ case AccessModeTemplate::kCompareAndSet:
+ parameters[index++] = varType;
+ parameters[index++] = varType;
+ return index;
+ case AccessModeTemplate::kGet:
+ return index;
+ case AccessModeTemplate::kGetAndUpdate:
+ case AccessModeTemplate::kSet:
+ parameters[index++] = varType;
+ return index;
+ }
+ return -1;
+}
+
+// Returns the return type associated with an AccessModeTemplate based
+// on the template and the variable type specified.
+Class* GetReturnType(AccessModeTemplate access_mode_template, ObjPtr<Class> varType)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(varType != nullptr);
+ switch (access_mode_template) {
+ case AccessModeTemplate::kCompareAndSet:
+ return Runtime::Current()->GetClassLinker()->FindPrimitiveClass('Z');
+ case AccessModeTemplate::kCompareAndExchange:
+ case AccessModeTemplate::kGet:
+ case AccessModeTemplate::kGetAndUpdate:
+ return varType.Ptr();
+ case AccessModeTemplate::kSet:
+ return Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V');
+ }
+ return nullptr;
+}
+
+ObjectArray<Class>* NewArrayOfClasses(Thread* self, int count)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ Runtime* const runtime = Runtime::Current();
+ ClassLinker* const class_linker = runtime->GetClassLinker();
+ ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass();
+ ObjPtr<mirror::Class> array_of_class = class_linker->FindArrayClass(self, &class_type);
+ return ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, count);
+}
+
+} // namespace
+
+Class* VarHandle::GetVarType() {
+ return GetFieldObject<Class>(VarTypeOffset());
+}
+
+Class* VarHandle::GetCoordinateType0() {
+ return GetFieldObject<Class>(CoordinateType0Offset());
+}
+
+Class* VarHandle::GetCoordinateType1() {
+ return GetFieldObject<Class>(CoordinateType1Offset());
+}
+
+int32_t VarHandle::GetAccessModesBitMask() {
+ return GetField32(AccessModesBitMaskOffset());
+}
+
+bool VarHandle::IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type) {
+ ScopedAssertNoThreadSuspension ants(__FUNCTION__);
+
+ AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
+ // Check return types first.
+ ObjPtr<Class> var_type = GetVarType();
+ ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type);
+ ObjPtr<Class> void_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass('V');
+ ObjPtr<Class> mt_rtype = method_type->GetRType();
+
+ // If the mt_rtype is void, the result of the operation will be discarded (okay).
+ if (mt_rtype != void_type && mt_rtype != vh_rtype) {
+ return false;
+ }
+
+ // Check the number of parameters matches.
+ ObjPtr<Class> vh_ptypes[VarHandle::kMaxAccessorParameters];
+ const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes,
+ access_mode_template,
+ var_type,
+ GetCoordinateType0(),
+ GetCoordinateType1());
+ if (vh_ptypes_count != method_type->GetPTypes()->GetLength()) {
+ return false;
+ }
+
+ // Check the parameter types match.
+ ObjPtr<ObjectArray<Class>> mt_ptypes = method_type->GetPTypes();
+ for (int32_t i = 0; i < vh_ptypes_count; ++i) {
+ if (mt_ptypes->Get(i) != vh_ptypes[i].Ptr()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self,
+ ObjPtr<VarHandle> var_handle,
+ AccessMode access_mode) {
+ // This is a static as the var_handle might be moved by the GC during it's execution.
+ AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
+
+ StackHandleScope<3> hs(self);
+ Handle<VarHandle> vh = hs.NewHandle(var_handle);
+ Handle<Class> rtype = hs.NewHandle(GetReturnType(access_mode_template, vh->GetVarType()));
+ const int32_t ptypes_count =
+ GetParameterCount(access_mode_template, vh->GetCoordinateType0(), vh->GetCoordinateType1());
+ Handle<ObjectArray<Class>> ptypes = hs.NewHandle(NewArrayOfClasses(self, ptypes_count));
+ if (ptypes == nullptr) {
+ return nullptr;
+ }
+
+ ObjPtr<Class> ptypes_array[VarHandle::kMaxAccessorParameters];
+ BuildParameterArray(ptypes_array,
+ access_mode_template,
+ vh->GetVarType(),
+ vh->GetCoordinateType0(),
+ vh->GetCoordinateType1());
+ for (int32_t i = 0; i < ptypes_count; ++i) {
+ ptypes->Set(i, ptypes_array[i].Ptr());
+ }
+ return MethodType::Create(self, rtype, ptypes);
+}
+
+MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode access_mode) {
+ return GetMethodTypeForAccessMode(self, this, access_mode);
+}
+
+void VarHandle::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void VarHandle::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void VarHandle::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+GcRoot<Class> VarHandle::static_class_;
+
+ArtField* FieldVarHandle::GetField() {
+ uintptr_t opaque_field = static_cast<uintptr_t>(GetField64(ArtFieldOffset()));
+ return reinterpret_cast<ArtField*>(opaque_field);
+}
+
+Class* FieldVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return static_class_.Read();
+}
+
+void FieldVarHandle::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void FieldVarHandle::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void FieldVarHandle::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+GcRoot<Class> FieldVarHandle::static_class_;
+
+Class* ArrayElementVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return static_class_.Read();
+}
+
+void ArrayElementVarHandle::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void ArrayElementVarHandle::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void ArrayElementVarHandle::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+GcRoot<Class> ArrayElementVarHandle::static_class_;
+
+bool ByteArrayViewVarHandle::GetNativeByteOrder() {
+ return GetFieldBoolean(NativeByteOrderOffset());
+}
+
+Class* ByteArrayViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return static_class_.Read();
+}
+
+void ByteArrayViewVarHandle::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void ByteArrayViewVarHandle::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void ByteArrayViewVarHandle::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+GcRoot<Class> ByteArrayViewVarHandle::static_class_;
+
+bool ByteBufferViewVarHandle::GetNativeByteOrder() {
+ return GetFieldBoolean(NativeByteOrderOffset());
+}
+
+Class* ByteBufferViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return static_class_.Read();
+}
+
+void ByteBufferViewVarHandle::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void ByteBufferViewVarHandle::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void ByteBufferViewVarHandle::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+GcRoot<Class> ByteBufferViewVarHandle::static_class_;
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
new file mode 100644
index 0000000..a2a5d8c
--- /dev/null
+++ b/runtime/mirror/var_handle.h
@@ -0,0 +1,255 @@
+/*
+ * 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_VAR_HANDLE_H_
+#define ART_RUNTIME_MIRROR_VAR_HANDLE_H_
+
+#include "handle.h"
+#include "gc_root.h"
+#include "object.h"
+
+namespace art {
+
+template<class T> class Handle;
+struct VarHandleOffsets;
+struct FieldVarHandleOffsets;
+struct ByteArrayViewVarHandleOffsets;
+struct ByteBufferViewVarHandleOffsets;
+
+namespace mirror {
+
+class MethodType;
+class VarHandleTest;
+
+// C++ mirror of java.lang.invoke.VarHandle
+class MANAGED VarHandle : public Object {
+ public:
+ // The maximum number of parameters a VarHandle accessor method can
+ // take. The Worst case is equivalent to a compare-and-swap
+ // operation on an array element which requires four parameters
+ // (array, index, old, new).
+ static constexpr int kMaxAccessorParameters = 4;
+
+ // Enumeration of the possible access modes. This mirrors the enum
+ // in java.lang.invoke.VarHandle.
+ enum class AccessMode : uint32_t {
+ kGet,
+ kSet,
+ kGetVolatile,
+ kSetVolatile,
+ kGetAcquire,
+ kSetRelease,
+ kGetOpaque,
+ kSetOpaque,
+ kCompareAndSet,
+ kCompareAndExchange,
+ kCompareAndExchangeAcquire,
+ kCompareAndExchangeRelease,
+ kWeakCompareAndSetPlain,
+ kWeakCompareAndSet,
+ kWeakCompareAndSetAcquire,
+ kWeakCompareAndSetRelease,
+ kGetAndSet,
+ kGetAndSetAcquire,
+ kGetAndSetRelease,
+ kGetAndAdd,
+ kGetAndAddAcquire,
+ kGetAndAddRelease,
+ kGetAndBitwiseOr,
+ kGetAndBitwiseOrRelease,
+ kGetAndBitwiseOrAcquire,
+ kGetAndBitwiseAnd,
+ kGetAndBitwiseAndRelease,
+ kGetAndBitwiseAndAcquire,
+ kGetAndBitwiseXor,
+ kGetAndBitwiseXorRelease,
+ kGetAndBitwiseXorAcquire,
+ };
+
+ // Returns true if the AccessMode specified is a supported operation.
+ bool IsAccessModeSupported(AccessMode accessMode) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return (GetAccessModesBitMask() & (1u << static_cast<uint32_t>(accessMode))) != 0;
+ }
+
+ // Returns true if the MethodType specified is compatible with the
+ // method type associated with the specified AccessMode. The
+ // supplied MethodType is assumed to be from the point of invocation
+ // so it is valid for the supplied MethodType to have a void return
+ // value when the return value for the AccessMode is non-void. This
+ // corresponds to the result of the accessor being discarded.
+ bool IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Allocates and returns the MethodType associated with the
+ // AccessMode. No check is made for whether the AccessMode is a
+ // supported operation so the MethodType can be used when raising a
+ // WrongMethodTypeException exception.
+ MethodType* GetMethodTypeForAccessMode(Thread* self, AccessMode accessMode)
+ 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:
+ Class* GetVarType() REQUIRES_SHARED(Locks::mutator_lock_);
+ Class* GetCoordinateType0() REQUIRES_SHARED(Locks::mutator_lock_);
+ Class* GetCoordinateType1() REQUIRES_SHARED(Locks::mutator_lock_);
+ int32_t GetAccessModesBitMask() REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static MethodType* GetMethodTypeForAccessMode(Thread* self,
+ ObjPtr<VarHandle> var_handle,
+ AccessMode access_mode)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static MemberOffset VarTypeOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(VarHandle, var_type_));
+ }
+
+ static MemberOffset CoordinateType0Offset() {
+ return MemberOffset(OFFSETOF_MEMBER(VarHandle, coordinate_type0_));
+ }
+
+ static MemberOffset CoordinateType1Offset() {
+ return MemberOffset(OFFSETOF_MEMBER(VarHandle, coordinate_type1_));
+ }
+
+ static MemberOffset AccessModesBitMaskOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(VarHandle, access_modes_bit_mask_));
+ }
+
+ HeapReference<mirror::Class> coordinate_type0_;
+ HeapReference<mirror::Class> coordinate_type1_;
+ HeapReference<mirror::Class> var_type_;
+ int32_t access_modes_bit_mask_;
+
+ // Root representing java.lang.invoke.VarHandle.class.
+ static GcRoot<mirror::Class> static_class_;
+
+ friend class VarHandleTest; // for testing purposes
+ friend struct art::VarHandleOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(VarHandle);
+};
+
+// Represents a VarHandle to a static or instance field.
+// The corresponding managed class in libart java.lang.invoke.FieldVarHandle.
+class MANAGED FieldVarHandle : public VarHandle {
+ public:
+ ArtField* GetField() REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ 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 ArtFieldOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(FieldVarHandle, art_field_));
+ }
+
+ // ArtField instance corresponding to variable for accessors.
+ int64_t art_field_;
+
+ // Root representing java.lang.invoke.FieldVarHandle.class.
+ static GcRoot<mirror::Class> static_class_;
+
+ friend class VarHandleTest; // for var_handle_test.
+ friend struct art::FieldVarHandleOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FieldVarHandle);
+};
+
+// Represents a VarHandle providing accessors to an array.
+// The corresponding managed class in libart java.lang.invoke.ArrayElementVarHandle.
+class MANAGED ArrayElementVarHandle : public VarHandle {
+ public:
+ static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ 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:
+ // Root representing java.lang.invoke.ArrayElementVarHandle.class.
+ static GcRoot<mirror::Class> static_class_;
+
+ friend class VarHandleTest;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ArrayElementVarHandle);
+};
+
+// Represents a VarHandle providing accessors to a view of a ByteArray.
+// The corresponding managed class in libart java.lang.invoke.ByteArrayViewVarHandle.
+class MANAGED ByteArrayViewVarHandle : public VarHandle {
+ public:
+ bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ 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 NativeByteOrderOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(ByteArrayViewVarHandle, native_byte_order_));
+ }
+
+ // Flag indicating that accessors should use native byte-ordering.
+ uint8_t native_byte_order_;
+
+ // Root representing java.lang.invoke.ByteArrayViewVarHandle.class.
+ static GcRoot<mirror::Class> static_class_;
+
+ friend class VarHandleTest; // for var_handle_test.
+ friend struct art::ByteArrayViewVarHandleOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ByteArrayViewVarHandle);
+};
+
+// Represents a VarHandle providing accessors to a view of a ByteBuffer
+// The corresponding managed class in libart java.lang.invoke.ByteBufferViewVarHandle.
+class MANAGED ByteBufferViewVarHandle : public VarHandle {
+ public:
+ bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static ByteBufferViewVarHandle* Create(Thread* const self, bool native_byte_order)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
+ static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ 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 NativeByteOrderOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(ByteBufferViewVarHandle, native_byte_order_));
+ }
+
+ // Flag indicating that accessors should use native byte-ordering.
+ uint8_t native_byte_order_;
+
+ // Root representing java.lang.invoke.ByteBufferViewVarHandle.class.
+ static GcRoot<mirror::Class> static_class_;
+
+ friend class VarHandleTest; // for var_handle_test.
+ friend struct art::ByteBufferViewVarHandleOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ByteBufferViewVarHandle);
+};
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_VAR_HANDLE_H_
diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc
new file mode 100644
index 0000000..0e1c994
--- /dev/null
+++ b/runtime/mirror/var_handle_test.cc
@@ -0,0 +1,991 @@
+/*
+ * 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 "var_handle.h"
+
+#include <string>
+#include <vector>
+
+#include "art_field-inl.h"
+#include "class-inl.h"
+#include "class_linker-inl.h"
+#include "class_loader.h"
+#include "common_runtime_test.h"
+#include "handle_scope-inl.h"
+#include "jvalue-inl.h"
+#include "method_type.h"
+#include "object_array-inl.h"
+#include "reflection.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+namespace mirror {
+
+// Tests for mirror::VarHandle and it's descendents.
+class VarHandleTest : public CommonRuntimeTest {
+ public:
+ static FieldVarHandle* CreateFieldVarHandle(Thread* const self,
+ ArtField* art_field,
+ int32_t access_modes_bit_mask)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) {
+ StackHandleScope<4> hs(self);
+ Handle<FieldVarHandle> fvh = hs.NewHandle(
+ ObjPtr<FieldVarHandle>::DownCast(FieldVarHandle::StaticClass()->AllocObject(self)));
+ Handle<Class> var_type = hs.NewHandle(art_field->GetType<true>().Ptr());
+
+ if (art_field->IsStatic()) {
+ InitializeVarHandle(fvh.Get(), var_type, access_modes_bit_mask);
+ } else {
+ Handle<Class> declaring_type = hs.NewHandle(art_field->GetDeclaringClass().Ptr());
+ InitializeVarHandle(fvh.Get(),
+ var_type,
+ declaring_type,
+ access_modes_bit_mask);
+ }
+ uintptr_t opaque_field = reinterpret_cast<uintptr_t>(art_field);
+ fvh->SetField64<false>(FieldVarHandle::ArtFieldOffset(), opaque_field);
+ return fvh.Get();
+ }
+
+ static ArrayElementVarHandle* CreateArrayElementVarHandle(Thread* const self,
+ Handle<Class> array_class,
+ int32_t access_modes_bit_mask)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) {
+ StackHandleScope<3> hs(self);
+ Handle<ArrayElementVarHandle> vh = hs.NewHandle(
+ ObjPtr<ArrayElementVarHandle>::DownCast(
+ ArrayElementVarHandle::StaticClass()->AllocObject(self)));
+
+ // Initialize super class fields
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Handle<Class> var_type = hs.NewHandle(array_class->GetComponentType());
+ Handle<Class> index_type = hs.NewHandle(class_linker->FindPrimitiveClass('I'));
+ InitializeVarHandle(vh.Get(), var_type, array_class, index_type, access_modes_bit_mask);
+ return vh.Get();
+ }
+
+ static ByteArrayViewVarHandle* CreateByteArrayViewVarHandle(Thread* const self,
+ Handle<Class> view_array_class,
+ bool native_byte_order,
+ int32_t access_modes_bit_mask)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) {
+ StackHandleScope<4> hs(self);
+ Handle<ByteArrayViewVarHandle> bvh = hs.NewHandle(
+ ObjPtr<ByteArrayViewVarHandle>::DownCast(
+ ByteArrayViewVarHandle::StaticClass()->AllocObject(self)));
+
+ // Initialize super class fields
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Handle<Class> var_type = hs.NewHandle(view_array_class->GetComponentType());
+ Handle<Class> index_type = hs.NewHandle(class_linker->FindPrimitiveClass('I'));
+ ObjPtr<mirror::Class> byte_class = class_linker->FindPrimitiveClass('B');
+ Handle<Class> byte_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &byte_class)));
+ InitializeVarHandle(bvh.Get(), var_type, byte_array_class, index_type, access_modes_bit_mask);
+ bvh->SetFieldBoolean<false>(ByteArrayViewVarHandle::NativeByteOrderOffset(), native_byte_order);
+ return bvh.Get();
+ }
+
+ static ByteBufferViewVarHandle* CreateByteBufferViewVarHandle(Thread* const self,
+ Handle<Class> view_array_class,
+ bool native_byte_order,
+ int32_t access_modes_bit_mask)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) {
+ StackHandleScope<5> hs(self);
+ Handle<ByteBufferViewVarHandle> bvh = hs.NewHandle(
+ ObjPtr<ByteBufferViewVarHandle>::DownCast(
+ ByteArrayViewVarHandle::StaticClass()->AllocObject(self)));
+ // Initialize super class fields
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Handle<Class> var_type = hs.NewHandle(view_array_class->GetComponentType());
+ Handle<Class> index_type = hs.NewHandle(class_linker->FindPrimitiveClass('I'));
+ Handle<ClassLoader> boot_class_loader;
+ Handle<Class> byte_buffer_class = hs.NewHandle(
+ class_linker->FindSystemClass(self, "Ljava/nio/ByteBuffer;"));
+ InitializeVarHandle(bvh.Get(), var_type, byte_buffer_class, index_type, access_modes_bit_mask);
+ bvh->SetFieldBoolean<false>(ByteBufferViewVarHandle::NativeByteOrderOffset(),
+ native_byte_order);
+ return bvh.Get();
+ }
+
+ static int32_t AccessModesBitMask(VarHandle::AccessMode mode) {
+ return 1 << static_cast<int32_t>(mode);
+ }
+
+ template<typename... Args>
+ static int32_t AccessModesBitMask(VarHandle::AccessMode first, Args... args) {
+ return AccessModesBitMask(first) | AccessModesBitMask(args...);
+ }
+
+ // Helper to get the VarType of a VarHandle.
+ static Class* GetVarType(VarHandle* vh) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return vh->GetVarType();
+ }
+
+ // Helper to get the CoordinateType0 of a VarHandle.
+ static Class* GetCoordinateType0(VarHandle* vh) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return vh->GetCoordinateType0();
+ }
+
+ // Helper to get the CoordinateType1 of a VarHandle.
+ static Class* GetCoordinateType1(VarHandle* vh) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return vh->GetCoordinateType1();
+ }
+
+ // Helper to get the AccessModesBitMask of a VarHandle.
+ static int32_t GetAccessModesBitMask(VarHandle* vh) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return vh->GetAccessModesBitMask();
+ }
+
+ private:
+ static void InitializeVarHandle(VarHandle* vh,
+ Handle<Class> var_type,
+ int32_t access_modes_bit_mask)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ vh->SetFieldObject<false>(VarHandle::VarTypeOffset(), var_type.Get());
+ vh->SetField32<false>(VarHandle::AccessModesBitMaskOffset(), access_modes_bit_mask);
+ }
+
+ static void InitializeVarHandle(VarHandle* vh,
+ Handle<Class> var_type,
+ Handle<Class> coordinate_type0,
+ int32_t access_modes_bit_mask)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ InitializeVarHandle(vh, var_type, access_modes_bit_mask);
+ vh->SetFieldObject<false>(VarHandle::CoordinateType0Offset(), coordinate_type0.Get());
+ }
+
+ static void InitializeVarHandle(VarHandle* vh,
+ Handle<Class> var_type,
+ Handle<Class> coordinate_type0,
+ Handle<Class> coordinate_type1,
+ int32_t access_modes_bit_mask)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ InitializeVarHandle(vh, var_type, access_modes_bit_mask);
+ vh->SetFieldObject<false>(VarHandle::CoordinateType0Offset(), coordinate_type0.Get());
+ vh->SetFieldObject<false>(VarHandle::CoordinateType1Offset(), coordinate_type1.Get());
+ }
+};
+
+// Convenience method for constructing MethodType instances from
+// well-formed method descriptors.
+static MethodType* MethodTypeOf(const std::string& method_descriptor) {
+ std::vector<std::string> descriptors;
+
+ auto it = method_descriptor.cbegin();
+ if (*it++ != '(') {
+ LOG(FATAL) << "Bad descriptor: " << method_descriptor;
+ }
+
+ bool returnValueSeen = false;
+ const char* prefix = "";
+ for (; it != method_descriptor.cend() && !returnValueSeen; ++it) {
+ switch (*it) {
+ case ')':
+ descriptors.push_back(std::string(++it, method_descriptor.cend()));
+ returnValueSeen = true;
+ break;
+ case '[':
+ prefix = "[";
+ break;
+ case 'Z':
+ case 'B':
+ case 'C':
+ case 'S':
+ case 'I':
+ case 'J':
+ case 'F':
+ case 'D':
+ descriptors.push_back(prefix + std::string(it, it + 1));
+ prefix = "";
+ break;
+ case 'L': {
+ auto last = it + 1;
+ while (*last != ';') {
+ ++last;
+ }
+ descriptors.push_back(prefix + std::string(it, last + 1));
+ prefix = "";
+ it = last;
+ break;
+ }
+ default:
+ LOG(FATAL) << "Bad descriptor: " << method_descriptor;
+ }
+ }
+
+ Runtime* const runtime = Runtime::Current();
+ ClassLinker* const class_linker = runtime->GetClassLinker();
+ Thread* const self = Thread::Current();
+
+ ScopedObjectAccess soa(self);
+ StackHandleScope<3> hs(self);
+ int ptypes_count = static_cast<int>(descriptors.size()) - 1;
+ ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass();
+ ObjPtr<mirror::Class> array_of_class = class_linker->FindArrayClass(self, &class_type);
+ Handle<ObjectArray<Class>> ptypes = hs.NewHandle(
+ ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, ptypes_count));
+ Handle<mirror::ClassLoader> boot_class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
+ for (int i = 0; i < ptypes_count; ++i) {
+ ptypes->Set(i, class_linker->FindClass(self, descriptors[i].c_str(), boot_class_loader));
+ }
+ Handle<Class> rtype =
+ hs.NewHandle(class_linker->FindClass(self, descriptors.back().c_str(), boot_class_loader));
+ return MethodType::Create(self, rtype, ptypes);
+}
+
+TEST_F(VarHandleTest, InstanceFieldVarHandle) {
+ Thread * const self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ ObjPtr<Object> i = BoxPrimitive(Primitive::kPrimInt, JValue::FromPrimitive<int32_t>(37));
+ ArtField* value = mirror::Class::FindField(self, i->GetClass(), "value", "I");
+ int32_t mask = AccessModesBitMask(VarHandle::AccessMode::kGet,
+ VarHandle::AccessMode::kGetAndSet,
+ VarHandle::AccessMode::kGetAndBitwiseXor);
+ StackHandleScope<1> hs(self);
+ Handle<mirror::FieldVarHandle> fvh(hs.NewHandle(CreateFieldVarHandle(self, value, mask)));
+ EXPECT_FALSE(fvh.IsNull());
+ EXPECT_EQ(value, fvh->GetField());
+
+ // Check access modes
+ EXPECT_TRUE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGet));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kSet));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetVolatile));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kSetVolatile));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kSetRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetOpaque));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kSetOpaque));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndSet));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchange));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchangeAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchangeRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetPlain));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSet));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetRelease));
+ EXPECT_TRUE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSet));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSetAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSetRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAdd));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAddAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAddRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOr));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOrRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOrAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAnd));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAndRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAndAcquire));
+ EXPECT_TRUE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXor));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXorRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXorAcquire));
+
+ // Check compatibility - "Get" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)I")));
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)V")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ }
+
+ // Check compatibility - "Set" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)V")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)V")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ }
+
+ // Check compatibility - "CompareAndSet" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode,
+ MethodTypeOf("(Ljava/lang/Integer;II)I")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ }
+
+ // Check compatibility - "CompareAndExchange" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)I")));
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)V")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ }
+
+ // Check compatibility - "GetAndUpdate" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)I")));
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)V")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ }
+
+ // Check synthesized method types match expected forms.
+ {
+ MethodType* get = MethodTypeOf("(Ljava/lang/Integer;)I");
+ MethodType* set = MethodTypeOf("(Ljava/lang/Integer;I)V");
+ MethodType* compareAndSet = MethodTypeOf("(Ljava/lang/Integer;II)Z");
+ MethodType* compareAndExchange = MethodTypeOf("(Ljava/lang/Integer;II)I");
+ MethodType* getAndUpdate = MethodTypeOf("(Ljava/lang/Integer;I)I");
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGet)->IsExactMatch(get));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSet)->IsExactMatch(set));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetVolatile)->IsExactMatch(get));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetVolatile)->IsExactMatch(set));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAcquire)->IsExactMatch(get));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetRelease)->IsExactMatch(set));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetOpaque)->IsExactMatch(get));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetOpaque)->IsExactMatch(set));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndSet)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchange)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchangeAcquire)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchangeRelease)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetPlain)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSet)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetAcquire)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetRelease)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSet)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSetAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSetRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAdd)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAddAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAddRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOr)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOrRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOrAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAnd)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAndRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAndAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXor)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXorRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXorAcquire)->IsExactMatch(getAndUpdate));
+ }
+}
+
+TEST_F(VarHandleTest, StaticFieldVarHandle) {
+ Thread * const self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ ObjPtr<Object> i = BoxPrimitive(Primitive::kPrimInt, JValue::FromPrimitive<int32_t>(37));
+ ArtField* value = mirror::Class::FindField(self, i->GetClass(), "MIN_VALUE", "I");
+ int32_t mask = AccessModesBitMask(VarHandle::AccessMode::kSet,
+ VarHandle::AccessMode::kGetOpaque,
+ VarHandle::AccessMode::kGetAndBitwiseAndRelease);
+ StackHandleScope<1> hs(self);
+ Handle<mirror::FieldVarHandle> fvh(hs.NewHandle(CreateFieldVarHandle(self, value, mask)));
+ EXPECT_FALSE(fvh.IsNull());
+ EXPECT_EQ(value, fvh->GetField());
+
+ // Check access modes
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGet));
+ EXPECT_TRUE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kSet));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetVolatile));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kSetVolatile));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kSetRelease));
+ EXPECT_TRUE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetOpaque));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kSetOpaque));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndSet));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchange));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchangeAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchangeRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetPlain));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSet));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSet));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSetAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSetRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAdd));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAddAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAddRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOr));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOrRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOrAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAnd));
+ EXPECT_TRUE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAndRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAndAcquire));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXor));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXorRelease));
+ EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXorAcquire));
+
+ // Check compatibility - "Get" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()I")));
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()V")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ }
+
+ // Check compatibility - "Set" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)V")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()V")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(F)V")));
+ }
+
+ // Check compatibility - "CompareAndSet" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode,
+ MethodTypeOf("(II)Ljava/lang/String;")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ }
+
+ // Check compatibility - "CompareAndExchange" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)I")));
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(ID)I")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)D")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ }
+
+ // Check compatibility - "GetAndUpdate" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)I")));
+ EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)V")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)Z")));
+ EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ }
+
+ // Check synthesized method types match expected forms.
+ {
+ MethodType* get = MethodTypeOf("()I");
+ MethodType* set = MethodTypeOf("(I)V");
+ MethodType* compareAndSet = MethodTypeOf("(II)Z");
+ MethodType* compareAndExchange = MethodTypeOf("(II)I");
+ MethodType* getAndUpdate = MethodTypeOf("(I)I");
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGet)->IsExactMatch(get));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSet)->IsExactMatch(set));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetVolatile)->IsExactMatch(get));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetVolatile)->IsExactMatch(set));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAcquire)->IsExactMatch(get));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetRelease)->IsExactMatch(set));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetOpaque)->IsExactMatch(get));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetOpaque)->IsExactMatch(set));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndSet)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchange)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchangeAcquire)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchangeRelease)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetPlain)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSet)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetAcquire)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetRelease)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSet)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSetAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSetRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAdd)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAddAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAddRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOr)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOrRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOrAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAnd)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAndRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAndAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXor)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXorRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(fvh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXorAcquire)->IsExactMatch(getAndUpdate));
+ }
+}
+
+TEST_F(VarHandleTest, ArrayElementVarHandle) {
+ Thread * const self = Thread::Current();
+ ScopedObjectAccess soa(self);
+ StackHandleScope<2> hs(self);
+
+ int32_t mask = AccessModesBitMask(VarHandle::AccessMode::kGet,
+ VarHandle::AccessMode::kSet,
+ VarHandle::AccessMode::kGetVolatile,
+ VarHandle::AccessMode::kSetVolatile,
+ VarHandle::AccessMode::kGetAcquire,
+ VarHandle::AccessMode::kSetRelease,
+ VarHandle::AccessMode::kGetOpaque,
+ VarHandle::AccessMode::kSetOpaque,
+ VarHandle::AccessMode::kCompareAndSet,
+ VarHandle::AccessMode::kCompareAndExchange,
+ VarHandle::AccessMode::kCompareAndExchangeAcquire,
+ VarHandle::AccessMode::kCompareAndExchangeRelease,
+ VarHandle::AccessMode::kWeakCompareAndSetPlain,
+ VarHandle::AccessMode::kWeakCompareAndSet,
+ VarHandle::AccessMode::kWeakCompareAndSetAcquire,
+ VarHandle::AccessMode::kWeakCompareAndSetRelease,
+ VarHandle::AccessMode::kGetAndSet,
+ VarHandle::AccessMode::kGetAndSetAcquire,
+ VarHandle::AccessMode::kGetAndSetRelease,
+ VarHandle::AccessMode::kGetAndAdd,
+ VarHandle::AccessMode::kGetAndAddAcquire,
+ VarHandle::AccessMode::kGetAndAddRelease,
+ VarHandle::AccessMode::kGetAndBitwiseOr,
+ VarHandle::AccessMode::kGetAndBitwiseOrRelease,
+ VarHandle::AccessMode::kGetAndBitwiseOrAcquire,
+ VarHandle::AccessMode::kGetAndBitwiseAnd,
+ VarHandle::AccessMode::kGetAndBitwiseAndRelease,
+ VarHandle::AccessMode::kGetAndBitwiseAndAcquire,
+ VarHandle::AccessMode::kGetAndBitwiseXor,
+ VarHandle::AccessMode::kGetAndBitwiseXorRelease,
+ VarHandle::AccessMode::kGetAndBitwiseXorAcquire);
+
+ ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Handle<Class> string_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &string_class)));
+ Handle<mirror::ArrayElementVarHandle> vh(hs.NewHandle(CreateArrayElementVarHandle(self, string_array_class, mask)));
+ EXPECT_FALSE(vh.IsNull());
+
+ // Check access modes
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGet));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSet));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetVolatile));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSetVolatile));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSetRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetOpaque));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSetOpaque));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndSet));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchange));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchangeAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchangeRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetPlain));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSet));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSet));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSetAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSetRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAdd));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAddAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAddRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOr));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOrRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOrAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAnd));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAndRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAndAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXor));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXorRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXorAcquire));
+
+ // Check compatibility - "Get" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Ljava/lang/String;")));
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;Ljava/lang/String;)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ }
+
+ // Check compatibility - "Set" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ }
+
+ // Check compatibility - "CompareAndSet" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
+ EXPECT_TRUE(
+ vh->IsMethodTypeCompatible(
+ access_mode,
+ MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode,
+ MethodTypeOf("([Ljava/lang/String;III)I")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ }
+
+ // Check compatibility - "CompareAndExchange" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;")));
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;II)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ }
+
+ // Check compatibility - "GetAndUpdate" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;")));
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ }
+
+ // Check synthesized method types match expected forms.
+ {
+ MethodType* get = MethodTypeOf("([Ljava/lang/String;I)Ljava/lang/String;");
+ MethodType* set = MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)V");
+ MethodType* compareAndSet = MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Z");
+ MethodType* compareAndExchange = MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+ MethodType* getAndUpdate = MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;");
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGet)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSet)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetVolatile)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetVolatile)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAcquire)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetRelease)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetOpaque)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetOpaque)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndSet)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchange)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchangeAcquire)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchangeRelease)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetPlain)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSet)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetAcquire)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetRelease)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSet)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSetAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSetRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAdd)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAddAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAddRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOr)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOrRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOrAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAnd)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAndRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAndAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXor)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXorRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXorAcquire)->IsExactMatch(getAndUpdate));
+ }
+}
+
+TEST_F(VarHandleTest, ByteArrayViewVarHandle) {
+ Thread * const self = Thread::Current();
+ ScopedObjectAccess soa(self);
+ StackHandleScope<2> hs(self);
+
+ int32_t mask = AccessModesBitMask(VarHandle::AccessMode::kGet,
+ VarHandle::AccessMode::kGetVolatile,
+ VarHandle::AccessMode::kGetAcquire,
+ VarHandle::AccessMode::kGetOpaque,
+ VarHandle::AccessMode::kCompareAndSet,
+ VarHandle::AccessMode::kCompareAndExchangeAcquire,
+ VarHandle::AccessMode::kWeakCompareAndSetPlain,
+ VarHandle::AccessMode::kWeakCompareAndSetAcquire,
+ VarHandle::AccessMode::kGetAndSet,
+ VarHandle::AccessMode::kGetAndSetRelease,
+ VarHandle::AccessMode::kGetAndAddAcquire,
+ VarHandle::AccessMode::kGetAndBitwiseOr,
+ VarHandle::AccessMode::kGetAndBitwiseOrAcquire,
+ VarHandle::AccessMode::kGetAndBitwiseAndRelease,
+ VarHandle::AccessMode::kGetAndBitwiseXor,
+ VarHandle::AccessMode::kGetAndBitwiseXorAcquire);
+
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ObjPtr<mirror::Class> char_class = class_linker->FindPrimitiveClass('C');
+ Handle<Class> char_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &char_class)));
+ const bool native_byte_order = true;
+ Handle<mirror::ByteArrayViewVarHandle> vh(hs.NewHandle(CreateByteArrayViewVarHandle(self, char_array_class, native_byte_order, mask)));
+ EXPECT_FALSE(vh.IsNull());
+ EXPECT_EQ(native_byte_order, vh->GetNativeByteOrder());
+
+ // Check access modes
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGet));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSet));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetVolatile));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSetVolatile));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAcquire));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSetRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetOpaque));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSetOpaque));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndSet));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchange));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchangeAcquire));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchangeRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetPlain));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSet));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetAcquire));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSet));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSetAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSetRelease));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAdd));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAddAcquire));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAddRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOr));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOrRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOrAcquire));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAnd));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAndRelease));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAndAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXor));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXorRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXorAcquire));
+
+ // Check compatibility - "Get" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)C")));
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BC)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ }
+
+ // Check compatibility - "Set" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ }
+
+ // Check compatibility - "CompareAndSet" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
+ EXPECT_TRUE(
+ vh->IsMethodTypeCompatible(
+ access_mode,
+ MethodTypeOf("([BICC)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode,
+ MethodTypeOf("([BIII)I")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ }
+
+ // Check compatibility - "CompareAndExchange" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BICC)C")));
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BICC)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BII)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ }
+
+ // Check compatibility - "GetAndUpdate" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)C")));
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ }
+
+ // Check synthesized method types match expected forms.
+ {
+ MethodType* get = MethodTypeOf("([BI)C");
+ MethodType* set = MethodTypeOf("([BIC)V");
+ MethodType* compareAndSet = MethodTypeOf("([BICC)Z");
+ MethodType* compareAndExchange = MethodTypeOf("([BICC)C");
+ MethodType* getAndUpdate = MethodTypeOf("([BIC)C");
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGet)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSet)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetVolatile)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetVolatile)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAcquire)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetRelease)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetOpaque)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetOpaque)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndSet)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchange)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchangeAcquire)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchangeRelease)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetPlain)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSet)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetAcquire)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetRelease)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSet)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSetAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSetRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAdd)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAddAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAddRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOr)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOrRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOrAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAnd)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAndRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAndAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXor)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXorRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXorAcquire)->IsExactMatch(getAndUpdate));
+ }
+}
+
+TEST_F(VarHandleTest, ByteBufferViewVarHandle) {
+ Thread * const self = Thread::Current();
+ ScopedObjectAccess soa(self);
+ StackHandleScope<2> hs(self);
+
+ int32_t mask = AccessModesBitMask(VarHandle::AccessMode::kGet,
+ VarHandle::AccessMode::kGetVolatile,
+ VarHandle::AccessMode::kGetAcquire,
+ VarHandle::AccessMode::kGetOpaque,
+ VarHandle::AccessMode::kCompareAndSet,
+ VarHandle::AccessMode::kCompareAndExchangeAcquire,
+ VarHandle::AccessMode::kWeakCompareAndSetPlain,
+ VarHandle::AccessMode::kWeakCompareAndSetAcquire,
+ VarHandle::AccessMode::kGetAndSet,
+ VarHandle::AccessMode::kGetAndSetRelease,
+ VarHandle::AccessMode::kGetAndAddAcquire,
+ VarHandle::AccessMode::kGetAndBitwiseOr,
+ VarHandle::AccessMode::kGetAndBitwiseOrAcquire,
+ VarHandle::AccessMode::kGetAndBitwiseAndRelease,
+ VarHandle::AccessMode::kGetAndBitwiseXor,
+ VarHandle::AccessMode::kGetAndBitwiseXorAcquire);
+
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ObjPtr<mirror::Class> double_class = class_linker->FindPrimitiveClass('D');
+ Handle<Class> double_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &double_class)));
+ const bool native_byte_order = false;
+ Handle<mirror::ByteBufferViewVarHandle> vh(hs.NewHandle(CreateByteBufferViewVarHandle(self, double_array_class, native_byte_order, mask)));
+ EXPECT_FALSE(vh.IsNull());
+ EXPECT_EQ(native_byte_order, vh->GetNativeByteOrder());
+
+ // Check access modes
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGet));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSet));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetVolatile));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSetVolatile));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAcquire));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSetRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetOpaque));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kSetOpaque));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndSet));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchange));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchangeAcquire));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kCompareAndExchangeRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetPlain));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSet));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetAcquire));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kWeakCompareAndSetRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSet));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSetAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndSetRelease));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAdd));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAddAcquire));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndAddRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOr));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOrRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseOrAcquire));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAnd));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAndRelease));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseAndAcquire));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXor));
+ EXPECT_FALSE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXorRelease));
+ EXPECT_TRUE(vh->IsAccessModeSupported(VarHandle::AccessMode::kGetAndBitwiseXorAcquire));
+
+ // Check compatibility - "Get" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)D")));
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;D)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z")));
+ }
+
+ // Check compatibility - "Set" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ }
+
+ // Check compatibility - "CompareAndSet" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet;
+ EXPECT_TRUE(
+ vh->IsMethodTypeCompatible(
+ access_mode,
+ MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode,
+ MethodTypeOf("(Ljava/nio/ByteBuffer;IDI)D")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V")));
+ }
+
+ // Check compatibility - "CompareAndExchange" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)D")));
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;II)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V")));
+ }
+
+ // Check compatibility - "GetAndUpdate" pattern
+ {
+ const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd;
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)D")));
+ EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)V")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)Z")));
+ EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V")));
+ }
+
+ // Check synthesized method types match expected forms.
+ {
+ MethodType* get = MethodTypeOf("(Ljava/nio/ByteBuffer;I)D");
+ MethodType* set = MethodTypeOf("(Ljava/nio/ByteBuffer;ID)V");
+ MethodType* compareAndSet = MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)Z");
+ MethodType* compareAndExchange = MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)D");
+ MethodType* getAndUpdate = MethodTypeOf("(Ljava/nio/ByteBuffer;ID)D");
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGet)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSet)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetVolatile)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetVolatile)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAcquire)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetRelease)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetOpaque)->IsExactMatch(get));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kSetOpaque)->IsExactMatch(set));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndSet)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchange)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchangeAcquire)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kCompareAndExchangeRelease)->IsExactMatch(compareAndExchange));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetPlain)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSet)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetAcquire)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kWeakCompareAndSetRelease)->IsExactMatch(compareAndSet));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSet)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSetAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndSetRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAdd)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAddAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndAddRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOr)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOrRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseOrAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAnd)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAndRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseAndAcquire)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXor)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXorRelease)->IsExactMatch(getAndUpdate));
+ EXPECT_TRUE(vh->GetMethodTypeForAccessMode(self, VarHandle::AccessMode::kGetAndBitwiseXorAcquire)->IsExactMatch(getAndUpdate));
+ }
+}
+
+} // namespace mirror
+} // namespace art