Reland "Use nterp cache for fields in switch interpreter."
This reverts commit 6f78517b8de12bac6fc2015ffaaab712347aea59.
Reason for revert: Fix in https://android-review.googlesource.com/c/platform/art/+/2267547.
Change-Id: If33e6d7e7a6852aa36e3b9da96e88c3a5b3f01a8
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 91c2663..847cbfb 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -376,76 +376,77 @@
allocator_type);
}
-template<FindFieldType type, bool access_check>
+FLATTEN
+inline ArtField* ResolveFieldWithAccessChecks(Thread* self,
+ ClassLinker* class_linker,
+ uint16_t field_index,
+ ArtMethod* caller,
+ bool is_static,
+ bool is_put,
+ size_t resolve_field_type) // Resolve if not zero
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (caller->SkipAccessChecks()) {
+ return class_linker->ResolveField(field_index, caller, is_static);
+ }
+
+ caller = caller->GetInterfaceMethodIfProxy(class_linker->GetImagePointerSize());
+
+ StackHandleScope<2> hs(self);
+ Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(caller->GetDexCache()));
+ Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(caller->GetClassLoader()));
+
+ ArtField* resolved_field = class_linker->ResolveFieldJLS(field_index,
+ h_dex_cache,
+ h_class_loader);
+ if (resolved_field == nullptr) {
+ return nullptr;
+ }
+
+ ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
+ if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
+ ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, caller);
+ return nullptr;
+ }
+ ObjPtr<mirror::Class> referring_class = caller->GetDeclaringClass();
+ if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class,
+ resolved_field,
+ caller->GetDexCache(),
+ field_index))) {
+ DCHECK(self->IsExceptionPending());
+ return nullptr;
+ }
+ if (UNLIKELY(is_put && !resolved_field->CanBeChangedBy(caller))) {
+ ThrowIllegalAccessErrorFinalField(caller, resolved_field);
+ return nullptr;
+ }
+
+ if (resolve_field_type != 0u) {
+ StackArtFieldHandleScope<1> rhs(self);
+ ReflectiveHandle<ArtField> field_handle(rhs.NewHandle(resolved_field));
+ if (resolved_field->ResolveType().IsNull()) {
+ DCHECK(self->IsExceptionPending());
+ return nullptr;
+ }
+ resolved_field = field_handle.Get();
+ }
+ return resolved_field;
+}
+
+template<FindFieldType type>
inline ArtField* FindFieldFromCode(uint32_t field_idx,
ArtMethod* referrer,
Thread* self,
- size_t expected_size) {
- constexpr bool is_primitive = (type & FindFieldFlags::PrimitiveBit) != 0;
+ bool should_resolve_type = false) {
constexpr bool is_set = (type & FindFieldFlags::WriteBit) != 0;
constexpr bool is_static = (type & FindFieldFlags::StaticBit) != 0;
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-
- ArtField* resolved_field;
- if (access_check) {
- // Slow path: According to JLS 13.4.8, a linkage error may occur if a compile-time
- // qualifying type of a field and the resolved run-time qualifying type of a field differed
- // in their static-ness.
- //
- // In particular, don't assume the dex instruction already correctly knows if the
- // real field is static or not. The resolution must not be aware of this.
- ArtMethod* method = referrer->GetInterfaceMethodIfProxy(kRuntimePointerSize);
-
- StackHandleScope<2> hs(self);
- Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(method->GetDexCache()));
- Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(method->GetClassLoader()));
-
- resolved_field = class_linker->ResolveFieldJLS(field_idx,
- h_dex_cache,
- h_class_loader);
- } else {
- // Fast path: Verifier already would've called ResolveFieldJLS and we wouldn't
- // be executing here if there was a static/non-static mismatch.
- resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
- }
-
- if (UNLIKELY(resolved_field == nullptr)) {
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
- return nullptr; // Failure.
- }
- ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
- if (access_check) {
- if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
- ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer);
- return nullptr;
- }
- ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
- if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class,
- resolved_field,
- referrer->GetDexCache(),
- field_idx))) {
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
- return nullptr; // Failure.
- }
- if (UNLIKELY(is_set && !resolved_field->CanBeChangedBy(referrer))) {
- ThrowIllegalAccessErrorFinalField(referrer, resolved_field);
- return nullptr; // Failure.
- } else {
- if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
- resolved_field->FieldSize() != expected_size)) {
- self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
- "Attempted read of %zd-bit %s on field '%s'",
- expected_size * (32 / sizeof(int32_t)),
- is_primitive ? "primitive" : "non-primitive",
- resolved_field->PrettyField(true).c_str());
- return nullptr; // Failure.
- }
- }
- }
- if (!is_static) {
+ ArtField* resolved_field = ResolveFieldWithAccessChecks(
+ self, class_linker, field_idx, referrer, is_static, is_set, should_resolve_type ? 1u : 0u);
+ if (!is_static || resolved_field == nullptr) {
// instance fields must be being accessed on an initialized class
return resolved_field;
} else {
+ ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
// If the class is initialized we're done.
if (LIKELY(fields_class->IsVisiblyInitialized())) {
return resolved_field;
@@ -463,28 +464,26 @@
}
}
+// NOLINTBEGIN(bugprone-macro-parentheses)
// Explicit template declarations of FindFieldFromCode for all field access types.
-#define EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \
+#define EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type) \
template REQUIRES_SHARED(Locks::mutator_lock_) ALWAYS_INLINE \
-ArtField* FindFieldFromCode<_type, _access_check>(uint32_t field_idx, \
- ArtMethod* referrer, \
- Thread* self, size_t expected_size) \
+ArtField* FindFieldFromCode<_type>(uint32_t field_idx, \
+ ArtMethod* referrer, \
+ Thread* self, \
+ bool should_resolve_type = false) \
-#define EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
- EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, false); \
- EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, true)
+EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(InstanceObjectRead);
+EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(InstanceObjectWrite);
+EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(InstancePrimitiveRead);
+EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(InstancePrimitiveWrite);
+EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(StaticObjectRead);
+EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(StaticObjectWrite);
+EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(StaticPrimitiveRead);
+EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(StaticPrimitiveWrite);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectRead);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectWrite);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveRead);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveWrite);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectRead);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectWrite);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveRead);
-EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveWrite);
-
-#undef EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL
#undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
+// NOLINTEND(bugprone-macro-parentheses)
static inline bool IsStringInit(const DexFile* dex_file, uint32_t method_idx)
REQUIRES_SHARED(Locks::mutator_lock_) {
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index 81a9e21..e2fc232 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -32,7 +32,7 @@
inline ArtField* FindFieldFast(uint32_t field_idx,
ArtMethod* referrer,
FindFieldType type,
- size_t expected_size)
+ bool should_resolve_type = false)
REQUIRES(!Roles::uninterruptible_)
REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedAssertNoThreadSuspension ants(__FUNCTION__);
@@ -41,7 +41,6 @@
return nullptr;
}
// Check for incompatible class change.
- const bool is_primitive = (type & FindFieldFlags::PrimitiveBit) != 0;
const bool is_set = (type & FindFieldFlags::WriteBit) != 0;
const bool is_static = (type & FindFieldFlags::StaticBit) != 0;
if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
@@ -63,8 +62,7 @@
// Illegal access.
return nullptr;
}
- if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive ||
- resolved_field->FieldSize() != expected_size)) {
+ if (should_resolve_type && resolved_field->LookupResolvedType() == nullptr) {
return nullptr;
}
return resolved_field;
@@ -73,17 +71,17 @@
// Helper function to do a null check after trying to resolve the field. Not for statics since obj
// does not exist there. There is a suspend check, object is a double pointer to update the value
// in the caller in case it moves.
-template<FindFieldType type, bool kAccessCheck>
+template<FindFieldType type>
ALWAYS_INLINE static inline ArtField* FindInstanceField(uint32_t field_idx,
ArtMethod* referrer,
Thread* self,
- size_t size,
- mirror::Object** obj)
+ mirror::Object** obj,
+ bool should_resolve_type = false)
REQUIRES(!Roles::uninterruptible_)
REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(obj));
- ArtField* field = FindFieldFromCode<type, kAccessCheck>(field_idx, referrer, self, size);
+ ArtField* field = FindFieldFromCode<type>(field_idx, referrer, self, should_resolve_type);
if (LIKELY(field != nullptr) && UNLIKELY(h == nullptr)) {
ThrowNullPointerExceptionForFieldAccess(field, referrer, (type & FindFieldFlags::ReadBit) != 0);
return nullptr;
@@ -116,13 +114,12 @@
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
ArtField* field = FindFieldFast( \
- field_idx, referrer, Static ## PrimitiveOrObject ## Read, \
- sizeof(PrimitiveType)); \
+ field_idx, referrer, Static ## PrimitiveOrObject ## Read); \
if (LIKELY(field != nullptr)) { \
return field->Get ## Kind (field->GetDeclaringClass())Ptr; /* NOLINT */ \
} \
- field = FindFieldFromCode<Static ## PrimitiveOrObject ## Read, true>( \
- field_idx, referrer, self, sizeof(PrimitiveType)); \
+ field = FindFieldFromCode<Static ## PrimitiveOrObject ## Read>( \
+ field_idx, referrer, self); \
if (LIKELY(field != nullptr)) { \
return field->Get ## Kind (field->GetDeclaringClass())Ptr; /* NOLINT */ \
} \
@@ -137,13 +134,12 @@
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
ArtField* field = FindFieldFast( \
- field_idx, referrer, Instance ## PrimitiveOrObject ## Read, \
- sizeof(PrimitiveType)); \
+ field_idx, referrer, Instance ## PrimitiveOrObject ## Read); \
if (LIKELY(field != nullptr) && obj != nullptr) { \
return field->Get ## Kind (obj)Ptr; /* NOLINT */ \
} \
- field = FindInstanceField<Instance ## PrimitiveOrObject ## Read, true>( \
- field_idx, referrer, self, sizeof(PrimitiveType), &obj); \
+ field = FindInstanceField<Instance ## PrimitiveOrObject ## Read>( \
+ field_idx, referrer, self, &obj); \
if (LIKELY(field != nullptr)) { \
return field->Get ## Kind (obj)Ptr; /* NOLINT */ \
} \
@@ -157,33 +153,30 @@
Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
+ bool should_resolve_type = (IsObject) && new_value != 0; \
ArtField* field = FindFieldFast( \
- field_idx, referrer, Static ## PrimitiveOrObject ## Write, \
- sizeof(PrimitiveType)); \
+ field_idx, \
+ referrer, \
+ Static ## PrimitiveOrObject ## Write, \
+ should_resolve_type); \
if (UNLIKELY(field == nullptr)) { \
if (IsObject) { \
StackHandleScope<1> hs(self); \
HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper( \
reinterpret_cast<mirror::Object**>(&new_value))); \
- field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write, true>( \
- field_idx, referrer, self, sizeof(PrimitiveType)); \
+ field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write>( \
+ field_idx, \
+ referrer, \
+ self, \
+ should_resolve_type); \
} else { \
- field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write, true>( \
- field_idx, referrer, self, sizeof(PrimitiveType)); \
+ field = FindFieldFromCode<Static ## PrimitiveOrObject ## Write>( \
+ field_idx, referrer, self); \
} \
if (UNLIKELY(field == nullptr)) { \
return -1; \
} \
} \
- if (!referrer->SkipAccessChecks() && (IsObject) && new_value != 0) { \
- StackArtFieldHandleScope<1> rhs(self); \
- ReflectiveHandle<ArtField> field_handle(rhs.NewHandle(field)); \
- if (field->ResolveType().IsNull()) { \
- self->AssertPendingException(); \
- return -1; \
- } \
- field = field_handle.Get(); \
- } \
field->Set ## Kind <false>(field->GetDeclaringClass(), new_value); \
return 0; \
} \
@@ -195,43 +188,31 @@
Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
+ bool should_resolve_type = (IsObject) && new_value != 0; \
ArtField* field = FindFieldFast( \
- field_idx, referrer, Instance ## PrimitiveOrObject ## Write, \
- sizeof(PrimitiveType)); \
+ field_idx, \
+ referrer, \
+ Instance ## PrimitiveOrObject ## Write, \
+ should_resolve_type); \
if (UNLIKELY(field == nullptr || obj == nullptr)) { \
if (IsObject) { \
StackHandleScope<1> hs(self); \
HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper( \
reinterpret_cast<mirror::Object**>(&new_value))); \
- field = \
- FindInstanceField<Instance ## PrimitiveOrObject ## Write, true>( \
- field_idx, \
- referrer, \
- self, \
- sizeof(PrimitiveType), \
- &obj); \
+ field = FindInstanceField<Instance ## PrimitiveOrObject ## Write>( \
+ field_idx, \
+ referrer, \
+ self, \
+ &obj, \
+ should_resolve_type); \
} else { \
- field = \
- FindInstanceField<Instance ## PrimitiveOrObject ## Write, true>( \
- field_idx, \
- referrer, \
- self, \
- sizeof(PrimitiveType), \
- &obj); \
+ field = FindInstanceField<Instance ## PrimitiveOrObject ## Write>( \
+ field_idx, referrer, self, &obj); \
} \
if (UNLIKELY(field == nullptr)) { \
return -1; \
} \
} \
- if (!referrer->SkipAccessChecks() && (IsObject) && new_value != 0) { \
- StackArtFieldHandleScope<1> rhs(self); \
- ReflectiveHandle<ArtField> field_handle(rhs.NewHandle(field)); \
- if (field->ResolveType().IsNull()) { \
- self->AssertPendingException(); \
- return -1; \
- } \
- field = field_handle.Get(); \
- } \
field->Set ## Kind<false>(obj, new_value); \
return 0; \
} \
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 49d7e64..64d4d71 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -346,24 +346,78 @@
return field_value;
}
+extern "C" size_t NterpGetStaticField(Thread* self,
+ ArtMethod* caller,
+ const uint16_t* dex_pc_ptr,
+ size_t resolve_field_type);
+
+extern "C" uint32_t NterpGetInstanceFieldOffset(Thread* self,
+ ArtMethod* caller,
+ const uint16_t* dex_pc_ptr,
+ size_t resolve_field_type);
+
+static inline void GetFieldInfo(Thread* self,
+ ArtMethod* caller,
+ const uint16_t* dex_pc_ptr,
+ bool is_static,
+ bool resolve_field_type,
+ ArtField** field,
+ bool* is_volatile,
+ MemberOffset* offset) {
+ size_t tls_value = 0u;
+ if (!self->GetInterpreterCache()->Get(self, dex_pc_ptr, &tls_value)) {
+ if (is_static) {
+ tls_value = NterpGetStaticField(self, caller, dex_pc_ptr, resolve_field_type);
+ } else {
+ tls_value = NterpGetInstanceFieldOffset(self, caller, dex_pc_ptr, resolve_field_type);
+ }
+
+ if (self->IsExceptionPending()) {
+ return;
+ }
+ }
+
+ if (is_static) {
+ DCHECK_NE(tls_value, 0u);
+ *is_volatile = ((tls_value & 1) != 0);
+ *field = reinterpret_cast<ArtField*>(tls_value & ~static_cast<size_t>(1u));
+ *offset = (*field)->GetOffset();
+ } else {
+ *is_volatile = (static_cast<int32_t>(tls_value) < 0);
+ *offset = MemberOffset(std::abs(static_cast<int32_t>(tls_value)));
+ }
+}
+
// 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 do_access_check,
+template<FindFieldType find_type,
+ Primitive::Type field_type,
+ bool do_access_check,
bool transaction_active = false>
-ALWAYS_INLINE bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst,
+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);
- const uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
- ArtMethod* method = shadow_frame.GetMethod();
- ArtField* f = FindFieldFromCode<find_type, do_access_check>(
- field_idx, method, self, Primitive::ComponentSize(field_type));
- if (UNLIKELY(f == nullptr)) {
- CHECK(self->IsExceptionPending());
+ 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 = f->GetDeclaringClass();
+ obj = field->GetDeclaringClass();
if (transaction_active) {
if (Runtime::Current()->GetTransaction()->ReadConstraint(obj)) {
Runtime::Current()->AbortTransactionAndThrowAbortError(self, "Can't read static fields of "
@@ -373,40 +427,57 @@
}
} else {
obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
- if (UNLIKELY(obj == nullptr)) {
- ThrowNullPointerExceptionForFieldAccess(f, method, true);
+ 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;
}
}
- JValue result;
- if (UNLIKELY(!DoFieldGetCommon<field_type>(self, shadow_frame, obj, f, &result))) {
- // Instrumentation threw an error!
- CHECK(self->IsExceptionPending());
- return false;
- }
- uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
+#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) {
- case Primitive::kPrimBoolean:
- shadow_frame.SetVReg(vregA, result.GetZ());
- break;
- case Primitive::kPrimByte:
- shadow_frame.SetVReg(vregA, result.GetB());
- break;
- case Primitive::kPrimChar:
- shadow_frame.SetVReg(vregA, result.GetC());
- break;
- case Primitive::kPrimShort:
- shadow_frame.SetVReg(vregA, result.GetS());
- break;
- case Primitive::kPrimInt:
- shadow_frame.SetVReg(vregA, result.GetI());
- break;
- case Primitive::kPrimLong:
- shadow_frame.SetVRegLong(vregA, result.GetJ());
- break;
+ 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, result.GetL());
+ 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;
@@ -447,34 +518,57 @@
// Returns true on success, otherwise throws an exception and returns false.
template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check,
bool transaction_active>
-ALWAYS_INLINE bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
- const Instruction* inst, uint16_t inst_data)
+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();
const bool do_assignability_check = do_access_check;
bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite);
- uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c();
- ArtMethod* method = shadow_frame.GetMethod();
- ArtField* f = FindFieldFromCode<find_type, do_access_check>(
- field_idx, method, self, Primitive::ComponentSize(field_type));
- if (UNLIKELY(f == nullptr)) {
- CHECK(self->IsExceptionPending());
+ 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 = f->GetDeclaringClass();
+ obj = field->GetDeclaringClass();
} else {
obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
- if (UNLIKELY(obj == nullptr)) {
- ThrowNullPointerExceptionForFieldAccess(f, method, false);
- return false;
+ 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));
}
}
if (transaction_active && !CheckWriteConstraint(self, obj)) {
return false;
}
- uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
JValue value = GetFieldValue<field_type>(shadow_frame, vregA);
if (transaction_active &&
@@ -482,12 +576,43 @@
!CheckWriteValueConstraint(self, value.GetL())) {
return false;
}
+ if (should_report) {
+ return DoFieldPutCommon<field_type, do_assignability_check, 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;
- return DoFieldPutCommon<field_type, do_assignability_check, transaction_active>(self,
- shadow_frame,
- obj,
- f,
- value);
+ 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;
}
// Handles string resolution for const-string and const-string-jumbo instructions. Also ensures the
diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc
index e58d77d..cb3cf12 100644
--- a/runtime/interpreter/mterp/nterp.cc
+++ b/runtime/interpreter/mterp/nterp.cc
@@ -379,58 +379,9 @@
}
}
-FLATTEN
-static ArtField* ResolveFieldWithAccessChecks(Thread* self,
- ClassLinker* class_linker,
- uint16_t field_index,
- ArtMethod* caller,
- bool is_static,
- bool is_put,
- size_t resolve_field_type) // Resolve if not zero
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (caller->SkipAccessChecks()) {
- return class_linker->ResolveField(field_index, caller, is_static);
- }
-
- caller = caller->GetInterfaceMethodIfProxy(kRuntimePointerSize);
-
- StackHandleScope<2> hs(self);
- Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(caller->GetDexCache()));
- Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(caller->GetClassLoader()));
-
- ArtField* resolved_field = class_linker->ResolveFieldJLS(field_index,
- h_dex_cache,
- h_class_loader);
- if (resolved_field == nullptr) {
- return nullptr;
- }
-
- ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
- if (UNLIKELY(resolved_field->IsStatic() != is_static)) {
- ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, caller);
- return nullptr;
- }
- ObjPtr<mirror::Class> referring_class = caller->GetDeclaringClass();
- if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class,
- resolved_field,
- caller->GetDexCache(),
- field_index))) {
- return nullptr;
- }
- if (UNLIKELY(is_put && !resolved_field->CanBeChangedBy(caller))) {
- ThrowIllegalAccessErrorFinalField(caller, resolved_field);
- return nullptr;
- }
- if (resolve_field_type != 0u && resolved_field->ResolveType() == nullptr) {
- DCHECK(self->IsExceptionPending());
- return nullptr;
- }
- return resolved_field;
-}
-
extern "C" size_t NterpGetStaticField(Thread* self,
ArtMethod* caller,
- uint16_t* dex_pc_ptr,
+ const uint16_t* dex_pc_ptr,
size_t resolve_field_type) // Resolve if not zero
REQUIRES_SHARED(Locks::mutator_lock_) {
UpdateHotness(caller);
@@ -483,7 +434,7 @@
extern "C" uint32_t NterpGetInstanceFieldOffset(Thread* self,
ArtMethod* caller,
- uint16_t* dex_pc_ptr,
+ const uint16_t* dex_pc_ptr,
size_t resolve_field_type) // Resolve if not zero
REQUIRES_SHARED(Locks::mutator_lock_) {
UpdateHotness(caller);
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index f67f6f3..7edeacb 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -424,10 +424,12 @@
ASSERT_TRUE(field_id != nullptr);
uint32_t field_idx = dex_file->GetIndexForFieldId(*field_id);
- ArtField* field = FindFieldFromCode<StaticObjectRead, true>(field_idx, clinit, Thread::Current(),
- sizeof(HeapReference<Object>));
+ ArtField* field = FindFieldFromCode<StaticObjectRead>(field_idx,
+ clinit,
+ Thread::Current(),
+ sizeof(HeapReference<Object>));
ObjPtr<Object> s0 = field->GetObj(klass.Get());
- EXPECT_TRUE(s0 != nullptr);
+ EXPECT_TRUE(s0 != nullptr) << field->PrettyField();
Handle<CharArray> char_array(hs.NewHandle(CharArray::Alloc(soa.Self(), 0)));
field->SetObj<false>(field->GetDeclaringClass(), char_array.Get());