Merge "Support field watchpoint in interpreter"
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 @@
       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 @@
     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 @@
   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 @@
     }
   }
   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 @@
     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 @@
  */
 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 @@
   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 @@
       }
       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 @@
   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_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 @@
   }
 }
 
+// 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 @@
     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 @@
   }
 }
 
-// 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 @@
     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,