ART: Interpreter support for VarHandle accessors

Add support for invoking VarHandle accessors in the interpreter and
forces code with VarHandles accessor invocations to use the interpreter.

Bug: 65872996
Test: art/test/run-test --host 712
Change-Id: I9ee3ad6aef6a3bc73d90cec0a8e023e5db42b7a2
diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc
index 5757992..5f00c6e 100644
--- a/runtime/mirror/emulated_stack_frame.cc
+++ b/runtime/mirror/emulated_stack_frame.cc
@@ -183,7 +183,7 @@
   }
 
   // Step 4 : Perform argument conversions (if required).
-  ShadowFrameGetter getter(operands, caller_frame);
+  ShadowFrameGetter getter(caller_frame, operands);
   EmulatedStackFrameAccessor setter(references, stack_frame, stack_frame->GetLength());
   if (!PerformConversions<ShadowFrameGetter, EmulatedStackFrameAccessor>(
           self, caller_type, callee_type, &getter, &setter, num_method_params)) {
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 6e2a07c..6c1cb73 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -935,6 +935,195 @@
   return success;
 }
 
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline ObjPtr<Object> Object::CompareAndExchangeFieldObject(MemberOffset field_offset,
+                                                            ObjPtr<Object> old_value,
+                                                            ObjPtr<Object> new_value) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  if (kVerifyFlags & kVerifyWrites) {
+    VerifyObject(new_value);
+  }
+  if (kVerifyFlags & kVerifyReads) {
+    VerifyObject(old_value);
+  }
+  uint32_t old_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(old_value));
+  uint32_t new_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(new_value));
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+  Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
+  bool success = atomic_addr->CompareAndExchangeStrongSequentiallyConsistent(&old_ref, new_ref);
+  ObjPtr<Object> witness_value(PtrCompression<kPoisonHeapReferences, Object>::Decompress(old_ref));
+  if (kIsDebugBuild) {
+    // Ensure caller has done read barrier on the reference field so it's in the to-space.
+    ReadBarrier::AssertToSpaceInvariant(witness_value.Ptr());
+  }
+  if (kTransactionActive && success) {
+    Runtime::Current()->RecordWriteFieldReference(this, field_offset, witness_value, true);
+  }
+  if (kVerifyFlags & kVerifyReads) {
+    VerifyObject(witness_value);
+  }
+  return witness_value;
+}
+
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline ObjPtr<Object> Object::ExchangeFieldObject(MemberOffset field_offset,
+                                                  ObjPtr<Object> new_value) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  if (kVerifyFlags & kVerifyWrites) {
+    VerifyObject(new_value);
+  }
+  uint32_t new_ref(PtrCompression<kPoisonHeapReferences, Object>::Compress(new_value));
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+  Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr);
+  uint32_t old_ref = atomic_addr->ExchangeSequentiallyConsistent(new_ref);
+  ObjPtr<Object> old_value(PtrCompression<kPoisonHeapReferences, Object>::Decompress(old_ref));
+  if (kIsDebugBuild) {
+    // Ensure caller has done read barrier on the reference field so it's in the to-space.
+    ReadBarrier::AssertToSpaceInvariant(old_value.Ptr());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true);
+  }
+  if (kVerifyFlags & kVerifyReads) {
+    VerifyObject(old_value);
+  }
+  return old_value;
+}
+
+template<typename T, VerifyObjectFlags kVerifyFlags>
+inline void Object::GetPrimitiveFieldViaAccessor(MemberOffset field_offset, Accessor<T>* accessor) {
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+  T* addr = reinterpret_cast<T*>(raw_addr);
+  accessor->Access(addr);
+}
+
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline void Object::UpdateFieldBooleanViaAccessor(MemberOffset field_offset,
+                                                  Accessor<uint8_t>* accessor) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    static const bool kIsVolatile = true;
+    uint8_t old_value = GetFieldBoolean<kVerifyFlags, kIsVolatile>(field_offset);
+    Runtime::Current()->RecordWriteFieldBoolean(this, field_offset, old_value, kIsVolatile);
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+  uint8_t* addr = raw_addr;
+  accessor->Access(addr);
+}
+
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline void Object::UpdateFieldByteViaAccessor(MemberOffset field_offset,
+                                               Accessor<int8_t>* accessor) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    static const bool kIsVolatile = true;
+    int8_t old_value = GetFieldByte<kVerifyFlags, kIsVolatile>(field_offset);
+    Runtime::Current()->RecordWriteFieldByte(this, field_offset, old_value, kIsVolatile);
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+  int8_t* addr = reinterpret_cast<int8_t*>(raw_addr);
+  accessor->Access(addr);
+}
+
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline void Object::UpdateFieldCharViaAccessor(MemberOffset field_offset,
+                                               Accessor<uint16_t>* accessor) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    static const bool kIsVolatile = true;
+    uint16_t old_value = GetFieldChar<kVerifyFlags, kIsVolatile>(field_offset);
+    Runtime::Current()->RecordWriteFieldChar(this, field_offset, old_value, kIsVolatile);
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+  uint16_t* addr = reinterpret_cast<uint16_t*>(raw_addr);
+  accessor->Access(addr);
+}
+
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline void Object::UpdateFieldShortViaAccessor(MemberOffset field_offset,
+                                                Accessor<int16_t>* accessor) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    static const bool kIsVolatile = true;
+    int16_t old_value = GetFieldShort<kVerifyFlags, kIsVolatile>(field_offset);
+    Runtime::Current()->RecordWriteFieldShort(this, field_offset, old_value, kIsVolatile);
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+  int16_t* addr = reinterpret_cast<int16_t*>(raw_addr);
+  accessor->Access(addr);
+}
+
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline void Object::UpdateField32ViaAccessor(MemberOffset field_offset,
+                                             Accessor<int32_t>* accessor) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    static const bool kIsVolatile = true;
+    int32_t old_value = GetField32<kVerifyFlags, kIsVolatile>(field_offset);
+    Runtime::Current()->RecordWriteField32(this, field_offset, old_value, kIsVolatile);
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+  int32_t* addr = reinterpret_cast<int32_t*>(raw_addr);
+  accessor->Access(addr);
+}
+
+template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags>
+inline void Object::UpdateField64ViaAccessor(MemberOffset field_offset,
+                                             Accessor<int64_t>* accessor) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    static const bool kIsVolatile = true;
+    int64_t old_value = GetField64<kVerifyFlags, kIsVolatile>(field_offset);
+    Runtime::Current()->RecordWriteField64(this, field_offset, old_value, kIsVolatile);
+  }
+  if (kVerifyFlags & kVerifyThis) {
+    VerifyObject(this);
+  }
+  uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value();
+  int64_t* addr = reinterpret_cast<int64_t*>(raw_addr);
+  accessor->Access(addr);
+}
+
 template<bool kIsStatic,
          VerifyObjectFlags kVerifyFlags,
          ReadBarrierOption kReadBarrierOption,
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 25b86a5..816ac69 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -347,6 +347,21 @@
                                                                      ObjPtr<Object> old_value,
                                                                      ObjPtr<Object> new_value)
       REQUIRES_SHARED(Locks::mutator_lock_);
+
+  template<bool kTransactionActive,
+           bool kCheckTransaction = true,
+           VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  ObjPtr<Object> CompareAndExchangeFieldObject(MemberOffset field_offset,
+                                               ObjPtr<Object> old_value,
+                                               ObjPtr<Object> new_value)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  template<bool kTransactionActive,
+           bool kCheckTransaction = true,
+           VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  ObjPtr<Object> ExchangeFieldObject(MemberOffset field_offset, ObjPtr<Object> new_value)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   template<bool kTransactionActive,
            bool kCheckTransaction = true,
            VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -592,6 +607,52 @@
           field_offset, reinterpret_cast64<int64_t>(new_value));
     }
   }
+
+  // Base class for accessors used to describe accesses performed by VarHandle methods.
+  template <typename T>
+  class Accessor {
+   public:
+    virtual ~Accessor() {
+      static_assert(std::is_arithmetic<T>::value, "unsupported type");
+    }
+    virtual void Access(T* field_address) = 0;
+  };
+
+  // Getter method that exposes the raw address of a primitive value-type field to an Accessor
+  // instance. This are used by VarHandle accessor methods to read fields with a wider range of
+  // memory orderings than usually required.
+  template<typename T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  void GetPrimitiveFieldViaAccessor(MemberOffset field_offset, Accessor<T>* accessor)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Update methods that expose the raw address of a primitive value-type to an Accessor instance
+  // that will attempt to update the field. These are used by VarHandle accessor methods to
+  // atomically update fields with a wider range of memory orderings than usually required.
+  template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  void UpdateFieldBooleanViaAccessor(MemberOffset field_offset, Accessor<uint8_t>* accessor)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  void UpdateFieldByteViaAccessor(MemberOffset field_offset, Accessor<int8_t>* accessor)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  void UpdateFieldCharViaAccessor(MemberOffset field_offset, Accessor<uint16_t>* accessor)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  void UpdateFieldShortViaAccessor(MemberOffset field_offset, Accessor<int16_t>* accessor)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  void UpdateField32ViaAccessor(MemberOffset field_offset, Accessor<int32_t>* accessor)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  template<bool kTransactionActive, bool kCheckTransaction = true,
+      VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  void UpdateField64ViaAccessor(MemberOffset field_offset, Accessor<int64_t>* accessor)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   // TODO fix thread safety analysis broken by the use of template. This should be
   // REQUIRES_SHARED(Locks::mutator_lock_).
   template <bool kVisitNativeRoots = true,
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index 3f4a28c..85d06f0 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -16,14 +16,23 @@
 
 #include "var_handle.h"
 
+#include "array-inl.h"
+#include "art_field-inl.h"
 #include "class-inl.h"
 #include "class_linker.h"
 #include "gc_root-inl.h"
