Fix lock order for jvmti kTaggingLockLevel

Add test for duplicate env free order.

Bug: 36648696

Test: ./test.py --host

Change-Id: I76fc8187b29f5e66cc29674320e887dbc508fe19
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 038aeb3..2414b5f 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -62,10 +62,11 @@
   kJdwpAdbStateLock,
   kJdwpSocketLock,
   kRegionSpaceRegionLock,
+  kMarkSweepMarkStackLock,
   kRosAllocGlobalLock,
   kRosAllocBracketLock,
   kRosAllocBulkFreeLock,
-  kMarkSweepMarkStackLock,
+  kTaggingLockLevel,
   kTransactionLogLock,
   kJniFunctionTableLock,
   kJniWeakGlobalsLock,
diff --git a/runtime/openjdkjvmti/jvmti_weak_table.h b/runtime/openjdkjvmti/jvmti_weak_table.h
index ae36122..eeea75a 100644
--- a/runtime/openjdkjvmti/jvmti_weak_table.h
+++ b/runtime/openjdkjvmti/jvmti_weak_table.h
@@ -53,7 +53,7 @@
 class JvmtiWeakTable : public art::gc::SystemWeakHolder {
  public:
   JvmtiWeakTable()
-      : art::gc::SystemWeakHolder(kTaggingLockLevel),
+      : art::gc::SystemWeakHolder(art::kTaggingLockLevel),
         update_since_last_sweep_(false) {
   }
 
@@ -200,10 +200,6 @@
     }
   };
 
-  // The tag table is used when visiting roots. So it needs to have a low lock level.
-  static constexpr art::LockLevel kTaggingLockLevel =
-      static_cast<art::LockLevel>(art::LockLevel::kAbortLock + 1);
-
   std::unordered_map<art::GcRoot<art::mirror::Object>,
                      T,
                      HashGcRoot,
diff --git a/test/905-object-free/expected.txt b/test/905-object-free/expected.txt
index 436ca11..6594ad8 100644
--- a/test/905-object-free/expected.txt
+++ b/test/905-object-free/expected.txt
@@ -10,3 +10,4 @@
 ---
 []
 ---
+Free counts 1000000 1000000
diff --git a/test/905-object-free/src/Main.java b/test/905-object-free/src/Main.java
index e41e378..67811c2 100644
--- a/test/905-object-free/src/Main.java
+++ b/test/905-object-free/src/Main.java
@@ -33,6 +33,9 @@
 
     enableFreeTracking(false);
     run(l);
+
+    enableFreeTracking(true);
+    stress();
   }
 
   private static void run(ArrayList<Object> l) {
@@ -62,6 +65,25 @@
     System.out.println("---");
   }
 
+  private static void stress() {
+    getCollectedTags(0);
+    getCollectedTags(1);
+    for (int i = 0; i <= 1000000; ++i) {
+      Object obj = new Object();
+      setTag(obj, i);
+      obj = null; // Clear vreg.
+    }
+    Runtime.getRuntime().gc();
+    long[] freedTags1 = getCollectedTags(0);
+    long[] freedTags2 = getCollectedTags(1);
+    System.out.println("Free counts " + freedTags1.length + " " + freedTags2.length);
+    for (int i = 0; i < freedTags1.length; ++i) {
+      if (freedTags1[i] != freedTags2[i]) {
+        System.out.println("Mismatched tags " + freedTags1[i] + " " + freedTags2[i]);
+      }
+    }
+  }
+
   private static void allocate(ArrayList<Object> l, long tag) {
     Object obj = new Object();
     l.add(obj);
@@ -69,7 +91,7 @@
   }
 
   private static void getAndPrintTags() {
-    long[] freedTags = getCollectedTags();
+    long[] freedTags = getCollectedTags(0);
     Arrays.sort(freedTags);
     System.out.println(Arrays.toString(freedTags));
   }
@@ -77,5 +99,5 @@
   private static native void setupObjectFreeCallback();
   private static native void enableFreeTracking(boolean enable);
   private static native void setTag(Object o, long tag);
-  private static native long[] getCollectedTags();
+  private static native long[] getCollectedTags(int index);
 }
