ART: Fix tagging

Tagging is local to the jvmtiEnv. Move from a global object tag
table to a table local to the ArtJvmtiEnv.

Bug: 31385027
Test: m test-art-host-run-test-903-hello-tagging
Change-Id: I2faeed87fd0421631fee7cd97bb7d496bf4e6338
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 77ca9ce..450b6b6 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -73,7 +73,6 @@
 namespace openjdkjvmti {
 
 EventHandler gEventHandler;
-ObjectTagTable gObjectTagTable(&gEventHandler);
 
 #define ENSURE_NON_NULL(n)      \
   do {                          \
@@ -334,7 +333,7 @@
                                      const jvmtiHeapCallbacks* callbacks,
                                      const void* user_data) {
     ENSURE_HAS_CAP(env, can_tag_objects);
-    HeapUtil heap_util(&gObjectTagTable);
+    HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
     return heap_util.FollowReferences(env,
                                       heap_filter,
                                       klass,
@@ -349,7 +348,7 @@
                                        const jvmtiHeapCallbacks* callbacks,
                                        const void* user_data) {
     ENSURE_HAS_CAP(env, can_tag_objects);
-    HeapUtil heap_util(&gObjectTagTable);
+    HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
     return heap_util.IterateThroughHeap(env, heap_filter, klass, callbacks, user_data);
   }
 
@@ -363,7 +362,7 @@
 
     art::ScopedObjectAccess soa(jni_env);
     art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(object);
-    if (!gObjectTagTable.GetTag(obj.Ptr(), tag_ptr)) {
+    if (!ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table->GetTag(obj.Ptr(), tag_ptr)) {
       *tag_ptr = 0;
     }
 
@@ -384,7 +383,7 @@
 
     art::ScopedObjectAccess soa(jni_env);
     art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(object);
-    gObjectTagTable.Set(obj.Ptr(), tag);
+    ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table->Set(obj.Ptr(), tag);
 
     return ERR(NONE);
   }
@@ -403,12 +402,12 @@
     }
 
     art::ScopedObjectAccess soa(jni_env);
-    return gObjectTagTable.GetTaggedObjects(env,
-                                            tag_count,
-                                            tags,
-                                            count_ptr,
-                                            object_result_ptr,
-                                            tag_result_ptr);
+    return ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table->GetTaggedObjects(env,
+                                                                               tag_count,
+                                                                               tags,
+                                                                               count_ptr,
+                                                                               object_result_ptr,
+                                                                               tag_result_ptr);
   }
 
   static jvmtiError ForceGarbageCollection(jvmtiEnv* env) {
@@ -579,7 +578,7 @@
   }
 
   static jvmtiError GetLoadedClasses(jvmtiEnv* env, jint* class_count_ptr, jclass** classes_ptr) {
-    HeapUtil heap_util(&gObjectTagTable);
+    HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
     return heap_util.GetLoadedClasses(env, class_count_ptr, classes_ptr);
   }
 
@@ -678,6 +677,7 @@
     ENSURE_HAS_CAP(env, can_retransform_classes);
     std::string error_msg;
     jvmtiError res = Transformer::RetransformClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env),
+                                                     &gEventHandler,
                                                      art::Runtime::Current(),
                                                      art::Thread::Current(),
                                                      class_count,
@@ -695,6 +695,7 @@
     ENSURE_HAS_CAP(env, can_redefine_classes);
     std::string error_msg;
     jvmtiError res = Redefiner::RedefineClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env),
+                                                &gEventHandler,
                                                 art::Runtime::Current(),
                                                 art::Thread::Current(),
                                                 class_count,
@@ -1162,6 +1163,8 @@
   static jvmtiError DisposeEnvironment(jvmtiEnv* env) {
     ENSURE_VALID_ENV(env);
     gEventHandler.RemoveArtJvmTiEnv(ArtJvmTiEnv::AsArtJvmTiEnv(env));
+    art::Runtime::Current()->RemoveSystemWeakHolder(
+        ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
     delete env;
     return OK;
   }
@@ -1333,13 +1336,25 @@
          version == JVMTI_VERSION;
 }
 
+extern const jvmtiInterface_1 gJvmtiInterface;
+ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler)
+    : art_vm(runtime),
+      local_data(nullptr),
+      capabilities(),
+      object_tag_table(new ObjectTagTable(event_handler)) {
+  functions = &gJvmtiInterface;
+}
+
 // Creates a jvmtiEnv and returns it with the art::ti::Env that is associated with it. new_art_ti
 // is a pointer to the uninitialized memory for an art::ti::Env.
 static void CreateArtJvmTiEnv(art::JavaVMExt* vm, /*out*/void** new_jvmtiEnv) {
-  struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm);
+  struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm, &gEventHandler);
   *new_jvmtiEnv = env;
 
   gEventHandler.RegisterArtJvmTiEnv(env);
+
+  art::Runtime::Current()->AddSystemWeakHolder(
+      ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
 }
 
 // A hook that the runtime uses to allow plugins to handle GetEnv calls. It returns true and
