diff options
| -rw-r--r-- | runtime/Android.bp | 2 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 60 | ||||
| -rw-r--r-- | runtime/class_linker.h | 5 | ||||
| -rw-r--r-- | runtime/class_linker_test.cc | 38 | ||||
| -rw-r--r-- | runtime/mirror/var_handle.cc | 399 | ||||
| -rw-r--r-- | runtime/mirror/var_handle.h | 255 | ||||
| -rw-r--r-- | runtime/mirror/var_handle_test.cc | 991 |
7 files changed, 1743 insertions, 7 deletions
diff --git a/runtime/Android.bp b/runtime/Android.bp index afc7d27551..ff5ae9f5f7 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -153,6 +153,7 @@ cc_defaults { "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 @@ art_cc_test { "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 b199933ae4..5435c1145b 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 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b 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 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b 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 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { 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 @@ ClassLinker::~ClassLinker() { 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 @@ const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) { "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 eba202228c..2d9ec5a440 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -120,6 +120,11 @@ class ClassLinker { 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 3e92317682..4d9282654a 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 CallSiteOffsets : public CheckOffsets<mirror::CallSite> { } }; +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 @@ TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) { 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 0000000000..e7eac1a5ab --- /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 0000000000..a2a5d8c9ff --- /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 0000000000..0e1c994bf0 --- /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 |