diff --git a/test/905-object-free/tracking_free.cc b/test/905-object-free/tracking_free.cc
index 5eed472..3baac88 100644
--- a/test/905-object-free/tracking_free.cc
+++ b/test/905-object-free/tracking_free.cc
@@ -31,25 +31,42 @@
 namespace art {
 namespace Test905ObjectFree {
 
-static std::vector<jlong> collected_tags;
+static std::vector<jlong> collected_tags1;
+static std::vector<jlong> collected_tags2;
 
-static void JNICALL ObjectFree(jvmtiEnv* ti_env ATTRIBUTE_UNUSED, jlong tag) {
-  collected_tags.push_back(tag);
+jvmtiEnv* jvmti_env2;
+
+static void JNICALL ObjectFree1(jvmtiEnv* ti_env, jlong tag) {
+  CHECK_EQ(ti_env, jvmti_env);
+  collected_tags1.push_back(tag);
+}
+
+static void JNICALL ObjectFree2(jvmtiEnv* ti_env, jlong tag) {
+  CHECK_EQ(ti_env, jvmti_env2);
+  collected_tags2.push_back(tag);
+}
+
+static void setupObjectFreeCallback(jvmtiEnv* env, jvmtiEventObjectFree callback) {
+  jvmtiEventCallbacks callbacks;
+  memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
+  callbacks.ObjectFree = callback;
+  jvmtiError ret = env->SetEventCallbacks(&callbacks, sizeof(callbacks));
+  if (ret != JVMTI_ERROR_NONE) {
+    char* err;
+    env->GetErrorName(ret, &err);
+    printf("Error setting callbacks: %s\n", err);
+    env->Deallocate(reinterpret_cast<unsigned char*>(err));
+  }
 }
 
 extern "C" JNIEXPORT void JNICALL Java_Main_setupObjectFreeCallback(
-    JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) {
-  jvmtiEventCallbacks callbacks;
-  memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
-  callbacks.ObjectFree = ObjectFree;
-
-  jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
-  if (ret != JVMTI_ERROR_NONE) {
-    char* err;
-    jvmti_env->GetErrorName(ret, &err);
-    printf("Error setting callbacks: %s\n", err);
-    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
-  }
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
+  setupObjectFreeCallback(jvmti_env, ObjectFree1);
+  JavaVM* jvm = nullptr;
+  env->GetJavaVM(&jvm);
+  CHECK_EQ(jvm->GetEnv(reinterpret_cast<void**>(&jvmti_env2), JVMTI_VERSION_1_2), 0);
+  SetAllCapabilities(jvmti_env2);
+  setupObjectFreeCallback(jvmti_env2, ObjectFree2);
 }
 
 extern "C" JNIEXPORT void JNICALL Java_Main_enableFreeTracking(JNIEnv* env ATTRIBUTE_UNUSED,
@@ -65,17 +82,29 @@
     printf("Error enabling/disabling object-free callbacks: %s\n", err);
     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
   }
+  ret = jvmti_env2->SetEventNotificationMode(
+      enable ? JVMTI_ENABLE : JVMTI_DISABLE,
+      JVMTI_EVENT_OBJECT_FREE,
+      nullptr);
+  if (ret != JVMTI_ERROR_NONE) {
+    char* err;
+    jvmti_env2->GetErrorName(ret, &err);
+    printf("Error enabling/disabling object-free callbacks: %s\n", err);
+    jvmti_env2->Deallocate(reinterpret_cast<unsigned char*>(err));
+  }
 }
 
 extern "C" JNIEXPORT jlongArray JNICALL Java_Main_getCollectedTags(JNIEnv* env,
-                                                                   jclass klass ATTRIBUTE_UNUSED) {
-  jlongArray ret = env->NewLongArray(collected_tags.size());
+                                                                   jclass klass ATTRIBUTE_UNUSED,
+                                                                   jint index) {
+  std::vector<jlong>& tags = (index == 0) ? collected_tags1 : collected_tags2;
+  jlongArray ret = env->NewLongArray(tags.size());
   if (ret == nullptr) {
     return ret;
   }
 
-  env->SetLongArrayRegion(ret, 0, collected_tags.size(), collected_tags.data());
-  collected_tags.clear();
+  env->SetLongArrayRegion(ret, 0, tags.size(), tags.data());
+  tags.clear();
 
   return ret;
 }