Fix 905 flake on low mem.

Test 905 could flake if a background GC occured. This could cause one
of the jvmtiEnvs to have its tag map updated and recomputed. Since
this map is unordered it leads to the order of free events being
different between the two environments. This is allowed (although
surprising) and test 905 assumed it was not the case.

We also expand this test to ensure that the right objects are getting
their free-events and that free events do not mess up the tagging of
other objects.

Test: ./test/testrunner/testrunner.py --host -j80
Bug: 119652731

Change-Id: Id17d1c87c710b80cd401dad109d98225ea28c29b
diff --git a/test/905-object-free/src/art/Test905.java b/test/905-object-free/src/art/Test905.java
index dddd1aa..367da99 100644
--- a/test/905-object-free/src/art/Test905.java
+++ b/test/905-object-free/src/art/Test905.java
@@ -20,6 +20,7 @@
 import java.lang.ref.ReferenceQueue;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.function.BiConsumer;
 
 public class Test905 {
   // Taken from jdwp tests.
@@ -110,26 +111,59 @@
     System.out.println("---");
   }
 
-  private static void stressAllocate(int i) {
+  private static void stressAllocate(int i, BiConsumer<Integer, Object> saver) {
     Object obj = new Object();
     Main.setTag(obj, i);
     setTag2(obj, i + 1);
+    saver.accept(i, obj);
   }
 
   private static void stress() {
     getCollectedTags(0);
     getCollectedTags(1);
-    // Allocate objects.
-    for (int i = 1; i <= 100000; ++i) {
-      stressAllocate(i);
+    final int num_obj = 400000;
+    final Object[] saved = new Object[num_obj/2];
+    // Allocate objects, Save every other one. We want to be sure that it's only the deleted objects
+    // that get their tags cleared and non-deleted objects correctly keep track of their tags.
+    for (int i = 1; i <= num_obj; ++i) {
+      stressAllocate(i, (idx, obj) -> {
+        if ((idx.intValue() - 1) % 2 == 0) {
+          saved[(idx.intValue() - 1)/2] = obj;
+        }
+      });
     }
     gcAndWait();
     long[] freedTags1 = getCollectedTags(0);
     long[] freedTags2 = getCollectedTags(1);
+    // Sort the freedtags
+    Arrays.sort(freedTags1);
+    Arrays.sort(freedTags2);
+    // Make sure we freed all the ones we expect to and both envs agree on this.
     System.out.println("Free counts " + freedTags1.length + " " + freedTags2.length);
     for (int i = 0; i < freedTags1.length; ++i) {
       if (freedTags1[i] + 1 != freedTags2[i]) {
-        System.out.println("Mismatched tags " + freedTags1[i] + " " + freedTags2[i]);
+        System.out.println("Mismatched tags " + (freedTags1[i] + 1) + " " + freedTags2[i]);
+      }
+    }
+    // Make sure the saved-tags aren't present.
+    for (int i = 0; i < saved.length; i++) {
+      // index = (tag - 1)/2 --> (index * 2) + 1 = tag
+      long expectedTag1 = (i * 2) + 1;
+      if (Main.getTag(saved[i]) != expectedTag1) {
+        System.out.println("Saved object has unexpected tag in env 1. Expected "
+                           + expectedTag1 + " got " + Main.getTag(saved[i]));
+      }
+      if (getTag2(saved[i]) != 1 + expectedTag1) {
+        System.out.println("Saved object has unexpected tag in env 2. Expected "
+                           + (expectedTag1 + 1) + " got " + getTag2(saved[i]));
+      }
+      if (Arrays.binarySearch(freedTags1, expectedTag1) >= 0) {
+        System.out.println("Saved object was marked as deleted in env 1. Object was "
+                           + expectedTag1);
+      }
+      if (Arrays.binarySearch(freedTags2, expectedTag1 + 1) >= 0) {
+        System.out.println("Saved object was marked as deleted in env 2. Object was "
+                           + (expectedTag1 + 1));
       }
     }
   }
@@ -161,4 +195,5 @@
   private static native void enableFreeTracking(boolean enable);
   private static native long[] getCollectedTags(int index);
   private static native void setTag2(Object o, long tag);
+  private static native long getTag2(Object o);
 }