+#include "jni_internal.h"
+#include "jvalue-inl.h"
+#include "method_handles.h"
 #include "method_type.h"
+#include "well_known_classes.h"
 
 namespace art {
 namespace mirror {
 
+static constexpr bool kTransactionActive = true;
+static constexpr bool kTransactionInactive = !kTransactionActive;
+
 namespace {
 
 struct VarHandleAccessorToAccessModeEntry {
@@ -158,32 +167,64 @@
   }
 }
 
-// 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++;
-    }
-  }
-
+int32_t GetNumberOfVarTypeParameters(AccessModeTemplate access_mode_template) {
   switch (access_mode_template) {
     case AccessModeTemplate::kGet:
-      return index;
+      return 0;
     case AccessModeTemplate::kSet:
     case AccessModeTemplate::kGetAndUpdate:
-      return index + 1;
+      return 1;
     case AccessModeTemplate::kCompareAndSet:
     case AccessModeTemplate::kCompareAndExchange:
-      return index + 2;
+      return 2;
   }
   UNREACHABLE();
 }
 
+// Returns the number of parameters associated with an
+// AccessModeTemplate and the supplied coordinate types.
+int32_t GetNumberOfParameters(AccessModeTemplate access_mode_template,
+                              ObjPtr<Class> coordinateType0,
+                              ObjPtr<Class> coordinateType1) {
+  int32_t count = 0;
+  if (!coordinateType0.IsNull()) {
+    count++;
+    if (!coordinateType1.IsNull()) {
+      count++;
+    }
+  }
+  return count + GetNumberOfVarTypeParameters(access_mode_template);
+}
+
+void ThrowNullPointerExceptionForCoordinate() REQUIRES_SHARED(Locks::mutator_lock_) {
+  ThrowNullPointerException("Attempt to access memory on a null object");
+}
+
+bool CheckElementIndex(Primitive::Type type,
+                       int32_t relative_index,
+                       int32_t start,
+                       int32_t limit) REQUIRES_SHARED(Locks::mutator_lock_) {
+  int64_t index = start + relative_index;
+  int64_t max_index = limit - Primitive::ComponentSize(type);
+  if (index < start || index > max_index) {
+    ThrowIndexOutOfBoundsException(index, limit - start);
+    return false;
+  }
+  return true;
+}
+
+bool CheckElementIndex(Primitive::Type type, int32_t index, int32_t range_limit)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  return CheckElementIndex(type, index, 0, range_limit);
+}
+
+// Returns true if access_mode only entails a memory read. False if
+// access_mode may write to memory.
+bool IsReadOnlyAccessMode(VarHandle::AccessMode access_mode) {
+  AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode);
+  return access_mode_template == AccessModeTemplate::kGet;
+}
+
 // 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
@@ -248,6 +289,1123 @@
   return ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, count);
 }
 
