diff options
-rw-r--r-- | runtime/interpreter/interpreter_common.h | 74 | ||||
-rw-r--r-- | runtime/jdwp/jdwp_event.cc | 13 | ||||
-rw-r--r-- | runtime/jdwp/jdwp_handler.cc | 4 | ||||
-rw-r--r-- | runtime/mirror/art_field.cc | 21 | ||||
-rw-r--r-- | runtime/mirror/art_field.h | 4 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 31 |
6 files changed, 116 insertions, 31 deletions
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 65bdf0e..cc1fa0c 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -169,6 +169,13 @@ static inline bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, return false; } } + // Report this field access to instrumentation if needed. + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (UNLIKELY(instrumentation->HasFieldReadListeners())) { + Object* this_object = f->IsStatic() ? nullptr : obj; + instrumentation->FieldReadEvent(self, this_object, shadow_frame.GetMethod(), + shadow_frame.GetDexPC(), f); + } uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data); switch (field_type) { case Primitive::kPrimBoolean: @@ -210,6 +217,17 @@ static inline bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* ins return false; } MemberOffset field_offset(inst->VRegC_22c()); + // Report this field access to instrumentation if needed. Since we only have the offset of + // the field from the base of the object, we need to look for it first. + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (UNLIKELY(instrumentation->HasFieldReadListeners())) { + ArtField* f = ArtField::FindInstanceFieldWithOffset(obj->GetClass(), + field_offset.Uint32Value()); + DCHECK(f != nullptr); + DCHECK(!f->IsStatic()); + instrumentation->FieldReadEvent(Thread::Current(), obj, shadow_frame.GetMethod(), + shadow_frame.GetDexPC(), f); + } const bool is_volatile = false; // iget-x-quick only on non volatile fields. const uint32_t vregA = inst->VRegA_22c(inst_data); switch (field_type) { @@ -228,6 +246,39 @@ static inline bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* ins return true; } +template<Primitive::Type field_type> +static inline JValue GetFieldValue(const ShadowFrame& shadow_frame, uint32_t vreg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + JValue field_value; + switch (field_type) { + case Primitive::kPrimBoolean: + field_value.SetZ(static_cast<uint8_t>(shadow_frame.GetVReg(vreg))); + break; + case Primitive::kPrimByte: + field_value.SetB(static_cast<int8_t>(shadow_frame.GetVReg(vreg))); + break; + case Primitive::kPrimChar: + field_value.SetC(static_cast<uint16_t>(shadow_frame.GetVReg(vreg))); + break; + case Primitive::kPrimShort: + field_value.SetS(static_cast<int16_t>(shadow_frame.GetVReg(vreg))); + break; + case Primitive::kPrimInt: + field_value.SetI(shadow_frame.GetVReg(vreg)); + break; + case Primitive::kPrimLong: + field_value.SetJ(shadow_frame.GetVRegLong(vreg)); + break; + case Primitive::kPrimNot: + field_value.SetL(shadow_frame.GetVRegReference(vreg)); + break; + default: + LOG(FATAL) << "Unreachable: " << field_type; + break; + } + return field_value; +} + // 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 do_access_check, bool transaction_active> @@ -254,6 +305,15 @@ static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, } } uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data); + // Report this field access to instrumentation if needed. Since we only have the offset of + // the field from the base of the object, we need to look for it first. + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (UNLIKELY(instrumentation->HasFieldWriteListeners())) { + JValue field_value = GetFieldValue<field_type>(shadow_frame, vregA); + Object* this_object = f->IsStatic() ? nullptr : obj; + instrumentation->FieldWriteEvent(self, this_object, shadow_frame.GetMethod(), + shadow_frame.GetDexPC(), f, field_value); + } switch (field_type) { case Primitive::kPrimBoolean: f->SetBoolean<transaction_active>(obj, shadow_frame.GetVReg(vregA)); @@ -309,8 +369,20 @@ static inline bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instructio return false; } MemberOffset field_offset(inst->VRegC_22c()); - const bool is_volatile = false; // iput-x-quick only on non volatile fields. const uint32_t vregA = inst->VRegA_22c(inst_data); + // Report this field modification to instrumentation if needed. Since we only have the offset of + // the field from the base of the object, we need to look for it first. + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (UNLIKELY(instrumentation->HasFieldWriteListeners())) { + ArtField* f = ArtField::FindInstanceFieldWithOffset(obj->GetClass(), + field_offset.Uint32Value()); + DCHECK(f != nullptr); + DCHECK(!f->IsStatic()); + JValue field_value = GetFieldValue<field_type>(shadow_frame, vregA); + instrumentation->FieldWriteEvent(Thread::Current(), obj, shadow_frame.GetMethod(), + shadow_frame.GetDexPC(), f, field_value); + } + const bool is_volatile = false; // iput-x-quick only on non volatile fields. switch (field_type) { case Primitive::kPrimInt: obj->SetField32<transaction_active>(field_offset, shadow_frame.GetVReg(vregA), is_volatile); diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc index adc1074..223b7a1 100644 --- a/runtime/jdwp/jdwp_event.cc +++ b/runtime/jdwp/jdwp_event.cc @@ -108,7 +108,7 @@ namespace JDWP { */ struct ModBasket { ModBasket() : pLoc(NULL), threadId(0), classId(0), excepClassId(0), - caught(false), field(0), thisPtr(0) { } + caught(false), fieldTypeID(0), fieldId(0), thisPtr(0) { } const JdwpLocation* pLoc; /* LocationOnly */ std::string className; /* ClassMatch/ClassExclude */ @@ -116,7 +116,8 @@ struct ModBasket { RefTypeId classId; /* ClassOnly */ RefTypeId excepClassId; /* ExceptionOnly */ bool caught; /* ExceptionOnly */ - FieldId field; /* FieldOnly */ + RefTypeId fieldTypeID; /* FieldOnly */ + FieldId fieldId; /* FieldOnly */ ObjectId thisPtr; /* InstanceOnly */ /* nothing for StepOnly -- handled differently */ }; @@ -457,7 +458,10 @@ static bool ModsMatch(JdwpEvent* pEvent, ModBasket* basket) } break; case MK_FIELD_ONLY: - if (!Dbg::MatchType(basket->classId, pMod->fieldOnly.refTypeId) || pMod->fieldOnly.fieldId != basket->field) { + if (pMod->fieldOnly.fieldId != basket->fieldId) { + return false; + } + if (!Dbg::MatchType(basket->fieldTypeID, pMod->fieldOnly.refTypeId)) { return false; } break; @@ -848,7 +852,8 @@ bool JdwpState::PostFieldEvent(const JdwpLocation* pLoc, RefTypeId typeId, Field basket.thisPtr = thisPtr; basket.threadId = Dbg::GetThreadSelfId(); basket.className = Dbg::GetClassName(pLoc->class_id); - basket.field = fieldId; + basket.fieldTypeID = typeId; + basket.fieldId = fieldId; if (InvokeInProgress()) { VLOG(jdwp) << "Not posting field event during invoke"; diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc index 8ef375b..4843c2b 100644 --- a/runtime/jdwp/jdwp_handler.cc +++ b/runtime/jdwp/jdwp_handler.cc @@ -354,8 +354,8 @@ static JdwpError VM_DisposeObjects(JdwpState*, Request& request, ExpandBuf*) static JdwpError VM_Capabilities(JdwpState*, Request&, ExpandBuf* reply) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - expandBufAdd1(reply, false); // canWatchFieldModification - expandBufAdd1(reply, false); // canWatchFieldAccess + expandBufAdd1(reply, true); // canWatchFieldModification + expandBufAdd1(reply, true); // canWatchFieldAccess expandBufAdd1(reply, true); // canGetBytecodes expandBufAdd1(reply, true); // canGetSyntheticAttribute expandBufAdd1(reply, true); // canGetOwnedMonitorInfo diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc index f91cab1..7b0b94c 100644 --- a/runtime/mirror/art_field.cc +++ b/runtime/mirror/art_field.cc @@ -19,6 +19,7 @@ #include "art_field-inl.h" #include "gc/accounting/card_table-inl.h" #include "object-inl.h" +#include "object_array-inl.h" #include "object_utils.h" #include "runtime.h" #include "scoped_thread_state_change.h" @@ -69,5 +70,25 @@ void ArtField::VisitRoots(RootCallback* callback, void* arg) { } } +// TODO: we could speed up the search if fields are ordered by offsets. +ArtField* ArtField::FindInstanceFieldWithOffset(mirror::Class* klass, uint32_t field_offset) { + DCHECK(klass != nullptr); + ObjectArray<ArtField>* instance_fields = klass->GetIFields(); + if (instance_fields != nullptr) { + for (int32_t i = 0, e = instance_fields->GetLength(); i < e; ++i) { + mirror::ArtField* field = instance_fields->GetWithoutChecks(i); + if (field->GetOffset().Uint32Value() == field_offset) { + return field; + } + } + } + // We did not find field in the class: look into superclass. + if (klass->GetSuperClass() != NULL) { + return FindInstanceFieldWithOffset(klass->GetSuperClass(), field_offset); + } else { + return nullptr; + } +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h index 0daa838..ba70cc6 100644 --- a/runtime/mirror/art_field.h +++ b/runtime/mirror/art_field.h @@ -132,6 +132,10 @@ class MANAGED ArtField : public Object { return (GetAccessFlags() & kAccVolatile) != 0; } + // Returns an instance field with this offset in the given class or nullptr if not found. + static ArtField* FindInstanceFieldWithOffset(mirror::Class* klass, uint32_t field_offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". // The class we are a part of diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index b6fe4d5..5d033bc 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -3594,29 +3594,6 @@ void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_ty } } -// Look for an instance field with this offset. -// TODO: we may speed up the search if offsets are sorted by doing a quick search. -static mirror::ArtField* FindInstanceFieldWithOffset(mirror::Class* klass, uint32_t field_offset) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::ObjectArray<mirror::ArtField>* instance_fields = klass->GetIFields(); - if (instance_fields != NULL) { - for (int32_t i = 0, e = instance_fields->GetLength(); i < e; ++i) { - mirror::ArtField* field = instance_fields->Get(i); - if (field->GetOffset().Uint32Value() == field_offset) { - return field; - } - } - } - // We did not find field in class: look into superclass. - if (klass->GetSuperClass() != NULL) { - return FindInstanceFieldWithOffset(klass->GetSuperClass(), field_offset); - } else { - VLOG(verifier) << "Failed to find instance field at offset '" << field_offset - << "' from '" << PrettyDescriptor(klass) << "'"; - return nullptr; - } -} - mirror::ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line) { DCHECK(inst->Opcode() == Instruction::IGET_QUICK || @@ -3631,7 +3608,13 @@ mirror::ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst, return nullptr; } uint32_t field_offset = static_cast<uint32_t>(inst->VRegC_22c()); - return FindInstanceFieldWithOffset(object_type.GetClass(), field_offset); + mirror::ArtField* f = mirror::ArtField::FindInstanceFieldWithOffset(object_type.GetClass(), + field_offset); + if (f == nullptr) { + VLOG(verifier) << "Failed to find instance field at offset '" << field_offset + << "' from '" << PrettyDescriptor(object_type.GetClass()) << "'"; + } + return f; } void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& insn_type, |