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/common_throws.cc b/runtime/common_throws.cc
index 19e7f76..f7ff15f 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -53,6 +53,11 @@
}
}
+static void ThrowException(const char* exception_descriptor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ Thread* self = Thread::Current();
+ self->ThrowNewException(exception_descriptor, nullptr);
+}
+
static void ThrowException(const char* exception_descriptor,
ObjPtr<mirror::Class> referrer,
const char* fmt,
@@ -243,6 +248,11 @@
ThrowException("Ljava/lang/IllegalArgumentException;", nullptr, msg);
}
+// IllegalStateException
+
+void ThrowIllegalStateException(const char* msg) {
+ ThrowException("Ljava/lang/IllegalStateException;", nullptr, msg);
+}
// IncompatibleClassChangeError
@@ -314,6 +324,13 @@
ArtMethod::PrettyMethod(method).c_str()).c_str());
}
+// IndexOutOfBoundsException
+
+void ThrowIndexOutOfBoundsException(int index, int length) {
+ ThrowException("Ljava/lang/IndexOutOfBoundsException;", nullptr,
+ StringPrintf("length=%d; index=%d", length, index).c_str());
+}
+
// InternalError
void ThrowInternalError(const char* fmt, ...) {
@@ -719,6 +736,12 @@
ThrowException("Ljava/lang/NullPointerException;", nullptr, msg);
}
+// ReadOnlyBufferException
+
+void ThrowReadOnlyBufferException() {
+ Thread::Current()->ThrowNewException("Ljava/nio/ReadOnlyBufferException;", nullptr);
+}
+
// RuntimeException
void ThrowRuntimeException(const char* fmt, ...) {
@@ -842,6 +865,12 @@
StringPrintf("length=%d; index=%d", length, index).c_str());
}
+// UnsupportedOperationException
+
+void ThrowUnsupportedOperationException() {
+ ThrowException("Ljava/lang/UnsupportedOperationException;");
+}
+
// VerifyError
void ThrowVerifyError(ObjPtr<mirror::Class> referrer, const char* fmt, ...) {
@@ -853,13 +882,13 @@
// WrongMethodTypeException
-void ThrowWrongMethodTypeException(mirror::MethodType* callee_type,
- mirror::MethodType* callsite_type) {
+void ThrowWrongMethodTypeException(mirror::MethodType* expected_type,
+ mirror::MethodType* actual_type) {
ThrowException("Ljava/lang/invoke/WrongMethodTypeException;",
nullptr,
StringPrintf("Expected %s but was %s",
- callee_type->PrettyDescriptor().c_str(),
- callsite_type->PrettyDescriptor().c_str()).c_str());
+ expected_type->PrettyDescriptor().c_str(),
+ actual_type->PrettyDescriptor().c_str()).c_str());
}
} // namespace art
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index 3512b2b..e9baa4f 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -120,6 +120,11 @@
void ThrowIllegalArgumentException(const char* msg)
REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+// IllegalAccessException
+
+void ThrowIllegalStateException(const char* msg)
+ REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+
// IncompatibleClassChangeError
void ThrowIncompatibleClassChangeError(InvokeType expected_type,
@@ -151,6 +156,11 @@
void ThrowIncompatibleClassChangeErrorForMethodConflict(ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+// IndexOutOfBoundsException
+
+void ThrowIndexOutOfBoundsException(int index, int length)
+ REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+
// InternalError
void ThrowInternalError(const char* fmt, ...)
@@ -223,6 +233,10 @@
void ThrowNullPointerException(const char* msg)
REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+// ReadOnlyBufferException
+
+void ThrowReadOnlyBufferException() REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+
// RuntimeException
void ThrowRuntimeException(const char* fmt, ...)
@@ -244,6 +258,10 @@
void ThrowStringIndexOutOfBoundsException(int index, int length)
REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+// UnsupportedOperationException
+
+void ThrowUnsupportedOperationException() REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+
// VerifyError
void ThrowVerifyError(ObjPtr<mirror::Class> referrer, const char* fmt, ...)
@@ -251,6 +269,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
// WrongMethodTypeException
+
void ThrowWrongMethodTypeException(mirror::MethodType* callee_type,
mirror::MethodType* callsite_type)
REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
diff --git a/runtime/dex/dex_instruction.cc b/runtime/dex/dex_instruction.cc
index b84791f..8862181 100644
--- a/runtime/dex/dex_instruction.cc
+++ b/runtime/dex/dex_instruction.cc
@@ -558,4 +558,11 @@
return operands_[operand_index];
}
+uint32_t NoReceiverInstructionOperands::GetOperand(size_t operand_index) const {
+ DCHECK_LT(GetNumberOfOperands(), inner_->GetNumberOfOperands());
+ // The receiver is the first operand and since we're skipping it, we need to
+ // add 1 to the operand_index.
+ return inner_->GetOperand(operand_index + 1);
+}
+
} // namespace art
diff --git a/runtime/dex/dex_instruction.h b/runtime/dex/dex_instruction.h
index 8b1a5ce..de14ed3 100644
--- a/runtime/dex/dex_instruction.h
+++ b/runtime/dex/dex_instruction.h
@@ -701,7 +701,7 @@
size_t GetNumberOfOperands() const { return num_operands_; }
private:
- size_t num_operands_;
+ const size_t num_operands_;
DISALLOW_IMPLICIT_CONSTRUCTORS(InstructionOperands);
};
@@ -737,6 +737,21 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(VarArgsInstructionOperands);
};
+// Class for accessing operands without the receiver by wrapping an
+// existing InstructionOperands instance.
+class NoReceiverInstructionOperands FINAL : public InstructionOperands {
+ public:
+ explicit NoReceiverInstructionOperands(InstructionOperands* inner)
+ : InstructionOperands(inner->GetNumberOfOperands() - 1), inner_(inner) {}
+ ~NoReceiverInstructionOperands() {}
+ uint32_t GetOperand(size_t operand_index) const OVERRIDE;
+
+ private:
+ const InstructionOperands* const inner_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(NoReceiverInstructionOperands);
+};
+
} // namespace art
#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_H_
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 12b8c38..91b2d0e 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -31,6 +31,7 @@
#include "mirror/class.h"
#include "mirror/emulated_stack_frame.h"
#include "mirror/method_handle_impl-inl.h"
+#include "mirror/var_handle.h"
#include "reflection-inl.h"
#include "reflection.h"
#include "stack.h"
@@ -723,263 +724,149 @@
}
}
-static bool UnimplementedSignaturePolymorphicMethod(Thread* self ATTRIBUTE_UNUSED,
- ShadowFrame& shadow_frame ATTRIBUTE_UNUSED,
- const Instruction* inst ATTRIBUTE_UNUSED,
- uint16_t inst_data ATTRIBUTE_UNUSED,
- JValue* result ATTRIBUTE_UNUSED)
+static bool DoVarHandleInvokeChecked(Thread* self,
+ Handle<mirror::VarHandle> var_handle,
+ Handle<mirror::MethodType> callsite_type,
+ mirror::VarHandle::AccessMode access_mode,
+ ShadowFrame& shadow_frame,
+ InstructionOperands* operands,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
- UNIMPLEMENTED(FATAL) << "TODO(oth): b/65872996";
- return false;
+ // TODO(oth): GetMethodTypeForAccessMode() allocates a MethodType()
+ // which is only required if we need to convert argument and/or
+ // return types.
+ StackHandleScope<1> hs(self);
+ Handle<mirror::MethodType> accessor_type(hs.NewHandle(
+ var_handle->GetMethodTypeForAccessMode(self, access_mode)));
+ const size_t num_vregs = accessor_type->NumberOfVRegs();
+ const int num_params = accessor_type->GetPTypes()->GetLength();
+ ShadowFrameAllocaUniquePtr accessor_frame =
+ CREATE_SHADOW_FRAME(num_vregs, nullptr, shadow_frame.GetMethod(), shadow_frame.GetDexPC());
+ ShadowFrameGetter getter(shadow_frame, operands);
+ static const uint32_t kFirstDestinationReg = 0;
+ ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg);
+ if (!PerformConversions(self, callsite_type, accessor_type, &getter, &setter, num_params)) {
+ return false;
+ }
+ RangeInstructionOperands accessor_operands(kFirstDestinationReg,
+ kFirstDestinationReg + num_vregs);
+ if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) {
+ return false;
+ }
+ return ConvertReturnValue(callsite_type, accessor_type, result);
}
-bool DoVarHandleCompareAndExchange(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+static bool DoVarHandleInvokeCommon(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result,
+ mirror::VarHandle::AccessMode access_mode)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Make sure to check for async exceptions
+ if (UNLIKELY(self->ObserveAsyncException())) {
+ return false;
+ }
+
+ bool is_var_args = inst->HasVarArgs();
+ const uint32_t vRegC = is_var_args ? inst->VRegC_45cc() : inst->VRegC_4rcc();
+ ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(vRegC));
+ if (receiver.IsNull()) {
+ ThrowNullPointerExceptionFromDexPC();
+ return false;
+ }
+
+ StackHandleScope<2> hs(self);
+ Handle<mirror::VarHandle> var_handle(hs.NewHandle(down_cast<mirror::VarHandle*>(receiver.Ptr())));
+ if (!var_handle->IsAccessModeSupported(access_mode)) {
+ ThrowUnsupportedOperationException();
+ return false;
+ }
+
+ const uint32_t vRegH = is_var_args ? inst->VRegH_45cc() : inst->VRegH_4rcc();
+ ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+ Handle<mirror::MethodType> callsite_type(hs.NewHandle(
+ class_linker->ResolveMethodType(self, vRegH, shadow_frame.GetMethod())));
+ // This implies we couldn't resolve one or more types in this VarHandle.
+ if (UNLIKELY(callsite_type == nullptr)) {
+ CHECK(self->IsExceptionPending());
+ return false;
+ }
+
+ if (!var_handle->IsMethodTypeCompatible(access_mode, callsite_type.Get())) {
+ ThrowWrongMethodTypeException(var_handle->GetMethodTypeForAccessMode(self, access_mode),
+ callsite_type.Get());
+ return false;
+ }
+
+ if (is_var_args) {
+ uint32_t args[Instruction::kMaxVarArgRegs];
+ inst->GetVarArgs(args, inst_data);
+ VarArgsInstructionOperands all_operands(args, inst->VRegA_45cc());
+ NoReceiverInstructionOperands operands(&all_operands);
+ return DoVarHandleInvokeChecked(self,
+ var_handle,
+ callsite_type,
+ access_mode,
+ shadow_frame,
+ &operands,
+ result);
+ } else {
+ RangeInstructionOperands all_operands(inst->VRegC_4rcc(), inst->VRegA_4rcc());
+ NoReceiverInstructionOperands operands(&all_operands);
+ return DoVarHandleInvokeChecked(self,
+ var_handle,
+ callsite_type,
+ access_mode,
+ shadow_frame,
+ &operands,
+ result);
+ }
}
-bool DoVarHandleCompareAndExchangeAcquire(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+#define DO_VAR_HANDLE_ACCESSOR(_access_mode) \
+bool DoVarHandle ## _access_mode(Thread* self, \
+ ShadowFrame& shadow_frame, \
+ const Instruction* inst, \
+ uint16_t inst_data, \
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { \
+ const auto access_mode = mirror::VarHandle::AccessMode::k ## _access_mode; \
+ return DoVarHandleInvokeCommon(self, shadow_frame, inst, inst_data, result, access_mode); \
}
-bool DoVarHandleCompareAndExchangeRelease(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
+DO_VAR_HANDLE_ACCESSOR(CompareAndExchange)
+DO_VAR_HANDLE_ACCESSOR(CompareAndExchangeAcquire)
+DO_VAR_HANDLE_ACCESSOR(CompareAndExchangeRelease)
+DO_VAR_HANDLE_ACCESSOR(CompareAndSet)
+DO_VAR_HANDLE_ACCESSOR(Get)
+DO_VAR_HANDLE_ACCESSOR(GetAcquire)
+DO_VAR_HANDLE_ACCESSOR(GetAndAdd)
+DO_VAR_HANDLE_ACCESSOR(GetAndAddAcquire)
+DO_VAR_HANDLE_ACCESSOR(GetAndAddRelease)
+DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseAnd)
+DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseAndAcquire)
+DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseAndRelease)
+DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseOr)
+DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseOrAcquire)
+DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseOrRelease)
+DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseXor)
+DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseXorAcquire)
+DO_VAR_HANDLE_ACCESSOR(GetAndBitwiseXorRelease)
+DO_VAR_HANDLE_ACCESSOR(GetAndSet)
+DO_VAR_HANDLE_ACCESSOR(GetAndSetAcquire)
+DO_VAR_HANDLE_ACCESSOR(GetAndSetRelease)
+DO_VAR_HANDLE_ACCESSOR(GetOpaque)
+DO_VAR_HANDLE_ACCESSOR(GetVolatile)
+DO_VAR_HANDLE_ACCESSOR(Set)
+DO_VAR_HANDLE_ACCESSOR(SetOpaque)
+DO_VAR_HANDLE_ACCESSOR(SetRelease)
+DO_VAR_HANDLE_ACCESSOR(SetVolatile)
+DO_VAR_HANDLE_ACCESSOR(WeakCompareAndSet)
+DO_VAR_HANDLE_ACCESSOR(WeakCompareAndSetAcquire)
+DO_VAR_HANDLE_ACCESSOR(WeakCompareAndSetPlain)
+DO_VAR_HANDLE_ACCESSOR(WeakCompareAndSetRelease)
-bool DoVarHandleCompareAndSet(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGet(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAcquire(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndAdd(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndAddAcquire(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndAddRelease(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndBitwiseAnd(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndBitwiseAndAcquire(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndBitwiseAndRelease(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndBitwiseOr(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndBitwiseOrAcquire(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndBitwiseOrRelease(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndBitwiseXor(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndBitwiseXorAcquire(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndBitwiseXorRelease(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndSet(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndSetAcquire(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetAndSetRelease(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetOpaque(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleGetVolatile(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleSet(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleSetOpaque(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleSetRelease(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleSetVolatile(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleWeakCompareAndSet(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleWeakCompareAndSetAcquire(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleWeakCompareAndSetPlain(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
-
-bool DoVarHandleWeakCompareAndSetRelease(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
- return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
-}
+#undef DO_VAR_HANDLE_ACCESSOR
template<bool is_range>
bool DoInvokePolymorphic(Thread* self,
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 2701ec6..9b21e1d 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -346,7 +346,7 @@
return false;
}
- ShadowFrameGetter getter(operands, caller_frame);
+ ShadowFrameGetter getter(caller_frame, operands);
ShadowFrameSetter setter(callee_frame, first_dest_reg);
return PerformConversions<ShadowFrameGetter, ShadowFrameSetter>(self,
callsite_type,
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index 6ffd1a8..3b1bf2e 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -130,8 +130,10 @@
// arguments while performing standard argument conversions.
class ShadowFrameGetter {
public:
- ShadowFrameGetter(const InstructionOperands* const operands, const ShadowFrame& shadow_frame)
- : operands_(operands), operand_index_(0), shadow_frame_(shadow_frame) {}
+ ShadowFrameGetter(const ShadowFrame& shadow_frame,
+ const InstructionOperands* const operands,
+ size_t operand_index = 0u)
+ : shadow_frame_(shadow_frame), operands_(operands), operand_index_(operand_index) {}
ALWAYS_INLINE uint32_t Get() REQUIRES_SHARED(Locks::mutator_lock_) {
return shadow_frame_.GetVReg(Next());
@@ -151,26 +153,24 @@
operand_index_ += 1;
return next;
}
+
uint32_t NextLong() {
const uint32_t next = operands_->GetOperand(operand_index_);
operand_index_ += 2;
return next;
}
- const InstructionOperands* const operands_;
- size_t operand_index_; // the next register operand to read from frame
const ShadowFrame& shadow_frame_;
+ const InstructionOperands* const operands_; // the set of register operands to read
+ size_t operand_index_; // the next register operand to read from frame
};
// A convenience class that allows values to be written to a given shadow frame,
// starting at location |first_dst_reg|.
class ShadowFrameSetter {
public:
- ShadowFrameSetter(ShadowFrame* shadow_frame,
- size_t first_dst_reg) :
- shadow_frame_(shadow_frame),
- arg_index_(first_dst_reg) {
- }
+ ShadowFrameSetter(ShadowFrame* shadow_frame, size_t first_dst_reg)
+ : shadow_frame_(shadow_frame), arg_index_(first_dst_reg) {}
ALWAYS_INLINE void Set(uint32_t value) REQUIRES_SHARED(Locks::mutator_lock_) {
shadow_frame_->SetVReg(arg_index_++, value);
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
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index afb3224..3e9dfd1 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4432,6 +4432,8 @@
expected_return_descriptor = mirror::MethodHandle::GetReturnTypeDescriptor(method_name);
} else if (klass == mirror::VarHandle::StaticClass()) {
expected_return_descriptor = mirror::VarHandle::GetReturnTypeDescriptor(method_name);
+ // TODO: add compiler support for VarHandle accessor methods (b/71781600)
+ Fail(VERIFY_ERROR_FORCE_INTERPRETER);
} else {
Fail(VERIFY_ERROR_BAD_CLASS_HARD)
<< "Signature polymorphic method in unsuppported class: " << klass->PrettyDescriptor();
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 5fe10f5..902c3b8 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -72,6 +72,7 @@
jclass WellKnownClasses::java_lang_Thread;
jclass WellKnownClasses::java_lang_ThreadGroup;
jclass WellKnownClasses::java_lang_Throwable;
+jclass WellKnownClasses::java_nio_ByteBuffer;
jclass WellKnownClasses::java_nio_DirectByteBuffer;
jclass WellKnownClasses::java_util_ArrayList;
jclass WellKnownClasses::java_util_Collections;
@@ -142,6 +143,11 @@
jfieldID WellKnownClasses::java_lang_Throwable_suppressedExceptions;
jfieldID WellKnownClasses::java_lang_reflect_Executable_artMethod;
jfieldID WellKnownClasses::java_lang_reflect_Proxy_h;
+jfieldID WellKnownClasses::java_nio_ByteBuffer_address;
+jfieldID WellKnownClasses::java_nio_ByteBuffer_hb;
+jfieldID WellKnownClasses::java_nio_ByteBuffer_isReadOnly;
+jfieldID WellKnownClasses::java_nio_ByteBuffer_limit;
+jfieldID WellKnownClasses::java_nio_ByteBuffer_offset;
jfieldID WellKnownClasses::java_nio_DirectByteBuffer_capacity;
jfieldID WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress;
jfieldID WellKnownClasses::java_util_ArrayList_array;
@@ -318,6 +324,7 @@
java_lang_Thread = CacheClass(env, "java/lang/Thread");
java_lang_ThreadGroup = CacheClass(env, "java/lang/ThreadGroup");
java_lang_Throwable = CacheClass(env, "java/lang/Throwable");
+ java_nio_ByteBuffer = CacheClass(env, "java/nio/ByteBuffer");
java_nio_DirectByteBuffer = CacheClass(env, "java/nio/DirectByteBuffer");
java_util_ArrayList = CacheClass(env, "java/util/ArrayList");
java_util_Collections = CacheClass(env, "java/util/Collections");
@@ -379,6 +386,11 @@
java_lang_Throwable_stackState = CacheField(env, java_lang_Throwable, false, "backtrace", "Ljava/lang/Object;");
java_lang_Throwable_suppressedExceptions = CacheField(env, java_lang_Throwable, false, "suppressedExceptions", "Ljava/util/List;");
java_lang_reflect_Executable_artMethod = CacheField(env, java_lang_reflect_Executable, false, "artMethod", "J");
+ java_nio_ByteBuffer_address = CacheField(env, java_nio_ByteBuffer, false, "address", "J");
+ java_nio_ByteBuffer_hb = CacheField(env, java_nio_ByteBuffer, false, "hb", "[B");
+ java_nio_ByteBuffer_isReadOnly = CacheField(env, java_nio_ByteBuffer, false, "isReadOnly", "Z");
+ java_nio_ByteBuffer_limit = CacheField(env, java_nio_ByteBuffer, false, "limit", "I");
+ java_nio_ByteBuffer_offset = CacheField(env, java_nio_ByteBuffer, false, "offset", "I");
java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I");
java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "address", "J");
java_util_ArrayList_array = CacheField(env, java_util_ArrayList, false, "elementData", "[Ljava/lang/Object;");
@@ -462,6 +474,7 @@
java_lang_Throwable = nullptr;
java_util_ArrayList = nullptr;
java_util_Collections = nullptr;
+ java_nio_ByteBuffer = nullptr;
java_nio_DirectByteBuffer = nullptr;
libcore_reflect_AnnotationFactory = nullptr;
libcore_reflect_AnnotationMember = nullptr;
@@ -530,6 +543,11 @@
java_lang_Throwable_stackTrace = nullptr;
java_lang_Throwable_stackState = nullptr;
java_lang_Throwable_suppressedExceptions = nullptr;
+ java_nio_ByteBuffer_address = nullptr;
+ java_nio_ByteBuffer_hb = nullptr;
+ java_nio_ByteBuffer_isReadOnly = nullptr;
+ java_nio_ByteBuffer_limit = nullptr;
+ java_nio_ByteBuffer_offset = nullptr;
java_nio_DirectByteBuffer_capacity = nullptr;
java_nio_DirectByteBuffer_effectiveDirectAddress = nullptr;
java_util_ArrayList_array = nullptr;
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 9e0b079..d5d7033 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -85,6 +85,7 @@
static jclass java_lang_Throwable;
static jclass java_util_ArrayList;
static jclass java_util_Collections;
+ static jclass java_nio_ByteBuffer;
static jclass java_nio_DirectByteBuffer;
static jclass libcore_reflect_AnnotationFactory;
static jclass libcore_reflect_AnnotationMember;
@@ -153,8 +154,14 @@
static jfieldID java_lang_Throwable_stackTrace;
static jfieldID java_lang_Throwable_stackState;
static jfieldID java_lang_Throwable_suppressedExceptions;
+ static jfieldID java_nio_ByteBuffer_address;
+ static jfieldID java_nio_ByteBuffer_hb;
+ static jfieldID java_nio_ByteBuffer_isReadOnly;
+ static jfieldID java_nio_ByteBuffer_limit;
+ static jfieldID java_nio_ByteBuffer_offset;
static jfieldID java_nio_DirectByteBuffer_capacity;
static jfieldID java_nio_DirectByteBuffer_effectiveDirectAddress;
+
static jfieldID java_util_ArrayList_array;
static jfieldID java_util_ArrayList_size;
static jfieldID java_util_Collections_EMPTY_LIST;