+// Method to insert a read barrier for accessors to reference fields.
+inline void ReadBarrierForVarHandleAccess(ObjPtr<Object> obj, MemberOffset field_offset)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (kUseReadBarrier) {
+    // We need to ensure that the reference stored in the field is a to-space one before attempting
+    // the CompareAndSet/CompareAndExchange/Exchange operation otherwise it will fail incorrectly
+    // if obj is in the process of being moved.
+    uint8_t* raw_field_addr = reinterpret_cast<uint8_t*>(obj.Ptr()) + field_offset.SizeValue();
+    auto field_addr = reinterpret_cast<mirror::HeapReference<mirror::Object>*>(raw_field_addr);
+    // Note that the read barrier load does NOT need to be volatile.
+    static constexpr bool kIsVolatile = false;
+    static constexpr bool kAlwaysUpdateField = true;
+    ReadBarrier::Barrier<mirror::Object, kIsVolatile, kWithReadBarrier, kAlwaysUpdateField>(
+        obj.Ptr(),
+        MemberOffset(field_offset),
+        field_addr);
+  }
+}
+
+inline MemberOffset GetMemberOffset(jfieldID field_id) REQUIRES_SHARED(Locks::mutator_lock_) {
+  ArtField* const field = jni::DecodeArtField(field_id);
+  return field->GetOffset();
+}
+
+//
+// Helper methods for storing results from atomic operations into
+// JValue instances.
+//
+
+inline void StoreResult(uint8_t value, JValue* result) {
+  result->SetZ(value);
+}
+
+inline void StoreResult(int8_t value, JValue* result) {
+  result->SetB(value);
+}
+
+inline void StoreResult(uint16_t value, JValue* result) {
+  result->SetC(value);
+}
+
+inline void StoreResult(int16_t value, JValue* result) {
+  result->SetS(value);
+}
+
+inline void StoreResult(int32_t value, JValue* result) {
+  result->SetI(value);
+}
+
+inline void StoreResult(int64_t value, JValue* result) {
+  result->SetJ(value);
+}
+
+inline void StoreResult(float value, JValue* result) {
+  result->SetF(value);
+}
+
+inline void StoreResult(double value, JValue* result) {
+  result->SetD(value);
+}
+
+inline void StoreResult(ObjPtr<Object> value, JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  result->SetL(value);
+}
+
+//
+// Helper class for byte-swapping value that has been stored in a JValue.
+//
+
+template <typename T>
+class JValueByteSwapper FINAL {
+ public:
+  static void ByteSwap(JValue* value);
+  static void MaybeByteSwap(bool byte_swap, JValue* value) {
+    if (byte_swap) {
+      ByteSwap(value);
+    }
+  }
+};
+
+template <>
+void JValueByteSwapper<uint16_t>::ByteSwap(JValue* value) {
+  value->SetC(BSWAP(value->GetC()));
+}
+
+template <>
+void JValueByteSwapper<int16_t>::ByteSwap(JValue* value) {
+  value->SetS(BSWAP(value->GetS()));
+}
+
+template <>
+void JValueByteSwapper<int32_t>::ByteSwap(JValue* value) {
+  value->SetI(BSWAP(value->GetI()));
+}
+
+template <>
+void JValueByteSwapper<int64_t>::ByteSwap(JValue* value) {
+  value->SetJ(BSWAP(value->GetJ()));
+}
+
+//
+// Accessor implementations, shared across all VarHandle types.
+//
+
+template <typename T, std::memory_order MO>
+class AtomicGetAccessor : public Object::Accessor<T> {
+ public:
+  explicit AtomicGetAccessor(JValue* result) : result_(result) {}
+
+  void Access(T* addr) OVERRIDE {
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    StoreResult(atom->load(MO), result_);
+  }
+
+ private:
+  JValue* result_;
+};
+
+template <typename T, std::memory_order MO>
+class AtomicSetAccessor : public Object::Accessor<T> {
+ public:
+  explicit AtomicSetAccessor(T new_value) : new_value_(new_value) {}
+
+  void Access(T* addr) OVERRIDE {
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    atom->store(new_value_, MO);
+  }
+
+ private:
+  T new_value_;
+};
+
+template <typename T> using GetAccessor = AtomicGetAccessor<T, std::memory_order_relaxed>;
+
+template <typename T> using SetAccessor = AtomicSetAccessor<T, std::memory_order_relaxed>;
+
+template <typename T>
+using GetVolatileAccessor = AtomicGetAccessor<T, std::memory_order_seq_cst>;
+
+template <typename T>
+using SetVolatileAccessor = AtomicSetAccessor<T, std::memory_order_seq_cst>;
+
+template <typename T, std::memory_order MOS, std::memory_order MOF>
+class AtomicStrongCompareAndSetAccessor : public Object::Accessor<T> {
+ public:
+  AtomicStrongCompareAndSetAccessor(T expected_value, T desired_value, JValue* result)
+      : expected_value_(expected_value), desired_value_(desired_value), result_(result) {}
+
+  void Access(T* addr) OVERRIDE {
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    bool success = atom->compare_exchange_strong(expected_value_, desired_value_, MOS, MOF);
+    StoreResult(success ? JNI_TRUE : JNI_FALSE, result_);
+  }
+
+ private:
+  T expected_value_;
+  T desired_value_;
+  JValue* result_;
+};
+
+template<typename T>
+using CompareAndSetAccessor =
+    AtomicStrongCompareAndSetAccessor<T, std::memory_order_seq_cst, std::memory_order_seq_cst>;
+
+template <typename T, std::memory_order MOS, std::memory_order MOF>
+class AtomicStrongCompareAndExchangeAccessor : public Object::Accessor<T> {
+ public:
+  AtomicStrongCompareAndExchangeAccessor(T expected_value, T desired_value, JValue* result)
+      : expected_value_(expected_value), desired_value_(desired_value), result_(result) {}
+
+  void Access(T* addr) OVERRIDE {
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    atom->compare_exchange_strong(expected_value_, desired_value_, MOS, MOF);
+    StoreResult(expected_value_, result_);
+  }
+
+ private:
+  T expected_value_;
+  T desired_value_;
+  JValue* result_;
+};
+
+template <typename T>
+using CompareAndExchangeAccessor =
+    AtomicStrongCompareAndExchangeAccessor<T, std::memory_order_seq_cst, std::memory_order_seq_cst>;
+
+template <typename T, std::memory_order MOS, std::memory_order MOF>
+class AtomicWeakCompareAndSetAccessor : public Object::Accessor<T> {
+ public:
+  AtomicWeakCompareAndSetAccessor(T expected_value, T desired_value, JValue* result)
+      : expected_value_(expected_value), desired_value_(desired_value), result_(result) {}
+
+  void Access(T* addr) OVERRIDE {
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    bool success = atom->compare_exchange_weak(expected_value_, desired_value_, MOS, MOF);
+    StoreResult(success ? JNI_TRUE : JNI_FALSE, result_);
+  }
+
+ private:
+  T expected_value_;
+  T desired_value_;
+  JValue* result_;
+};
+
+template <typename T>
+using WeakCompareAndSetAccessor =
+    AtomicWeakCompareAndSetAccessor<T, std::memory_order_seq_cst, std::memory_order_seq_cst>;
+
+template <typename T, std::memory_order MO>
+class AtomicGetAndSetAccessor : public Object::Accessor<T> {
+ public:
+  AtomicGetAndSetAccessor(T new_value, JValue* result) : new_value_(new_value), result_(result) {}
+
+  void Access(T* addr) OVERRIDE {
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    T old_value = atom->exchange(new_value_, MO);
+    StoreResult(old_value, result_);
+  }
+
+ private:
+  T new_value_;
+  JValue* result_;
+};
+
+template <typename T>
+using GetAndSetAccessor = AtomicGetAndSetAccessor<T, std::memory_order_seq_cst>;
+
+template <typename T, bool kIsFloat, std::memory_order MO>
+class AtomicGetAndAddOperator {
+ public:
+  static T Apply(T* addr, T addend) {
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    return atom->fetch_add(addend, MO);
+  }
+};
+
+template <typename T, std::memory_order MO>
+class AtomicGetAndAddOperator<T, /* kIsFloat */ true, MO> {
+ public:
+  static T Apply(T* addr, T addend) {
+    // c++11 does not have std::atomic<T>::fetch_and_add for floating
+    // point types, so we effect one with a compare and swap.
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    T old_value = atom->load(std::memory_order_relaxed);
+    T new_value;
+    do {
+      new_value = old_value + addend;
+    } while (!atom->compare_exchange_weak(old_value, new_value, MO, std::memory_order_relaxed));
+    return old_value;
+  }
+};
+
+template <typename T, std::memory_order MO>
+class AtomicGetAndAddAccessor : public Object::Accessor<T> {
+ public:
+  AtomicGetAndAddAccessor(T addend, JValue* result) : addend_(addend), result_(result) {}
+
+  void Access(T* addr) OVERRIDE {
+    constexpr bool kIsFloatingPoint = std::is_floating_point<T>::value;
+    T old_value = AtomicGetAndAddOperator<T, kIsFloatingPoint, MO>::Apply(addr, addend_);
+    StoreResult(old_value, result_);
+  }
+
+ private:
+  T addend_;
+  JValue* result_;
+};
+
+template <typename T>
+using GetAndAddAccessor = AtomicGetAndAddAccessor<T, std::memory_order_seq_cst>;
+
+// Accessor specifically for memory views where the caller can specify
+// the byte-ordering. Addition only works outside of the byte-swapped
+// memory view because of the direction of carries.
+template <typename T, std::memory_order MO>
+class AtomicGetAndAddWithByteSwapAccessor : public Object::Accessor<T> {
+ public:
+  AtomicGetAndAddWithByteSwapAccessor(T value, JValue* result) : value_(value), result_(result) {}
+
+  void Access(T* addr) OVERRIDE {
+    std::atomic<T>* const atom = reinterpret_cast<std::atomic<T>*>(addr);
+    T current_value = atom->load(std::memory_order_relaxed);
+    T sum;
+    do {
+      sum = BSWAP(current_value) + value_;
+      // NB current_value is a pass-by-reference argument in the call to
+      // atomic<T>::compare_exchange_weak().
+    } while (!atom->compare_exchange_weak(current_value,
+                                          BSWAP(sum),
+                                          MO,
+                                          std::memory_order_relaxed));
+    StoreResult(BSWAP(current_value), result_);
+  }
+
+ private:
+  T value_;
+  JValue* result_;
+};
+
+template <typename T>
+using GetAndAddWithByteSwapAccessor =
+    AtomicGetAndAddWithByteSwapAccessor<T, std::memory_order_seq_cst>;
+
+template <typename T, std::memory_order MO>
+class AtomicGetAndBitwiseOrAccessor : public Object::Accessor<T> {
+ public:
+  AtomicGetAndBitwiseOrAccessor(T value, JValue* result) : value_(value), result_(result) {}
+
+  void Access(T* addr) OVERRIDE {
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    T old_value = atom->fetch_or(value_, MO);
+    StoreResult(old_value, result_);
+  }
+
+ private:
+  T value_;
+  JValue* result_;
+};
+
+template <typename T>
+using GetAndBitwiseOrAccessor = AtomicGetAndBitwiseOrAccessor<T, std::memory_order_seq_cst>;
+
+template <typename T, std::memory_order MO>
+class AtomicGetAndBitwiseAndAccessor : public Object::Accessor<T> {
+ public:
+  AtomicGetAndBitwiseAndAccessor(T value, JValue* result) : value_(value), result_(result) {}
+
+  void Access(T* addr) OVERRIDE {
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    T old_value = atom->fetch_and(value_, MO);
+    StoreResult(old_value, result_);
+  }
+
+ private:
+  T value_;
+  JValue* result_;
+};
+
+template <typename T>
+using GetAndBitwiseAndAccessor =
+    AtomicGetAndBitwiseAndAccessor<T, std::memory_order_seq_cst>;
+
+template <typename T, std::memory_order MO>
+class AtomicGetAndBitwiseXorAccessor : public Object::Accessor<T> {
+ public:
+  AtomicGetAndBitwiseXorAccessor(T value, JValue* result) : value_(value), result_(result) {}
+
+  void Access(T* addr) OVERRIDE {
+    std::atomic<T>* atom = reinterpret_cast<std::atomic<T>*>(addr);
+    T old_value = atom->fetch_xor(value_, MO);
+    StoreResult(old_value, result_);
+  }
+
+ private:
+  T value_;
+  JValue* result_;
+};
+
+template <typename T>
+using GetAndBitwiseXorAccessor = AtomicGetAndBitwiseXorAccessor<T, std::memory_order_seq_cst>;
+
+//
+// Unreachable access modes.
+//
+
+NO_RETURN void UnreachableAccessMode(const char* access_mode, const char* type_name) {
+  LOG(FATAL) << "Unreachable access mode :" << access_mode << " for type " << type_name;
+  UNREACHABLE();
+}
+
+#define UNREACHABLE_ACCESS_MODE(ACCESS_MODE, TYPE)             \
+template<> void ACCESS_MODE ## Accessor<TYPE>::Access(TYPE*) { \
+  UnreachableAccessMode(#ACCESS_MODE, #TYPE);                  \
+}
+
+// The boolean primitive type is not numeric (boolean == std::uint8_t).
+UNREACHABLE_ACCESS_MODE(GetAndAdd, uint8_t)
+
+// The floating point types do not support bitwise operations.
+UNREACHABLE_ACCESS_MODE(GetAndBitwiseOr, float)
+UNREACHABLE_ACCESS_MODE(GetAndBitwiseAnd, float)
+UNREACHABLE_ACCESS_MODE(GetAndBitwiseXor, float)
+UNREACHABLE_ACCESS_MODE(GetAndBitwiseOr, double)
+UNREACHABLE_ACCESS_MODE(GetAndBitwiseAnd, double)
+UNREACHABLE_ACCESS_MODE(GetAndBitwiseXor, double)
+
+// A helper class for object field accesses for floats and
+// doubles. The object interface deals with Field32 and Field64. The
+// former is used for both integers and floats, the latter for longs
+// and doubles. This class provides the necessary coercion.
+template <typename T, typename U>
+class TypeAdaptorAccessor : public Object::Accessor<T> {
+ public:
+  explicit TypeAdaptorAccessor(Object::Accessor<U>* inner_accessor)
+      : inner_accessor_(inner_accessor) {}
+
+  void Access(T* addr) OVERRIDE {
+    static_assert(sizeof(T) == sizeof(U), "bad conversion");
+    inner_accessor_->Access(reinterpret_cast<U*>(addr));
+  }
+
+ private:
+  Object::Accessor<U>* inner_accessor_;
+};
+
+template <typename T>
+class FieldAccessViaAccessor {
+ public:
+  typedef Object::Accessor<T> Accessor;
+
+  // Apply an Accessor to get a field in an object.
+  static void Get(ObjPtr<Object> obj,
+                  MemberOffset field_offset,
+                  Accessor* accessor)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    obj->GetPrimitiveFieldViaAccessor(field_offset, accessor);
+  }
+
+  // Apply an Accessor to update a field in an object.
+  static void Update(ObjPtr<Object> obj,
+                     MemberOffset field_offset,
+                     Accessor* accessor)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+};
+
+template <>
+inline void FieldAccessViaAccessor<float>::Get(ObjPtr<Object> obj,
+                                               MemberOffset field_offset,
+                                               Accessor* accessor)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  TypeAdaptorAccessor<int32_t, float> float_to_int_accessor(accessor);
+  obj->GetPrimitiveFieldViaAccessor(field_offset, &float_to_int_accessor);
+}
+
+template <>
+inline void FieldAccessViaAccessor<double>::Get(ObjPtr<Object> obj,
+                                                MemberOffset field_offset,
+                                                Accessor* accessor)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  TypeAdaptorAccessor<int64_t, double> double_to_int_accessor(accessor);
+  obj->GetPrimitiveFieldViaAccessor(field_offset, &double_to_int_accessor);
+}
+
+template <>
+void FieldAccessViaAccessor<uint8_t>::Update(ObjPtr<Object> obj,
+                                             MemberOffset field_offset,
+                                             Accessor* accessor)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (Runtime::Current()->IsActiveTransaction()) {
+    obj->UpdateFieldBooleanViaAccessor<kTransactionActive>(field_offset, accessor);
+  } else {
+    obj->UpdateFieldBooleanViaAccessor<kTransactionInactive>(field_offset, accessor);
+  }
+}
+
+template <>
+void FieldAccessViaAccessor<int8_t>::Update(ObjPtr<Object> obj,
+                                            MemberOffset field_offset,
+                                            Accessor* accessor)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (Runtime::Current()->IsActiveTransaction()) {
+    obj->UpdateFieldByteViaAccessor<kTransactionActive>(field_offset, accessor);
+  } else {
+    obj->UpdateFieldByteViaAccessor<kTransactionInactive>(field_offset, accessor);
+  }
+}
+
+template <>
+void FieldAccessViaAccessor<uint16_t>::Update(ObjPtr<Object> obj,
+                                              MemberOffset field_offset,
+                                              Accessor* accessor)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (Runtime::Current()->IsActiveTransaction()) {
+    obj->UpdateFieldCharViaAccessor<kTransactionActive>(field_offset, accessor);
+  } else {
+    obj->UpdateFieldCharViaAccessor<kTransactionInactive>(field_offset, accessor);
+  }
+}
+
+template <>
+void FieldAccessViaAccessor<int16_t>::Update(ObjPtr<Object> obj,
+                                              MemberOffset field_offset,
+                                              Accessor* accessor)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (Runtime::Current()->IsActiveTransaction()) {
+    obj->UpdateFieldShortViaAccessor<kTransactionActive>(field_offset, accessor);
+  } else {
+    obj->UpdateFieldShortViaAccessor<kTransactionInactive>(field_offset, accessor);
+  }
+}
+
+template <>
+void FieldAccessViaAccessor<int32_t>::Update(ObjPtr<Object> obj,
+                                             MemberOffset field_offset,
+                                             Accessor* accessor)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (Runtime::Current()->IsActiveTransaction()) {
+    obj->UpdateField32ViaAccessor<kTransactionActive>(field_offset, accessor);
+  } else {
+    obj->UpdateField32ViaAccessor<kTransactionInactive>(field_offset, accessor);
+  }
+}
+
+template <>
+void FieldAccessViaAccessor<int64_t>::Update(ObjPtr<Object> obj,
+                                             MemberOffset field_offset,
+                                             Accessor* accessor)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (Runtime::Current()->IsActiveTransaction()) {
+    obj->UpdateField64ViaAccessor<kTransactionActive>(field_offset, accessor);
+  } else {
+    obj->UpdateField64ViaAccessor<kTransactionInactive>(field_offset, accessor);
+  }
+}
+
+template <>
+void FieldAccessViaAccessor<float>::Update(ObjPtr<Object> obj,
+                                           MemberOffset field_offset,
+                                           Accessor* accessor)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  TypeAdaptorAccessor<int32_t, float> float_to_int_accessor(accessor);
+  if (Runtime::Current()->IsActiveTransaction()) {
+    obj->UpdateField32ViaAccessor<kTransactionActive>(field_offset, &float_to_int_accessor);
+  } else {
+    obj->UpdateField32ViaAccessor<kTransactionInactive>(field_offset, &float_to_int_accessor);
+  }
+}
+
+template <>
+void FieldAccessViaAccessor<double>::Update(ObjPtr<Object> obj,
+                                            MemberOffset field_offset,
+                                            Accessor* accessor)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  TypeAdaptorAccessor<int64_t, double> double_to_int_accessor(accessor);
+  if (Runtime::Current()->IsActiveTransaction()) {
+    obj->UpdateField64ViaAccessor<kTransactionActive>(field_offset, &double_to_int_accessor);
+  } else {
+    obj->UpdateField64ViaAccessor<kTransactionInactive>(field_offset, &double_to_int_accessor);
+  }
+}
+
+// Helper class that gets values from a shadow frame with appropriate type coercion.
+template <typename T>
+class ValueGetter {
+ public:
+  static T Get(ShadowFrameGetter* getter) REQUIRES_SHARED(Locks::mutator_lock_) {
+    static_assert(sizeof(T) <= sizeof(uint32_t), "Bad size");
+    uint32_t raw_value = getter->Get();
+    return static_cast<T>(raw_value);
+  }
+};
+
+template <>
+int64_t ValueGetter<int64_t>::Get(ShadowFrameGetter* getter) {
+  return getter->GetLong();
+}
+
+template <>
+float ValueGetter<float>::Get(ShadowFrameGetter* getter) {
+  uint32_t raw_value = getter->Get();
+  return *reinterpret_cast<float*>(&raw_value);
+}
+
+template <>
+double ValueGetter<double>::Get(ShadowFrameGetter* getter) {
+  int64_t raw_value = getter->GetLong();
+  return *reinterpret_cast<double*>(&raw_value);
+}
+
+template <>
+ObjPtr<Object> ValueGetter<ObjPtr<Object>>::Get(ShadowFrameGetter* getter) {
+  return getter->GetReference();
+}
+
+// Class for accessing fields of Object instances
+template <typename T>
+class FieldAccessor {
+ public:
+  static bool Dispatch(VarHandle::AccessMode access_mode,
+                       ObjPtr<Object> obj,
+                       MemberOffset field_offset,
+                       ShadowFrameGetter* getter,
+                       JValue* result)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+};
+
+// Dispatch implementation for primitive fields.
+template <typename T>
+bool FieldAccessor<T>::Dispatch(VarHandle::AccessMode access_mode,
+                                ObjPtr<Object> obj,
+                                MemberOffset field_offset,
+                                ShadowFrameGetter* getter,
+                                JValue* result) {
+  switch (access_mode) {
+    case VarHandle::AccessMode::kGet: {
+      GetAccessor<T> accessor(result);
+      FieldAccessViaAccessor<T>::Get(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kSet: {
+      T new_value = ValueGetter<T>::Get(getter);
+      SetAccessor<T> accessor(new_value);
+      FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kGetAcquire:
+    case VarHandle::AccessMode::kGetOpaque:
+    case VarHandle::AccessMode::kGetVolatile: {
+      GetVolatileAccessor<T> accessor(result);
+      FieldAccessViaAccessor<T>::Get(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kSetOpaque:
+    case VarHandle::AccessMode::kSetRelease:
+    case VarHandle::AccessMode::kSetVolatile: {
+      T new_value = ValueGetter<T>::Get(getter);
+      SetVolatileAccessor<T> accessor(new_value);
+      FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kCompareAndSet: {
+      T expected_value = ValueGetter<T>::Get(getter);
+      T desired_value = ValueGetter<T>::Get(getter);
+      CompareAndSetAccessor<T> accessor(expected_value, desired_value, result);
+      FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kCompareAndExchange:
+    case VarHandle::AccessMode::kCompareAndExchangeAcquire:
+    case VarHandle::AccessMode::kCompareAndExchangeRelease: {
+      T expected_value = ValueGetter<T>::Get(getter);
+      T desired_value = ValueGetter<T>::Get(getter);
+      CompareAndExchangeAccessor<T> accessor(expected_value, desired_value, result);
+      FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kWeakCompareAndSet:
+    case VarHandle::AccessMode::kWeakCompareAndSetAcquire:
+    case VarHandle::AccessMode::kWeakCompareAndSetPlain:
+    case VarHandle::AccessMode::kWeakCompareAndSetRelease: {
+      T expected_value = ValueGetter<T>::Get(getter);
+      T desired_value = ValueGetter<T>::Get(getter);
+      WeakCompareAndSetAccessor<T> accessor(expected_value, desired_value, result);
+      FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kGetAndSet:
+    case VarHandle::AccessMode::kGetAndSetAcquire:
+    case VarHandle::AccessMode::kGetAndSetRelease: {
+      T new_value = ValueGetter<T>::Get(getter);
+      GetAndSetAccessor<T> accessor(new_value, result);
+      FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kGetAndAdd:
+    case VarHandle::AccessMode::kGetAndAddAcquire:
+    case VarHandle::AccessMode::kGetAndAddRelease: {
+      T value = ValueGetter<T>::Get(getter);
+      GetAndAddAccessor<T> accessor(value, result);
+      FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kGetAndBitwiseOr:
+    case VarHandle::AccessMode::kGetAndBitwiseOrAcquire:
+    case VarHandle::AccessMode::kGetAndBitwiseOrRelease: {
+      T value = ValueGetter<T>::Get(getter);
+      GetAndBitwiseOrAccessor<T> accessor(value, result);
+      FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kGetAndBitwiseAnd:
+    case VarHandle::AccessMode::kGetAndBitwiseAndAcquire:
+    case VarHandle::AccessMode::kGetAndBitwiseAndRelease: {
+      T value = ValueGetter<T>::Get(getter);
+      GetAndBitwiseAndAccessor<T> accessor(value, result);
+      FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor);
+      break;
+    }
+    case VarHandle::AccessMode::kGetAndBitwiseXor:
+    case VarHandle::AccessMode::kGetAndBitwiseXorAcquire:
+    case VarHandle::AccessMode::kGetAndBitwiseXorRelease: {
+      T value = ValueGetter<T>::Get(getter);
+      GetAndBitwiseXorAccessor<T> accessor(value, result);
+      FieldAccessViaAccessor<T>::Update(obj, field_offset, &accessor);
+      break;
+    }
+  }
+  return true;
+}
+
+// Dispatch implementation for reference fields.
+template <>
+bool FieldAccessor<ObjPtr<Object>>::Dispatch(VarHandle::AccessMode access_mode,
+                                             ObjPtr<Object> obj,
+                                             MemberOffset field_offset,
+                                             ShadowFrameGetter* getter,
+                                             JValue* result)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  // To keep things simple, use the minimum strongest existing
+  // field accessor for Object fields. This may be the most
+  // straightforward strategy in general for the interpreter.
+  switch (access_mode) {
+    case VarHandle::AccessMode::kGet: {
+      StoreResult(obj->GetFieldObject<Object>(field_offset), result);
+      break;
+    }
+    case VarHandle::AccessMode::kSet: {
+      ObjPtr<Object> new_value = ValueGetter<ObjPtr<Object>>::Get(getter);
+      if (Runtime::Current()->IsActiveTransaction()) {
+        obj->SetFieldObject<kTransactionActive>(field_offset, new_value);
+      } else {
+        obj->SetFieldObject<kTransactionInactive>(field_offset, new_value);
+      }
+      break;
+    }
+    case VarHandle::AccessMode::kGetAcquire:
+    case VarHandle::AccessMode::kGetOpaque:
+    case VarHandle::AccessMode::kGetVolatile: {
+      StoreResult(obj->GetFieldObjectVolatile<Object>(field_offset), result);
+      break;
+    }
+    case VarHandle::AccessMode::kSetOpaque:
+    case VarHandle::AccessMode::kSetRelease:
+    case VarHandle::AccessMode::kSetVolatile: {
+      ObjPtr<Object> new_value = ValueGetter<ObjPtr<Object>>::Get(getter);
+      if (Runtime::Current()->IsActiveTransaction()) {
+        obj->SetFieldObjectVolatile<kTransactionActive>(field_offset, new_value);
+      } else {
+        obj->SetFieldObjectVolatile<kTransactionInactive>(field_offset, new_value);
+      }
+      break;
+    }
+    case VarHandle::AccessMode::kCompareAndSet: {
+      ReadBarrierForVarHandleAccess(obj, field_offset);
+      ObjPtr<Object> expected_value = ValueGetter<ObjPtr<Object>>::Get(getter);
+      ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter);
+      bool cas_result;
+      if (Runtime::Current()->IsActiveTransaction()) {
+        cas_result = obj->CasFieldStrongSequentiallyConsistentObject<kTransactionActive>(
+            field_offset,
+            expected_value,
+            desired_value);
+      } else {
+        cas_result = obj->CasFieldStrongSequentiallyConsistentObject<kTransactionInactive>(
+            field_offset,
+            expected_value,
+            desired_value);
+      }
+      StoreResult(cas_result, result);
+      break;
+    }
+    case VarHandle::AccessMode::kWeakCompareAndSet:
+    case VarHandle::AccessMode::kWeakCompareAndSetAcquire:
+    case VarHandle::AccessMode::kWeakCompareAndSetPlain:
+    case VarHandle::AccessMode::kWeakCompareAndSetRelease: {
+      ReadBarrierForVarHandleAccess(obj, field_offset);
+      ObjPtr<Object> expected_value = ValueGetter<ObjPtr<Object>>::Get(getter);
+      ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter);
+      bool cas_result;
+      if (Runtime::Current()->IsActiveTransaction()) {
+        cas_result = obj->CasFieldWeakSequentiallyConsistentObject<kTransactionActive>(
+            field_offset,
+            expected_value,
+            desired_value);
+      } else {
+        cas_result = obj->CasFieldWeakSequentiallyConsistentObject<kTransactionInactive>(
+            field_offset,
+            expected_value,
+            desired_value);
+      }
+      StoreResult(cas_result, result);
+      break;
+    }
+    case VarHandle::AccessMode::kCompareAndExchange:
+    case VarHandle::AccessMode::kCompareAndExchangeAcquire:
+    case VarHandle::AccessMode::kCompareAndExchangeRelease: {
+      ReadBarrierForVarHandleAccess(obj, field_offset);
+      ObjPtr<Object> expected_value = ValueGetter<ObjPtr<Object>>::Get(getter);
+      ObjPtr<Object> desired_value = ValueGetter<ObjPtr<Object>>::Get(getter);
+      ObjPtr<Object> witness_value;
+      if (Runtime::Current()->IsActiveTransaction()) {
+        witness_value = obj->CompareAndExchangeFieldObject<kTransactionActive>(
+            field_offset,
+            expected_value,
+            desired_value);
+      } else {
+        witness_value = obj->CompareAndExchangeFieldObject<kTransactionInactive>(
+            field_offset,
+            expected_value,
+            desired_value);
+      }
+      StoreResult(witness_value, result);
+      break;
+    }
+    case VarHandle::AccessMode::kGetAndSet:
+    case VarHandle::AccessMode::kGetAndSetAcquire:
+    case VarHandle::AccessMode::kGetAndSetRelease: {
+      ReadBarrierForVarHandleAccess(obj, field_offset);
+      ObjPtr<Object> new_value = ValueGetter<ObjPtr<Object>>::Get(getter);
+      ObjPtr<Object> old_value;
+      if (Runtime::Current()->IsActiveTransaction()) {
+        old_value = obj->ExchangeFieldObject<kTransactionActive>(field_offset, new_value);
+      } else {
+        old_value = obj->ExchangeFieldObject<kTransactionInactive>(field_offset, new_value);
+      }
+      StoreResult(old_value, result);
+      break;
+    }
+    case VarHandle::AccessMode::kGetAndAdd:
+    case VarHandle::AccessMode::kGetAndAddAcquire:
+    case VarHandle::AccessMode::kGetAndAddRelease:
+    case VarHandle::AccessMode::kGetAndBitwiseOr:
+    case VarHandle::AccessMode::kGetAndBitwiseOrAcquire:
+    case VarHandle::AccessMode::kGetAndBitwiseOrRelease:
+    case VarHandle::AccessMode::kGetAndBitwiseAnd:
+    case VarHandle::AccessMode::kGetAndBitwiseAndAcquire:
+    case VarHandle::AccessMode::kGetAndBitwiseAndRelease:
+    case VarHandle::AccessMode::kGetAndBitwiseXor:
+    case VarHandle::AccessMode::kGetAndBitwiseXorAcquire:
+    case VarHandle::AccessMode::kGetAndBitwiseXorRelease: {
+      size_t index = static_cast<size_t>(access_mode);
+      const char* access_mode_name = kAccessorToAccessMode[index].method_name;
+      UnreachableAccessMode(access_mode_name, "Object");
+    }
+  }
+  return true;
+}
+
+// Class for accessing primitive array elements.
+template <typename T>
+class PrimitiveArrayElementAccessor {
+ public:
+  static T* GetElementAddress(ObjPtr<Array> target_array, int target_element)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    auto primitive_array = ObjPtr<PrimitiveArray<T>>::DownCast(target_array);
+    DCHECK(primitive_array->CheckIsValidIndex(target_element));
+    return &primitive_array->GetData()[target_element];
+  }
+
+  static bool Dispatch(VarHandle::AccessMode access_mode,
+                       ObjPtr<Array> target_array,
+                       int target_element,
+                       ShadowFrameGetter* getter,
+                       JValue* result)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    T* element_address = GetElementAddress(target_array, target_element);
+    switch (access_mode) {
+      case VarHandle::AccessMode::kGet: {
+        GetAccessor<T> accessor(result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kSet: {
+        T new_value = ValueGetter<T>::Get(getter);
+        SetAccessor<T> accessor(new_value);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAcquire:
+      case VarHandle::AccessMode::kGetOpaque:
+      case VarHandle::AccessMode::kGetVolatile: {
+        GetVolatileAccessor<T> accessor(result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kSetOpaque:
+      case VarHandle::AccessMode::kSetRelease:
+      case VarHandle::AccessMode::kSetVolatile: {
+        T new_value = ValueGetter<T>::Get(getter);
+        SetVolatileAccessor<T> accessor(new_value);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kCompareAndSet: {
+        T expected_value = ValueGetter<T>::Get(getter);
+        T desired_value = ValueGetter<T>::Get(getter);
+        CompareAndSetAccessor<T> accessor(expected_value, desired_value, result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kCompareAndExchange:
+      case VarHandle::AccessMode::kCompareAndExchangeAcquire:
+      case VarHandle::AccessMode::kCompareAndExchangeRelease: {
+        T expected_value = ValueGetter<T>::Get(getter);
+        T desired_value = ValueGetter<T>::Get(getter);
+        CompareAndExchangeAccessor<T> accessor(expected_value, desired_value, result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kWeakCompareAndSet:
+      case VarHandle::AccessMode::kWeakCompareAndSetAcquire:
+      case VarHandle::AccessMode::kWeakCompareAndSetPlain:
+      case VarHandle::AccessMode::kWeakCompareAndSetRelease: {
+        T expected_value = ValueGetter<T>::Get(getter);
+        T desired_value = ValueGetter<T>::Get(getter);
+        WeakCompareAndSetAccessor<T> accessor(expected_value, desired_value, result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAndSet:
+      case VarHandle::AccessMode::kGetAndSetAcquire:
+      case VarHandle::AccessMode::kGetAndSetRelease: {
+        T new_value = ValueGetter<T>::Get(getter);
+        GetAndSetAccessor<T> accessor(new_value, result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAndAdd:
+      case VarHandle::AccessMode::kGetAndAddAcquire:
+      case VarHandle::AccessMode::kGetAndAddRelease: {
+        T value = ValueGetter<T>::Get(getter);
+        GetAndAddAccessor<T> accessor(value, result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAndBitwiseOr:
+      case VarHandle::AccessMode::kGetAndBitwiseOrAcquire:
+      case VarHandle::AccessMode::kGetAndBitwiseOrRelease: {
+        T value = ValueGetter<T>::Get(getter);
+        GetAndBitwiseOrAccessor<T> accessor(value, result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAndBitwiseAnd:
+      case VarHandle::AccessMode::kGetAndBitwiseAndAcquire:
+      case VarHandle::AccessMode::kGetAndBitwiseAndRelease: {
+        T value = ValueGetter<T>::Get(getter);
+        GetAndBitwiseAndAccessor<T> accessor(value, result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAndBitwiseXor:
+      case VarHandle::AccessMode::kGetAndBitwiseXorAcquire:
+      case VarHandle::AccessMode::kGetAndBitwiseXorRelease: {
+        T value = ValueGetter<T>::Get(getter);
+        GetAndBitwiseXorAccessor<T> accessor(value, result);
+        accessor.Access(element_address);
+        break;
+      }
+    }
+    return true;
+  }
+};
+
+// Class for accessing primitive array elements.
+template <typename T>
+class ByteArrayViewAccessor {
+ public:
+  static inline bool IsAccessAligned(int8_t* data, int data_index) {
+    static_assert(IsPowerOfTwo(sizeof(T)), "unexpected size");
+    static_assert(std::is_arithmetic<T>::value, "unexpected type");
+    uintptr_t alignment_mask = sizeof(T) - 1;
+    uintptr_t address = reinterpret_cast<uintptr_t>(data + data_index);
+    return (address & alignment_mask) == 0;
+  }
+
+  static inline void MaybeByteSwap(bool byte_swap, T* const value) {
+    if (byte_swap) {
+      *value = BSWAP(*value);
+    }
+  }
+
+  static bool Dispatch(const VarHandle::AccessMode access_mode,
+                       int8_t* const data,
+                       const int data_index,
+                       const bool byte_swap,
+                       ShadowFrameGetter* const getter,
+                       JValue* const result)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    const bool is_aligned = IsAccessAligned(data, data_index);
+    if (!is_aligned) {
+      switch (access_mode) {
+        case VarHandle::AccessMode::kGet: {
+          T value;
+          memcpy(&value, data + data_index, sizeof(T));
+          MaybeByteSwap(byte_swap, &value);
+          StoreResult(value, result);
+          return true;
+        }
+        case VarHandle::AccessMode::kSet: {
+          T new_value = ValueGetter<T>::Get(getter);
+          MaybeByteSwap(byte_swap, &new_value);
+          memcpy(data + data_index, &new_value, sizeof(T));
+          return true;
+        }
+        default:
+          // No other access modes support unaligned access.
+          ThrowIllegalStateException("Unaligned access not supported");
+          return false;
+      }
+    }
+
+    T* const element_address = reinterpret_cast<T*>(data + data_index);
+    CHECK(IsAccessAligned(reinterpret_cast<int8_t*>(element_address), 0));
+    switch (access_mode) {
+      case VarHandle::AccessMode::kGet: {
+        GetAccessor<T> accessor(result);
+        accessor.Access(element_address);
+        JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result);
+        break;
+      }
+      case VarHandle::AccessMode::kSet: {
+        T new_value = ValueGetter<T>::Get(getter);
+        MaybeByteSwap(byte_swap, &new_value);
+        SetAccessor<T> accessor(new_value);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAcquire:
+      case VarHandle::AccessMode::kGetOpaque:
+      case VarHandle::AccessMode::kGetVolatile: {
+        GetVolatileAccessor<T> accessor(result);
+        accessor.Access(element_address);
+        JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result);
+        break;
+      }
+      case VarHandle::AccessMode::kSetOpaque:
+      case VarHandle::AccessMode::kSetRelease:
+      case VarHandle::AccessMode::kSetVolatile: {
+        T new_value = ValueGetter<T>::Get(getter);
+        MaybeByteSwap(byte_swap, &new_value);
+        SetVolatileAccessor<T> accessor(new_value);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kCompareAndSet: {
+        T expected_value = ValueGetter<T>::Get(getter);
+        T desired_value = ValueGetter<T>::Get(getter);
+        MaybeByteSwap(byte_swap, &expected_value);
+        MaybeByteSwap(byte_swap, &desired_value);
+        CompareAndSetAccessor<T> accessor(expected_value, desired_value, result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kCompareAndExchange:
+      case VarHandle::AccessMode::kCompareAndExchangeAcquire:
+      case VarHandle::AccessMode::kCompareAndExchangeRelease: {
+        T expected_value = ValueGetter<T>::Get(getter);
+        T desired_value = ValueGetter<T>::Get(getter);
+        MaybeByteSwap(byte_swap, &expected_value);
+        MaybeByteSwap(byte_swap, &desired_value);
+        CompareAndExchangeAccessor<T> accessor(expected_value, desired_value, result);
+        accessor.Access(element_address);
+        JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result);
+        break;
+      }
+      case VarHandle::AccessMode::kWeakCompareAndSet:
+      case VarHandle::AccessMode::kWeakCompareAndSetAcquire:
+      case VarHandle::AccessMode::kWeakCompareAndSetPlain:
+      case VarHandle::AccessMode::kWeakCompareAndSetRelease: {
+        T expected_value = ValueGetter<T>::Get(getter);
+        T desired_value = ValueGetter<T>::Get(getter);
+        MaybeByteSwap(byte_swap, &expected_value);
+        MaybeByteSwap(byte_swap, &desired_value);
+        WeakCompareAndSetAccessor<T> accessor(expected_value, desired_value, result);
+        accessor.Access(element_address);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAndSet:
+      case VarHandle::AccessMode::kGetAndSetAcquire:
+      case VarHandle::AccessMode::kGetAndSetRelease: {
+        T new_value = ValueGetter<T>::Get(getter);
+        MaybeByteSwap(byte_swap, &new_value);
+        GetAndSetAccessor<T> accessor(new_value, result);
+        accessor.Access(element_address);
+        JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAndAdd:
+      case VarHandle::AccessMode::kGetAndAddAcquire:
+      case VarHandle::AccessMode::kGetAndAddRelease: {
+        T value = ValueGetter<T>::Get(getter);
+        if (byte_swap) {
+          GetAndAddWithByteSwapAccessor<T> accessor(value, result);
+          accessor.Access(element_address);
+        } else {
+          GetAndAddAccessor<T> accessor(value, result);
+          accessor.Access(element_address);
+        }
+        break;
+      }
+      case VarHandle::AccessMode::kGetAndBitwiseOr:
+      case VarHandle::AccessMode::kGetAndBitwiseOrAcquire:
+      case VarHandle::AccessMode::kGetAndBitwiseOrRelease: {
+        T value = ValueGetter<T>::Get(getter);
+        MaybeByteSwap(byte_swap, &value);
+        GetAndBitwiseOrAccessor<T> accessor(value, result);
+        accessor.Access(element_address);
+        JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAndBitwiseAnd:
+      case VarHandle::AccessMode::kGetAndBitwiseAndAcquire:
+      case VarHandle::AccessMode::kGetAndBitwiseAndRelease: {
+        T value = ValueGetter<T>::Get(getter);
+        MaybeByteSwap(byte_swap, &value);
+        GetAndBitwiseAndAccessor<T> accessor(value, result);
+        accessor.Access(element_address);
+        JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result);
+        break;
+      }
+      case VarHandle::AccessMode::kGetAndBitwiseXor:
+      case VarHandle::AccessMode::kGetAndBitwiseXorAcquire:
+      case VarHandle::AccessMode::kGetAndBitwiseXorRelease: {
+        T value = ValueGetter<T>::Get(getter);
+        MaybeByteSwap(byte_swap, &value);
+        GetAndBitwiseXorAccessor<T> accessor(value, result);
+        accessor.Access(element_address);
+        JValueByteSwapper<T>::MaybeByteSwap(byte_swap, result);
+        break;
+      }
+    }
+    return true;
+  }
+};
+
 }  // namespace
 
 Class* VarHandle::GetVarType() {
@@ -267,35 +1425,38 @@
 }
 
 bool VarHandle::IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type) {
-  ScopedAssertNoThreadSuspension ants(__FUNCTION__);
-
+  StackHandleScope<3> hs(Thread::Current());
+  Handle<Class> mt_rtype(hs.NewHandle(method_type->GetRType()));
+  Handle<VarHandle> vh(hs.NewHandle(this));
+  Handle<Class> var_type(hs.NewHandle(vh->GetVarType()));
   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 return type first.
+  if (mt_rtype->GetPrimitiveType() == Primitive::Type::kPrimVoid) {
+    // The result of the operation will be discarded. The return type
+    // of the VarHandle is immaterial.
+  } else {
+    ObjPtr<Class> vh_rtype(GetReturnType(access_mode_template, var_type.Get()));
+    if (!IsReturnTypeConvertible(vh_rtype, mt_rtype.Get())) {
+      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,
+                                                      var_type.Get(),
                                                       GetCoordinateType0(),
                                                       GetCoordinateType1());
   if (vh_ptypes_count != method_type->GetPTypes()->GetLength()) {
     return false;
   }
 
-  // Check the parameter types match.
+  // Check the parameter types are compatible.
   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()) {
+    if (!IsParameterTypeConvertible(mt_ptypes->Get(i), vh_ptypes[i])) {
       return false;
     }
   }
@@ -311,8 +1472,9 @@
   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());
+  const int32_t ptypes_count = GetNumberOfParameters(access_mode_template,
+                                                     vh->GetCoordinateType0(),
+                                                     vh->GetCoordinateType1());
   Handle<ObjectArray<Class>> ptypes = hs.NewHandle(NewArrayOfClasses(self, ptypes_count));
   if (ptypes == nullptr) {
     return nullptr;
@@ -334,6 +1496,29 @@
   return GetMethodTypeForAccessMode(self, this, access_mode);
 }
 
+bool VarHandle::Access(AccessMode access_mode,
+                       ShadowFrame* shadow_frame,
+                       InstructionOperands* operands,
+                       JValue* result) {
+  Class* klass = GetClass();
+  if (klass == FieldVarHandle::StaticClass()) {
+    auto vh = reinterpret_cast<FieldVarHandle*>(this);
+    return vh->Access(access_mode, shadow_frame, operands, result);
+  } else if (klass == ArrayElementVarHandle::StaticClass()) {
+    auto vh = reinterpret_cast<ArrayElementVarHandle*>(this);
+    return vh->Access(access_mode, shadow_frame, operands, result);
+  } else if (klass == ByteArrayViewVarHandle::StaticClass()) {
+    auto vh = reinterpret_cast<ByteArrayViewVarHandle*>(this);
+    return vh->Access(access_mode, shadow_frame, operands, result);
+  } else if (klass == ByteBufferViewVarHandle::StaticClass()) {
+    auto vh = reinterpret_cast<ByteBufferViewVarHandle*>(this);
+    return vh->Access(access_mode, shadow_frame, operands, result);
+  } else {
+    LOG(FATAL) << "Unknown varhandle kind";
+    UNREACHABLE();
+  }
+}
+
 const char* VarHandle::GetReturnTypeDescriptor(const char* accessor_name) {
   AccessMode access_mode;
   if (!GetAccessModeByMethodName(accessor_name, &access_mode)) {
@@ -369,6 +1554,10 @@
   return true;
 }
 
+Class* VarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+  return static_class_.Read();
+}
+
 void VarHandle::SetClass(Class* klass) {
   CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
   CHECK(klass != nullptr);
@@ -391,6 +1580,57 @@
   return reinterpret_cast<ArtField*>(opaque_field);
 }
 
+bool FieldVarHandle::Access(AccessMode access_mode,
+                            ShadowFrame* shadow_frame,
+                            InstructionOperands* operands,
+                            JValue* result) {
+  ShadowFrameGetter getter(*shadow_frame, operands);
+  ArtField* field = GetField();
+  ObjPtr<Object> obj;
+  if (field->IsStatic()) {
+    DCHECK_LE(operands->GetNumberOfOperands(),
+              2u * (Primitive::Is64BitType(GetVarType()->GetPrimitiveType()) ? 2u : 1u));
+    obj = field->GetDeclaringClass();
+  } else {
+    DCHECK_GE(operands->GetNumberOfOperands(), 1u);
+    DCHECK_LE(operands->GetNumberOfOperands(),
+              1u + 2u * (Primitive::Is64BitType(GetVarType()->GetPrimitiveType()) ? 2u : 1u));
+    obj = getter.GetReference();
+    if (obj.IsNull()) {
+      ThrowNullPointerExceptionForCoordinate();
+      return false;
+    }
+  }
+  DCHECK(!obj.IsNull());
+
+  const MemberOffset offset = field->GetOffset();
+  const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType();
+  switch (primitive_type) {
+    case Primitive::Type::kPrimNot:
+      return FieldAccessor<ObjPtr<Object>>::Dispatch(access_mode, obj, offset, &getter, result);
+    case Primitive::kPrimBoolean:
+      return FieldAccessor<uint8_t>::Dispatch(access_mode, obj, offset, &getter, result);
+    case Primitive::kPrimByte:
+      return FieldAccessor<int8_t>::Dispatch(access_mode, obj, offset, &getter, result);
+    case Primitive::kPrimChar:
+      return FieldAccessor<uint16_t>::Dispatch(access_mode, obj, offset, &getter, result);
+    case Primitive::kPrimShort:
+      return FieldAccessor<int16_t>::Dispatch(access_mode, obj, offset, &getter, result);
+    case Primitive::kPrimInt:
+      return FieldAccessor<int32_t>::Dispatch(access_mode, obj, offset, &getter, result);
+    case Primitive::kPrimFloat:
+      return FieldAccessor<float>::Dispatch(access_mode,  obj, offset, &getter, result);
+    case Primitive::kPrimLong:
+      return FieldAccessor<int64_t>::Dispatch(access_mode, obj, offset, &getter, result);
+    case Primitive::kPrimDouble:
+      return FieldAccessor<double>::Dispatch(access_mode, obj, offset, &getter, result);
+    case Primitive::kPrimVoid:
+      break;
+  }
+  LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type;
+  UNREACHABLE();
+}
+
 Class* FieldVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
   return static_class_.Read();
 }
@@ -412,6 +1652,94 @@
 
 GcRoot<Class> FieldVarHandle::static_class_;
 
+bool ArrayElementVarHandle::Access(AccessMode access_mode,
+                                   ShadowFrame* shadow_frame,
+                                   InstructionOperands* operands,
+                                   JValue* result) {
+  ShadowFrameGetter getter(*shadow_frame, operands);
+
+  // The target array is the first co-ordinate type preceeding var type arguments.
+  ObjPtr<Object> raw_array(getter.GetReference());
+  if (raw_array == nullptr) {
+    ThrowNullPointerExceptionForCoordinate();
+    return false;
+  }
+
+  ObjPtr<Array> target_array(raw_array->AsArray());
+
+  // The target array element is the second co-ordinate type preceeding var type arguments.
+  const int target_element = getter.Get();
+  if (!target_array->CheckIsValidIndex(target_element)) {
+    DCHECK(Thread::Current()->IsExceptionPending());
+    return false;
+  }
+
+  const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType();
+  switch (primitive_type) {
+    case Primitive::Type::kPrimNot: {
+      MemberOffset target_element_offset =
+          target_array->AsObjectArray<Object>()->OffsetOfElement(target_element);
+      return FieldAccessor<ObjPtr<Object>>::Dispatch(access_mode,
+                                                     target_array,
+                                                     target_element_offset,
+                                                     &getter,
+                                                     result);
+    }
+    case Primitive::Type::kPrimBoolean:
+      return PrimitiveArrayElementAccessor<uint8_t>::Dispatch(access_mode,
+                                                              target_array,
+                                                              target_element,
+                                                              &getter,
+                                                              result);
+    case Primitive::Type::kPrimByte:
+      return PrimitiveArrayElementAccessor<int8_t>::Dispatch(access_mode,
+                                                             target_array,
+                                                             target_element,
+                                                             &getter,
+                                                             result);
+    case Primitive::Type::kPrimChar:
+      return PrimitiveArrayElementAccessor<uint16_t>::Dispatch(access_mode,
+                                                               target_array,
+                                                               target_element,
+                                                               &getter,
+                                                               result);
+    case Primitive::Type::kPrimShort:
+      return PrimitiveArrayElementAccessor<int16_t>::Dispatch(access_mode,
+                                                              target_array,
+                                                              target_element,
+                                                              &getter,
+                                                              result);
+    case Primitive::Type::kPrimInt:
+      return PrimitiveArrayElementAccessor<int32_t>::Dispatch(access_mode,
+                                                              target_array,
+                                                              target_element,
+                                                              &getter,
+                                                              result);
+    case Primitive::Type::kPrimLong:
+      return PrimitiveArrayElementAccessor<int64_t>::Dispatch(access_mode,
+                                                              target_array,
+                                                              target_element,
+                                                              &getter,
+                                                              result);
+    case Primitive::Type::kPrimFloat:
+      return PrimitiveArrayElementAccessor<float>::Dispatch(access_mode,
+                                                            target_array,
+                                                            target_element,
+                                                            &getter,
+                                                            result);
+    case Primitive::Type::kPrimDouble:
+      return PrimitiveArrayElementAccessor<double>::Dispatch(access_mode,
+                                                             target_array,
+                                                             target_element,
+                                                             &getter,
+                                                             result);
+    case Primitive::Type::kPrimVoid:
+      break;
+  }
+  LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type;
+  UNREACHABLE();
+}
+
 Class* ArrayElementVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
   return static_class_.Read();
 }
@@ -437,6 +1765,90 @@
   return GetFieldBoolean(NativeByteOrderOffset());
 }
 
+bool ByteArrayViewVarHandle::Access(AccessMode access_mode,
+                                    ShadowFrame* shadow_frame,
+                                    InstructionOperands* operands,
+                                    JValue* result) {
+  ShadowFrameGetter getter(*shadow_frame, operands);
+
+  // The byte array is the first co-ordinate type preceeding var type arguments.
+  ObjPtr<Object> raw_byte_array(getter.GetReference());
+  if (raw_byte_array == nullptr) {
+    ThrowNullPointerExceptionForCoordinate();
+    return false;
+  }
+
+  ObjPtr<ByteArray> byte_array(raw_byte_array->AsByteArray());
+
+  // The offset in the byte array element is the second co-ordinate type.
+  const int32_t data_offset = getter.Get();
+
+  // Bounds check requested access.
+  const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType();
+  if (!CheckElementIndex(primitive_type, data_offset, byte_array->GetLength())) {
+    return false;
+  }
+
+  int8_t* const data = byte_array->GetData();
+  bool byte_swap = !GetNativeByteOrder();
+  switch (primitive_type) {
+    case Primitive::Type::kPrimNot:
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimVoid:
+      // These are not supported for byte array views and not instantiable.
+      break;
+    case Primitive::kPrimChar:
+      return ByteArrayViewAccessor<uint16_t>::Dispatch(access_mode,
+                                                       data,
+                                                       data_offset,
+                                                       byte_swap,
+                                                       &getter,
+                                                       result);
+    case Primitive::kPrimShort:
+      return ByteArrayViewAccessor<int16_t>::Dispatch(access_mode,
+                                                      data,
+                                                      data_offset,
+                                                      byte_swap,
+                                                      &getter,
+                                                      result);
+    case Primitive::kPrimInt:
+      return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode,
+                                                      data,
+                                                      data_offset,
+                                                      byte_swap,
+                                                      &getter,
+                                                      result);
+    case Primitive::kPrimFloat:
+      // Treated as a bitwise representation. See javadoc comments for
+      // java.lang.invoke.MethodHandles.byteArrayViewVarHandle().
+      return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode,
+                                                      data,
+                                                      data_offset,
+                                                      byte_swap,
+                                                      &getter,
+                                                      result);
+    case Primitive::kPrimLong:
+      return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode,
+                                                      data,
+                                                      data_offset,
+                                                      byte_swap,
+                                                      &getter,
+                                                      result);
+    case Primitive::kPrimDouble:
+      // Treated as a bitwise representation. See javadoc comments for
+      // java.lang.invoke.MethodHandles.byteArrayViewVarHandle().
+      return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode,
+                                                      data,
+                                                      data_offset,
+                                                      byte_swap,
+                                                      &getter,
+                                                      result);
+  }
+  LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type;
+  UNREACHABLE();
+}
+
 Class* ByteArrayViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
   return static_class_.Read();
 }
@@ -462,6 +1874,122 @@
   return GetFieldBoolean(NativeByteOrderOffset());
 }
 
+bool ByteBufferViewVarHandle::Access(AccessMode access_mode,
+                                     ShadowFrame* shadow_frame,
+                                     InstructionOperands* operands,
+                                     JValue* result) {
+  ShadowFrameGetter getter(*shadow_frame, operands);
+
+  // The byte buffer is the first co-ordinate argument preceeding var type arguments.
+  ObjPtr<Object> byte_buffer(getter.GetReference());
+  if (byte_buffer == nullptr) {
+    ThrowNullPointerExceptionForCoordinate();
+    return false;
+  }
+
+  // The byte index for access is the second co-ordinate
+  // argument. This is relative to the offset field of the ByteBuffer.
+  const int32_t byte_index = getter.Get();
+
+  // Check access_mode is compatible with ByteBuffer's read-only property.
+  bool is_read_only = byte_buffer->GetFieldBoolean(
+      GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_isReadOnly));
+  if (is_read_only && !IsReadOnlyAccessMode(access_mode)) {
+    ThrowReadOnlyBufferException();
+    return false;
+  }
+
+  // The native_address is only set for ByteBuffer instances backed by native memory.
+  const int64_t native_address =
+      byte_buffer->GetField64(GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_address));
+
+  // Determine offset and limit for accesses.
+  int32_t byte_buffer_offset;
+  if (native_address == 0l) {
+    // Accessing a heap allocated byte buffer.
+    byte_buffer_offset = byte_buffer->GetField32(
+        GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_offset));
+  } else {
+    // Accessing direct memory.
+    byte_buffer_offset = 0;
+  }
+  const int32_t byte_buffer_limit = byte_buffer->GetField32(
+      GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_limit));
+
+  const Primitive::Type primitive_type = GetVarType()->GetPrimitiveType();
+  if (!CheckElementIndex(primitive_type, byte_index, byte_buffer_offset, byte_buffer_limit)) {
+    return false;
+  }
+  const int32_t checked_offset32 = byte_buffer_offset + byte_index;
+
+  int8_t* data;
+  if (native_address == 0) {
+    ObjPtr<ByteArray> heap_byte_array = byte_buffer->GetFieldObject<ByteArray>(
+        GetMemberOffset(WellKnownClasses::java_nio_ByteBuffer_hb));
+    data = heap_byte_array->GetData();
+  } else {
+    data = reinterpret_cast<int8_t*>(static_cast<uint32_t>(native_address));
+  }
+
+  bool byte_swap = !GetNativeByteOrder();
+  switch (primitive_type) {
+    case Primitive::kPrimChar:
+      return ByteArrayViewAccessor<uint16_t>::Dispatch(access_mode,
+                                                       data,
+                                                       checked_offset32,
+                                                       byte_swap,
+                                                       &getter,
+                                                       result);
+    case Primitive::kPrimShort:
+      return ByteArrayViewAccessor<int16_t>::Dispatch(access_mode,
+                                                      data,
+                                                      checked_offset32,
+                                                      byte_swap,
+                                                      &getter,
+                                                      result);
+    case Primitive::kPrimInt:
+      return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode,
+                                                      data,
+                                                      checked_offset32,
+                                                      byte_swap,
+                                                      &getter,
+                                                      result);
+    case Primitive::kPrimFloat:
+      // Treated as a bitwise representation. See javadoc comments for
+      // java.lang.invoke.MethodHandles.byteArrayViewVarHandle().
+      return ByteArrayViewAccessor<int32_t>::Dispatch(access_mode,
+                                                      data,
+                                                      checked_offset32,
+                                                      byte_swap,
+                                                      &getter,
+                                                      result);
+    case Primitive::kPrimLong:
+      return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode,
+                                                      data,
+                                                      checked_offset32,
+                                                      byte_swap,
+                                                      &getter,
+                                                      result);
+    case Primitive::kPrimDouble:
+      // Treated as a bitwise representation. See javadoc comments for
+      // java.lang.invoke.MethodHandles.byteArrayViewVarHandle().
+      return ByteArrayViewAccessor<int64_t>::Dispatch(access_mode,
+                                                      data,
+                                                      checked_offset32,
+                                                      byte_swap,
+                                                      &getter,
+                                                      result);
+    case Primitive::Type::kPrimNot:
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimVoid:
+      // These are not supported for byte array views and not instantiable.
+      break;
+  }
+  LOG(FATAL) << "Unreachable: Unexpected primitive " << primitive_type;
+  UNREACHABLE();
+}
+
 Class* ByteBufferViewVarHandle::StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
   return static_class_.Read();
 }
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index 7b48669..6565af7 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -18,18 +18,24 @@
 #define ART_RUNTIME_MIRROR_VAR_HANDLE_H_
 
 #include "handle.h"
+#include "interpreter/shadow_frame.h"
 #include "gc_root.h"
+#include "jvalue.h"
 #include "object.h"
 
 namespace art {
 
 template<class T> class Handle;
+class InstructionOperands;
+
 struct VarHandleOffsets;
 struct FieldVarHandleOffsets;
 struct ArrayElementVarHandleOffsets;
 struct ByteArrayViewVarHandleOffsets;
 struct ByteBufferViewVarHandleOffsets;
 
+class ShadowFrameGetter;
+
 namespace mirror {
 
 class MethodType;
@@ -44,6 +50,10 @@
   // (array, index, old, new).
   static constexpr int kMaxAccessorParameters = 4;
 
+  // The maximum number of VarType parameters a VarHandle accessor
+  // method can take.
+  static constexpr size_t kMaxVarTypeParameters = 2;
+
   // Enumeration of the possible access modes. This mirrors the enum
   // in java.lang.invoke.VarHandle.
   enum class AccessMode : uint32_t {
@@ -101,11 +111,16 @@
   // 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_);
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
-  static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return static_class_.Read();
-  }
+  bool Access(AccessMode access_mode,
+              ShadowFrame* shadow_frame,
+              InstructionOperands* operands,
+              JValue* result)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Gets the variable type that is operated on by this VarHandle instance.
+  Class* GetVarType() REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Gets the return type descriptor for a named accessor method,
   // nullptr if accessor_method is not supported.
@@ -115,12 +130,13 @@
   // VarHandle access method, such as "setOpaque". Returns false otherwise.
   static bool GetAccessModeByMethodName(const char* method_name, AccessMode* access_mode);
 
+
+  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:
-  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_);
@@ -163,6 +179,12 @@
 // The corresponding managed class in libart java.lang.invoke.FieldVarHandle.
 class MANAGED FieldVarHandle : public VarHandle {
  public:
+  bool Access(AccessMode access_mode,
+              ShadowFrame* shadow_frame,
+              InstructionOperands* operands,
+              JValue* result)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   ArtField* GetField() REQUIRES_SHARED(Locks::mutator_lock_);
 
   static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -190,6 +212,12 @@
 // The corresponding managed class in libart java.lang.invoke.ArrayElementVarHandle.
 class MANAGED ArrayElementVarHandle : public VarHandle {
  public:
+    bool Access(AccessMode access_mode,
+                ShadowFrame* shadow_frame,
+                InstructionOperands* operands,
+                JValue* result)
+      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_);
@@ -207,6 +235,12 @@
 // The corresponding managed class in libart java.lang.invoke.ByteArrayViewVarHandle.
 class MANAGED ByteArrayViewVarHandle : public VarHandle {
  public:
+  bool Access(AccessMode access_mode,
+              ShadowFrame* shadow_frame,
+              InstructionOperands* operands,
+              JValue* result)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_);
 
   static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -234,10 +268,13 @@
 // The corresponding managed class in libart java.lang.invoke.ByteBufferViewVarHandle.
 class MANAGED ByteBufferViewVarHandle : public VarHandle {
  public:
-  bool GetNativeByteOrder() REQUIRES_SHARED(Locks::mutator_lock_);
+  bool Access(AccessMode access_mode,
+              ShadowFrame* shadow_frame,
+              InstructionOperands* operands,
+              JValue* result)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
-  static ByteBufferViewVarHandle* Create(Thread* const self, bool native_byte_order)
-      REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+  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_);
@@ -245,6 +282,21 @@
   static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
+  bool AccessHeapBuffer(AccessMode access_mode,
+                        ObjPtr<Object> byte_buffer,
+                        int buffer_offset,
+                        ObjPtr<ByteArray> heap_byte_array,
+                        ShadowFrameGetter* getter,
+                        JValue* result)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  bool AccessFixedMemory(AccessMode access_mode,
+                         ObjPtr<Object> byte_buffer,
+                         int buffer_offset,
+                         ShadowFrameGetter* getter,
+                         JValue* result)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   static MemberOffset NativeByteOrderOffset() {
     return MemberOffset(OFFSETOF_MEMBER(ByteBufferViewVarHandle, native_byte_order_));
   }
diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc
index e844fd4..d9fa07f 100644
--- a/runtime/mirror/var_handle_test.cc
+++ b/runtime/mirror/var_handle_test.cc
@@ -327,7 +327,7 @@
     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")));
+    EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(IIII)V")));
   }
 
   // Check compatibility - "GetAndUpdate" pattern
@@ -336,7 +336,7 @@
     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")));
+    EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)S")));
   }
 
   // Check synthesized method types match expected forms.
@@ -461,8 +461,8 @@
     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")));
+    EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)S")));
+    EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(IIJ)V")));
   }
 
   // Check compatibility - "GetAndUpdate" pattern