@@ -1371,7 +1386,6 @@
   SearchUtil::Register();
 
   runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler);
-  runtime->AddSystemWeakHolder(&gObjectTagTable);
 
   return true;
 }
diff --git a/runtime/openjdkjvmti/art_jvmti.h b/runtime/openjdkjvmti/art_jvmti.h
index 99139a1..2ff3a47 100644
--- a/runtime/openjdkjvmti/art_jvmti.h
+++ b/runtime/openjdkjvmti/art_jvmti.h
@@ -48,8 +48,7 @@
 
 namespace openjdkjvmti {
 
-extern const jvmtiInterface_1 gJvmtiInterface;
-extern EventHandler gEventHandler;
+class ObjectTagTable;
 
 // A structure that is a jvmtiEnv with additional information for the runtime.
 struct ArtJvmTiEnv : public jvmtiEnv {
@@ -60,10 +59,10 @@
   EventMasks event_masks;
   std::unique_ptr<jvmtiEventCallbacks> event_callbacks;
 
-  explicit ArtJvmTiEnv(art::JavaVMExt* runtime)
-      : art_vm(runtime), local_data(nullptr), capabilities() {
-    functions = &gJvmtiInterface;
-  }
+  // Tagging is specific to the jvmtiEnv.
+  std::unique_ptr<ObjectTagTable> object_tag_table;
+
+  ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler);
 
   static ArtJvmTiEnv* AsArtJvmTiEnv(jvmtiEnv* env) {
     return art::down_cast<ArtJvmTiEnv*>(env);
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 7cc7a63..c4d20c0 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -303,6 +303,7 @@
 }
 
 jvmtiError Redefiner::RedefineClasses(ArtJvmTiEnv* env,
+                                      EventHandler* event_handler,
                                       art::Runtime* runtime,
                                       art::Thread* self,
                                       jint class_count,
@@ -350,6 +351,7 @@
   }
   // Call all the transformation events.
   jvmtiError res = Transformer::RetransformClassesDirect(env,
+                                                         event_handler,
                                                          self,
                                                          &def_vector);
   if (res != OK) {
diff --git a/runtime/openjdkjvmti/ti_redefine.h b/runtime/openjdkjvmti/ti_redefine.h
index 65ee291..4e6d05f 100644
--- a/runtime/openjdkjvmti/ti_redefine.h
+++ b/runtime/openjdkjvmti/ti_redefine.h
@@ -88,6 +88,7 @@
   // The caller is responsible for freeing it. The runtime makes its own copy of the data.
   // TODO This function should call the transformation events.
   static jvmtiError RedefineClasses(ArtJvmTiEnv* env,
+                                    EventHandler* event_handler,
                                     art::Runtime* runtime,
                                     art::Thread* self,
                                     jint class_count,
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index 2fec631..36421b9 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -63,12 +63,13 @@
 
 jvmtiError Transformer::RetransformClassesDirect(
       ArtJvmTiEnv* env,
+      EventHandler* event_handler,
       art::Thread* self,
       /*in-out*/std::vector<ArtClassDefinition>* definitions) {
   for (ArtClassDefinition& def : *definitions) {
     jint new_len = -1;
     unsigned char* new_data = nullptr;
-    gEventHandler.DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
+    event_handler->DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
         self,
         GetJniEnv(env),
         def.klass,
@@ -85,6 +86,7 @@
 }
 
 jvmtiError Transformer::RetransformClasses(ArtJvmTiEnv* env,
+                                           EventHandler* event_handler,
                                            art::Runtime* runtime,
                                            art::Thread* self,
                                            jint class_count,
@@ -114,7 +116,7 @@
     }
     definitions.push_back(std::move(def));
   }
-  res = RetransformClassesDirect(env, self, &definitions);
+  res = RetransformClassesDirect(env, event_handler, self, &definitions);
   if (res != OK) {
     return res;
   }
diff --git a/runtime/openjdkjvmti/transform.h b/runtime/openjdkjvmti/transform.h
index 65f2ae1..c6a36e8 100644
--- a/runtime/openjdkjvmti/transform.h
+++ b/runtime/openjdkjvmti/transform.h
@@ -42,14 +42,20 @@
 
 namespace openjdkjvmti {
 
+class EventHandler;
+
 jvmtiError GetClassLocation(ArtJvmTiEnv* env, jclass klass, /*out*/std::string* location);
 
 class Transformer {
  public:
   static jvmtiError RetransformClassesDirect(
-      ArtJvmTiEnv* env, art::Thread* self, /*in-out*/std::vector<ArtClassDefinition>* definitions);
+      ArtJvmTiEnv* env,
+      EventHandler* event_handler,
+      art::Thread* self,
+      /*in-out*/std::vector<ArtClassDefinition>* definitions);
 
   static jvmtiError RetransformClasses(ArtJvmTiEnv* env,
+                                       EventHandler* event_handler,
                                        art::Runtime* runtime,
                                        art::Thread* self,
                                        jint class_count,
diff --git a/test/903-hello-tagging/expected.txt b/test/903-hello-tagging/expected.txt
index 872b79b..acfdbd8 100644
--- a/test/903-hello-tagging/expected.txt
+++ b/test/903-hello-tagging/expected.txt
@@ -8,3 +8,4 @@
 [<null;1>, <null;1>, <null;2>, <null;2>, <null;3>, <null;3>, <null;4>, <null;4>, <null;5>, <null;5>, <null;6>, <null;6>, <null;7>, <null;7>, <null;8>, <null;8>, <null;9>, <null;9>]
 18
 [<1;0>, <2;0>, <3;0>, <4;0>, <5;0>, <6;0>, <7;0>, <8;0>, <9;0>, <11;0>, <12;0>, <13;0>, <14;0>, <15;0>, <16;0>, <17;0>, <18;0>, <19;0>]
+[100, 101, 102, 103, 104, 105, 106, 107, 108, 109]
diff --git a/test/903-hello-tagging/src/Main.java b/test/903-hello-tagging/src/Main.java
index 2f0365a..48896b2 100644
--- a/test/903-hello-tagging/src/Main.java
+++ b/test/903-hello-tagging/src/Main.java
@@ -22,6 +22,7 @@
   public static void main(String[] args) {
     doTest();
     testGetTaggedObjects();
+    testTags();
   }
 
   public static void doTest() {
@@ -35,6 +36,12 @@
     }
   }
 
+  public static void testTags() {
+    Object o = new Object();
+    long[] res = testTagsInDifferentEnvs(o, 100, 10);
+    System.out.println(Arrays.toString(res));
+  }
+
   private static WeakReference<Object> test() {
     Object o1 = new Object();
     setTag(o1, 1);
@@ -166,4 +173,5 @@
   private static native long getTag(Object o);
   private static native Object[] getTaggedObjects(long[] searchTags, boolean returnObjects,
       boolean returnTags);
+  private static native long[] testTagsInDifferentEnvs(Object o, long baseTag, int n);
 }
diff --git a/test/903-hello-tagging/tagging.cc b/test/903-hello-tagging/tagging.cc
index f74c1fc..6177263 100644
--- a/test/903-hello-tagging/tagging.cc
+++ b/test/903-hello-tagging/tagging.cc
@@ -139,6 +139,62 @@
   return resultArray;
 }
 
+static jvmtiEnv* CreateJvmtiEnv(JNIEnv* env) {
+  JavaVM* jvm;
+  CHECK_EQ(0, env->GetJavaVM(&jvm));
+
+  jvmtiEnv* new_jvmti_env;
+  CHECK_EQ(0, jvm->GetEnv(reinterpret_cast<void**>(&new_jvmti_env), JVMTI_VERSION_1_0));
+
+  jvmtiCapabilities capa;
+  memset(&capa, 0, sizeof(jvmtiCapabilities));
+  capa.can_tag_objects = 1;
+  jvmtiError error = new_jvmti_env->AddCapabilities(&capa);
+  CHECK_EQ(JVMTI_ERROR_NONE, error);
+
+  return new_jvmti_env;
+}
+
+static void SetTag(jvmtiEnv* env, jobject obj, jlong tag) {
+  jvmtiError ret = env->SetTag(obj, tag);
+  CHECK_EQ(JVMTI_ERROR_NONE, ret);
+}
+
+static jlong GetTag(jvmtiEnv* env, jobject obj) {
+  jlong tag;
+  jvmtiError ret = env->GetTag(obj, &tag);
+  CHECK_EQ(JVMTI_ERROR_NONE, ret);
+  return tag;
+}
+
+extern "C" JNIEXPORT jlongArray JNICALL Java_Main_testTagsInDifferentEnvs(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj, jlong base_tag, jint count) {
+  std::unique_ptr<jvmtiEnv*[]> envs = std::unique_ptr<jvmtiEnv*[]>(new jvmtiEnv*[count]);
+  envs[0] = jvmti_env;
+  for (int32_t i = 1; i != count; ++i) {
+    envs[i] = CreateJvmtiEnv(env);
+  }
+
+  for (int32_t i = 0; i != count; ++i) {
+    SetTag(envs[i], obj, base_tag + i);
+  }
+  std::unique_ptr<jlong[]> vals = std::unique_ptr<jlong[]>(new jlong[count]);
+  for (int32_t i = 0; i != count; ++i) {
+    vals[i] = GetTag(envs[i], obj);
+  }
+
+  for (int32_t i = 1; i != count; ++i) {
+    CHECK_EQ(JVMTI_ERROR_NONE, envs[i]->DisposeEnvironment());
+  }
+
+  jlongArray res = env->NewLongArray(count);
+  if (res == nullptr) {
+    return nullptr;
+  }
+  env->SetLongArrayRegion(res, 0, count, vals.get());
+  return res;
+}
+
 }  // namespace Test903HelloTagging
 }  // namespace art