summaryrefslogtreecommitdiff
path: root/runtime/interpreter/interpreter_switch_impl-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/interpreter/interpreter_switch_impl-inl.h')
-rw-r--r--runtime/interpreter/interpreter_switch_impl-inl.h200
1 files changed, 200 insertions, 0 deletions
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index ce0117f724..35708b00c6 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -44,6 +44,206 @@
namespace art HIDDEN {
namespace interpreter {
+// We declare the helpers classes for transaction checks here but they shall be defined
+// only when compiling the transactional and non-transactional interpreter.
+class ActiveTransactionChecker; // For transactional interpreter.
+class InactiveTransactionChecker; // For non-transactional interpreter.
+
+// Handles iget-XXX and sget-XXX instructions.
+// Returns true on success, otherwise throws an exception and returns false.
+template<FindFieldType find_type,
+ Primitive::Type field_type,
+ bool transaction_active = false>
+ALWAYS_INLINE bool DoFieldGet(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data) REQUIRES_SHARED(Locks::mutator_lock_) {
+ const bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead);
+ bool should_report = Runtime::Current()->GetInstrumentation()->HasFieldReadListeners();
+ ArtField* field = nullptr;
+ MemberOffset offset(0u);
+ bool is_volatile;
+ GetFieldInfo(self,
+ shadow_frame.GetMethod(),
+ reinterpret_cast<const uint16_t*>(inst),
+ is_static,
+ /*resolve_field_type=*/ false,
+ &field,
+ &is_volatile,
+ &offset);
+ if (self->IsExceptionPending()) {
+ return false;
+ }
+
+ ObjPtr<mirror::Object> obj;
+ if (is_static) {
+ obj = field->GetDeclaringClass();
+ using TransactionChecker = typename std::conditional_t<
+ transaction_active, ActiveTransactionChecker, InactiveTransactionChecker>;
+ if (TransactionChecker::ReadConstraint(self, obj)) {
+ return false;
+ }
+ } else {
+ obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
+ if (should_report || obj == nullptr) {
+ field = ResolveFieldWithAccessChecks(self,
+ Runtime::Current()->GetClassLinker(),
+ inst->VRegC_22c(),
+ shadow_frame.GetMethod(),
+ /* is_static= */ false,
+ /* is_put= */ false,
+ /* resolve_field_type= */ false);
+ if (obj == nullptr) {
+ ThrowNullPointerExceptionForFieldAccess(
+ field, shadow_frame.GetMethod(), /* is_read= */ true);
+ return false;
+ }
+ // Reload in case suspension happened during field resolution.
+ obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
+ }
+ }
+
+ uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
+ JValue result;
+ if (should_report) {
+ DCHECK(field != nullptr);
+ if (UNLIKELY(!DoFieldGetCommon<field_type>(self, shadow_frame, obj, field, &result))) {
+ // Instrumentation threw an error!
+ CHECK(self->IsExceptionPending());
+ return false;
+ }
+ }
+
+#define FIELD_GET(prim, type, jtype, vreg) \
+ case Primitive::kPrim ##prim: \
+ shadow_frame.SetVReg ##vreg(vregA, \
+ should_report ? result.Get ##jtype() \
+ : is_volatile ? obj->GetField ## type ## Volatile(offset) \
+ : obj->GetField ##type(offset)); \
+ break;
+
+ switch (field_type) {
+ FIELD_GET(Boolean, Boolean, Z, )
+ FIELD_GET(Byte, Byte, B, )
+ FIELD_GET(Char, Char, C, )
+ FIELD_GET(Short, Short, S, )
+ FIELD_GET(Int, 32, I, )
+ FIELD_GET(Long, 64, J, Long)
+#undef FIELD_GET
+ case Primitive::kPrimNot:
+ shadow_frame.SetVRegReference(
+ vregA,
+ should_report ? result.GetL()
+ : is_volatile ? obj->GetFieldObjectVolatile<mirror::Object>(offset)
+ : obj->GetFieldObject<mirror::Object>(offset));
+ break;
+ default:
+ LOG(FATAL) << "Unreachable: " << field_type;
+ UNREACHABLE();
+ }
+ return true;
+}
+
+// Handles iput-XXX and sput-XXX instructions.
+// Returns true on success, otherwise throws an exception and returns false.
+template<FindFieldType find_type, Primitive::Type field_type, bool transaction_active>
+ALWAYS_INLINE bool DoFieldPut(Thread* self,
+ const ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ bool should_report = Runtime::Current()->GetInstrumentation()->HasFieldWriteListeners();
+ bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
+ uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
+ bool resolve_field_type = (shadow_frame.GetVRegReference(vregA) != nullptr);
+ ArtField* field = nullptr;
+ MemberOffset offset(0u);
+ bool is_volatile;
+ GetFieldInfo(self,
+ shadow_frame.GetMethod(),
+ reinterpret_cast<const uint16_t*>(inst),
+ is_static,
+ resolve_field_type,
+ &field,
+ &is_volatile,
+ &offset);
+ if (self->IsExceptionPending()) {
+ return false;
+ }
+
+ ObjPtr<mirror::Object> obj;
+ if (is_static) {
+ obj = field->GetDeclaringClass();
+ } else {
+ obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
+ if (should_report || obj == nullptr) {
+ field = ResolveFieldWithAccessChecks(self,
+ Runtime::Current()->GetClassLinker(),
+ inst->VRegC_22c(),
+ shadow_frame.GetMethod(),
+ /* is_static= */ false,
+ /* is_put= */ true,
+ resolve_field_type);
+ if (UNLIKELY(obj == nullptr)) {
+ ThrowNullPointerExceptionForFieldAccess(
+ field, shadow_frame.GetMethod(), /* is_read= */ false);
+ return false;
+ }
+ // Reload in case suspension happened during field resolution.
+ obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
+ }
+ }
+ using TransactionChecker = typename std::conditional_t<
+ transaction_active, ActiveTransactionChecker, InactiveTransactionChecker>;
+ if (TransactionChecker::WriteConstraint(self, obj)) {
+ return false;
+ }
+
+ JValue value = GetFieldValue<field_type>(shadow_frame, vregA);
+
+ if (field_type == Primitive::kPrimNot &&
+ TransactionChecker::WriteValueConstraint(self, value.GetL())) {
+ return false;
+ }
+ if (should_report) {
+ return DoFieldPutCommon<field_type, transaction_active>(self,
+ shadow_frame,
+ obj,
+ field,
+ value);
+ }
+#define FIELD_SET(prim, type, jtype) \
+ case Primitive::kPrim ## prim: \
+ if (is_volatile) { \
+ obj->SetField ## type ## Volatile<transaction_active>(offset, value.Get ## jtype()); \
+ } else { \
+ obj->SetField ## type<transaction_active>(offset, value.Get ## jtype()); \
+ } \
+ break;
+
+ switch (field_type) {
+ FIELD_SET(Boolean, Boolean, Z)
+ FIELD_SET(Byte, Byte, B)
+ FIELD_SET(Char, Char, C)
+ FIELD_SET(Short, Short, S)
+ FIELD_SET(Int, 32, I)
+ FIELD_SET(Long, 64, J)
+ FIELD_SET(Not, Object, L)
+ case Primitive::kPrimVoid: {
+ LOG(FATAL) << "Unreachable " << field_type;
+ break;
+ }
+ }
+#undef FIELD_SET
+
+ if (transaction_active) {
+ if (UNLIKELY(self->IsExceptionPending())) {
+ return false;
+ }
+ }
+ return true;
+}
+
// Short-lived helper class which executes single DEX bytecode. It is inlined by compiler.
// Any relevant execution information is stored in the fields - it should be kept to minimum.
// All instance functions must be inlined so that the fields can be stored in registers.