Add field access & modify JVMTI callbacks

This adds support for the FieldAccess and FieldModification callbacks
in JVMTI and all other functions and behaviors associated with the
can_generate_field_modification_events and
can_generate_field_access_events capabilities.

Tests follow in the next CL.

Bug: 34409228
Test: ./test.py --host -j40

Change-Id: Id18fc53677cc1f96e1460c498ade7607219d5a79
diff --git a/runtime/openjdkjvmti/events.cc b/runtime/openjdkjvmti/events.cc
index 90bc122..989b9af 100644
--- a/runtime/openjdkjvmti/events.cc
+++ b/runtime/openjdkjvmti/events.cc
@@ -33,6 +33,7 @@
 
 #include "art_jvmti.h"
 #include "art_method-inl.h"
+#include "art_field-inl.h"
 #include "base/logging.h"
 #include "gc/allocation_listener.h"
 #include "gc/gc_pause_listener.h"
@@ -433,24 +434,92 @@
   }
 
   // Call-back for when we read from a field.
-  void FieldRead(art::Thread* self ATTRIBUTE_UNUSED,
-                 art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
-                 art::ArtMethod* method ATTRIBUTE_UNUSED,
-                 uint32_t dex_pc ATTRIBUTE_UNUSED,
-                 art::ArtField* field ATTRIBUTE_UNUSED)
+  void FieldRead(art::Thread* self,
+                 art::Handle<art::mirror::Object> this_object,
+                 art::ArtMethod* method,
+                 uint32_t dex_pc,
+                 art::ArtField* field)
       REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE {
-    return;
+    if (event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kFieldAccess)) {
+      art::JNIEnvExt* jnienv = self->GetJniEnv();
+      // DCHECK(!self->IsExceptionPending());
+      ScopedLocalRef<jobject> this_ref(jnienv, AddLocalRef<jobject>(jnienv, this_object.Get()));
+      ScopedLocalRef<jobject> fklass(jnienv,
+                                     AddLocalRef<jobject>(jnienv,
+                                                          field->GetDeclaringClass().Ptr()));
+      RunEventCallback<ArtJvmtiEvent::kFieldAccess>(self,
+                                                    jnienv,
+                                                    art::jni::EncodeArtMethod(method),
+                                                    static_cast<jlocation>(dex_pc),
+                                                    static_cast<jclass>(fklass.get()),
+                                                    this_ref.get(),
+                                                    art::jni::EncodeArtField(field));
+    }
+  }
+
+  void FieldWritten(art::Thread* self,
+                    art::Handle<art::mirror::Object> this_object,
+                    art::ArtMethod* method,
+                    uint32_t dex_pc,
+                    art::ArtField* field,
+                    art::Handle<art::mirror::Object> new_val)
+      REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE {
+    if (event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kFieldModification)) {
+      art::JNIEnvExt* jnienv = self->GetJniEnv();
+      // DCHECK(!self->IsExceptionPending());
+      ScopedLocalRef<jobject> this_ref(jnienv, AddLocalRef<jobject>(jnienv, this_object.Get()));
+      ScopedLocalRef<jobject> fklass(jnienv,
+                                     AddLocalRef<jobject>(jnienv,
+                                                          field->GetDeclaringClass().Ptr()));
+      ScopedLocalRef<jobject> fval(jnienv, AddLocalRef<jobject>(jnienv, new_val.Get()));
+      jvalue val;
+      val.l = fval.get();
+      RunEventCallback<ArtJvmtiEvent::kFieldModification>(
+          self,
+          jnienv,
+          art::jni::EncodeArtMethod(method),
+          static_cast<jlocation>(dex_pc),
+          static_cast<jclass>(fklass.get()),
+          field->IsStatic() ? nullptr :  this_ref.get(),
+          art::jni::EncodeArtField(field),
+          'L',  // type_char
+          val);
+    }
   }
 
   // Call-back for when we write into a field.
-  void FieldWritten(art::Thread* self ATTRIBUTE_UNUSED,
-                    art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED,
-                    art::ArtMethod* method ATTRIBUTE_UNUSED,
-                    uint32_t dex_pc ATTRIBUTE_UNUSED,
-                    art::ArtField* field ATTRIBUTE_UNUSED,
-                    const art::JValue& field_value ATTRIBUTE_UNUSED)
+  void FieldWritten(art::Thread* self,
+                    art::Handle<art::mirror::Object> this_object,
+                    art::ArtMethod* method,
+                    uint32_t dex_pc,
+                    art::ArtField* field,
+                    const art::JValue& field_value)
       REQUIRES_SHARED(art::Locks::mutator_lock_) OVERRIDE {
-    return;
+    if (event_handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kFieldModification)) {
+      art::JNIEnvExt* jnienv = self->GetJniEnv();
+      DCHECK(!self->IsExceptionPending());
+      ScopedLocalRef<jobject> this_ref(jnienv, AddLocalRef<jobject>(jnienv, this_object.Get()));
+      ScopedLocalRef<jobject> fklass(jnienv,
+                                     AddLocalRef<jobject>(jnienv,
+                                                          field->GetDeclaringClass().Ptr()));
+      char type_char = art::Primitive::Descriptor(field->GetTypeAsPrimitiveType())[0];
+      jvalue val;
+      // 64bit integer is the largest value in the union so we should be fine simply copying it into
+      // the union.
+      val.j = field_value.GetJ();
+      RunEventCallback<ArtJvmtiEvent::kFieldModification>(
+          self,
+          jnienv,
+          art::jni::EncodeArtMethod(method),
+          static_cast<jlocation>(dex_pc),
+          static_cast<jclass>(fklass.get()),
+          field->IsStatic() ? nullptr :  this_ref.get(),  // nb static field modification get given
+                                                          // the class as this_object for some
+                                                          // reason.
+          art::jni::EncodeArtField(field),
+          type_char,
+          val);
+    }
   }
 
   // Call-back when an exception is caught.
@@ -490,15 +559,20 @@
     case ArtJvmtiEvent::kMethodExit:
       return art::instrumentation::Instrumentation::kMethodExited |
              art::instrumentation::Instrumentation::kMethodUnwind;
+    case ArtJvmtiEvent::kFieldModification:
+      return art::instrumentation::Instrumentation::kFieldWritten;
+    case ArtJvmtiEvent::kFieldAccess:
+      return art::instrumentation::Instrumentation::kFieldRead;
     default:
       LOG(FATAL) << "Unknown event ";
       return 0;
   }
 }
 
-static void SetupMethodTraceListener(JvmtiMethodTraceListener* listener,
-                                     ArtJvmtiEvent event,
-                                     bool enable) {
+static void SetupTraceListener(JvmtiMethodTraceListener* listener,
+                               ArtJvmtiEvent event,
+                               bool enable) {
+  art::ScopedThreadStateChange stsc(art::Thread::Current(), art::ThreadState::kNative);
   uint32_t new_events = GetInstrumentationEventsFor(event);
   art::instrumentation::Instrumentation* instr = art::Runtime::Current()->GetInstrumentation();
   art::gc::ScopedGCCriticalSection gcs(art::Thread::Current(),
@@ -529,7 +603,9 @@
 
     case ArtJvmtiEvent::kMethodEntry:
     case ArtJvmtiEvent::kMethodExit:
-      SetupMethodTraceListener(method_trace_listener_.get(), event, enable);
+    case ArtJvmtiEvent::kFieldAccess:
+    case ArtJvmtiEvent::kFieldModification:
+      SetupTraceListener(method_trace_listener_.get(), event, enable);
       return;
 
     default: