Add obsolete object event

Add an extension event to notify agents that an object is becoming
obsolete. This is meant to be used by agents performing allocation
tracking using the VMObjectAlloc event to let them know that an object
replacement is occurring. This event is only triggered by calls to
JVMTI functions that create obsolete objects. Normal GC actions
(including a moving compaction) will not cause this event to trigger.

Test: ./test.py --host
Bug: 134162467

Change-Id: If48b880814a751ba6c24c18d0ad116db4f8fdf64
diff --git a/openjdkjvmti/events.h b/openjdkjvmti/events.h
index ac86d0c..d5ab4fb 100644
--- a/openjdkjvmti/events.h
+++ b/openjdkjvmti/events.h
@@ -80,7 +80,8 @@
     // capability.
     kClassFileLoadHookRetransformable = JVMTI_MAX_EVENT_TYPE_VAL + 1,
     kDdmPublishChunk = JVMTI_MAX_EVENT_TYPE_VAL + 2,
-    kMaxNormalEventTypeVal = kDdmPublishChunk,
+    kObsoleteObjectCreated = JVMTI_MAX_EVENT_TYPE_VAL + 3,
+    kMaxNormalEventTypeVal = kObsoleteObjectCreated,
 
     // All that follow are events used to implement internal JVMTI functions. They are not settable
     // directly by agents.
@@ -102,6 +103,10 @@
                                               jint data_len,
                                               const jbyte* data);
 
+using ArtJvmtiEventObsoleteObjectCreated = void (*)(jvmtiEnv *jvmti_env,
+                                                    jlong* obsolete_tag,
+                                                    jlong* new_tag);
+
 // It is not enough to store a Thread pointer, as these may be reused. Use the pointer and the
 // thread id.
 // Note: We could just use the tid like tracing does.
@@ -114,7 +119,7 @@
 };
 
 struct ArtJvmtiEventCallbacks : jvmtiEventCallbacks {
-  ArtJvmtiEventCallbacks() : DdmPublishChunk(nullptr) {
+  ArtJvmtiEventCallbacks() : DdmPublishChunk(nullptr), ObsoleteObjectCreated(nullptr) {
     memset(this, 0, sizeof(jvmtiEventCallbacks));
   }
 
@@ -125,6 +130,7 @@
   jvmtiError Set(jint index, jvmtiExtensionEvent cb);
 
   ArtJvmtiEventDdmPublishChunk DdmPublishChunk;
+  ArtJvmtiEventObsoleteObjectCreated ObsoleteObjectCreated;
 };
 
 bool IsExtensionEvent(jint e);
@@ -285,6 +291,16 @@
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(art::Locks::user_code_suspension_lock_, art::Locks::thread_list_lock_);
 
+  template<typename Visitor>
+  void ForEachEnv(art::Thread* self, Visitor v) REQUIRES(!envs_lock_) {
+    art::ReaderMutexLock mu(self, envs_lock_);
+    for (ArtJvmTiEnv* e : envs) {
+      if (e != nullptr) {
+        v(e);
+      }
+    }
+  }
+
  private:
   void SetupTraceListener(JvmtiMethodTraceListener* listener, ArtJvmtiEvent event, bool enable);