1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 package android.jvmti.cts; 15 16 import static org.junit.Assert.assertEquals; 17 import static org.junit.Assert.assertTrue; 18 19 import java.lang.ref.WeakReference; 20 import java.util.ArrayList; 21 import java.util.Collections; 22 import java.util.LinkedList; 23 import java.util.List; 24 import org.junit.Before; 25 import org.junit.Test; 26 27 import art.Main; 28 29 /** 30 * Check tagging-related functionality. 31 */ 32 public class JvmtiTaggingTest extends JvmtiTestBase { 33 test()34 private static WeakReference<Object> test() { 35 Object o1 = new Object(); 36 Main.setTag(o1, 1); 37 38 Object o2 = new Object(); 39 Main.setTag(o2, 2); 40 41 assertEquals(1, Main.getTag(o1)); 42 assertEquals(2, Main.getTag(o2)); 43 44 Runtime.getRuntime().gc(); 45 Runtime.getRuntime().gc(); 46 47 assertEquals(1, Main.getTag(o1)); 48 assertEquals(2, Main.getTag(o2)); 49 50 Runtime.getRuntime().gc(); 51 Runtime.getRuntime().gc(); 52 53 Main.setTag(o1, 10); 54 Main.setTag(o2, 20); 55 56 assertEquals(10, Main.getTag(o1)); 57 assertEquals(20, Main.getTag(o2)); 58 59 return new WeakReference<Object>(o1); 60 } 61 62 // Very simplistic tagging. 63 @Test testTagging()64 public void testTagging() throws Exception { 65 test(); 66 } 67 68 @Test testTaggingGC()69 public void testTaggingGC() { 70 WeakReference<Object> weak = test(); 71 72 Runtime.getRuntime().gc(); 73 Runtime.getRuntime().gc(); 74 75 if (weak.get() != null) { 76 throw new RuntimeException("WeakReference not cleared"); 77 } 78 } 79 80 private ArrayList<Object> l; 81 82 @Test testGetTaggedObjects()83 public void testGetTaggedObjects() { 84 // Use an array list to ensure that the objects stay live for a bit. Also gives us a source 85 // to compare to. We use index % 10 as the tag. 86 l = new ArrayList<>(); 87 88 for (int i = 0; i < 20; i++) { 89 Integer o = new Integer(i); 90 l.add(o); 91 if (i % 10 != 0) { 92 Main.setTag(o, i % 10); 93 } 94 } 95 96 GetTaggedObjectsExpectation exp1 = new GetTaggedObjectsExpectation(18); 97 getTaggedObjectsRun(null, false, false, exp1); 98 99 GetTaggedObjectsExpectation exp2 = new GetTaggedObjectsExpectation(18); 100 exp2.add(l.get(1), 1).add(l.get(11), 1).add(l.get(2), 2).add(l.get(12), 2).add(l.get(3), 3) 101 .add(l.get(13), 3).add(l.get(4), 4).add(l.get(14), 4).add(l.get(5), 5) 102 .add(l.get(15), 5).add(l.get(6), 6).add(l.get(16), 6).add(l.get(7), 7) 103 .add(l.get(17), 7).add(l.get(8), 8).add(l.get(18), 8).add(l.get(9), 9) 104 .add(l.get(19), 9); 105 getTaggedObjectsRun(null, true, true, exp2); 106 107 GetTaggedObjectsExpectation exp3 = new GetTaggedObjectsExpectation(4); 108 exp3.add(l.get(2), 2).add(l.get(12), 2).add(l.get(5), 5).add(l.get(15), 5); 109 getTaggedObjectsRun(new long[] {2, 5}, true, true, exp3); 110 111 GetTaggedObjectsExpectation exp4 = new GetTaggedObjectsExpectation(18); 112 exp4.add(null, 1).add(null, 1).add(null, 2).add(null, 2).add(null, 3).add(null, 3) 113 .add(null, 4).add(null, 4).add(null, 5).add(null, 5).add(null, 6).add(null, 6) 114 .add(null, 7).add(null, 7).add(null, 8).add(null, 8).add(null, 9).add(null, 9); 115 getTaggedObjectsRun(null, false, true, exp4); 116 117 GetTaggedObjectsExpectation exp5 = new GetTaggedObjectsExpectation(18); 118 for (int i = 0; i < l.size(); i++) { 119 if (i % 10 != 0) { 120 exp5.add(l.get(i), 0); 121 } 122 } 123 getTaggedObjectsRun(null, true, false, exp5); 124 125 l = null; 126 Runtime.getRuntime().gc(); 127 Runtime.getRuntime().gc(); 128 } 129 getTaggedObjectsRun(long[] searchTags, boolean returnObjects, boolean returnTags, GetTaggedObjectsExpectation exp)130 private static void getTaggedObjectsRun(long[] searchTags, boolean returnObjects, 131 boolean returnTags, GetTaggedObjectsExpectation exp) { 132 Object[] result = getTaggedObjects(searchTags, returnObjects, returnTags); 133 134 Object[] objects = (Object[]) result[0]; 135 long[] tags = (long[]) result[1]; 136 int count = (int) result[2]; 137 138 exp.check(count, objects, tags); 139 } 140 141 private static class GetTaggedObjectsExpectation { 142 List<Pair> expectations = new LinkedList<>(); 143 int count; 144 GetTaggedObjectsExpectation(int c)145 public GetTaggedObjectsExpectation(int c) { 146 count = c; 147 } 148 check(int count, Object[] objects, long[] tags)149 public void check(int count, Object[] objects, long[] tags) { 150 assertEquals(this.count, count); 151 152 if (objects == null && tags == null) { 153 assertTrue(expectations.isEmpty()); 154 return; 155 } 156 157 int l1 = objects == null ? 0 : objects.length; 158 int l2 = tags == null ? 0 : tags.length; 159 int l = Math.max(l1, l2); 160 List<Pair> tmp = new ArrayList<>(l); 161 for (int i = 0; i < l; i++) { 162 tmp.add(new Pair(objects == null ? null : objects[i], tags == null ? 0 : tags[i])); 163 } 164 Collections.sort(tmp); 165 Collections.sort(expectations); 166 167 if (!expectations.equals(tmp)) { 168 for (int i = 0; i < expectations.size(); i++) { 169 Pair p1 = expectations.get(i); 170 Pair p2 = tmp.get(i); 171 if (!p1.equals(p2)) { 172 String s = "Not equal: " + p1 + "[" + System.identityHashCode(p1.obj) + 173 "] vs " + p2 + "[" + System.identityHashCode(p2.obj); 174 throw new RuntimeException(s); 175 } 176 } 177 } 178 179 assertEquals(expectations, tmp); 180 } 181 add(Object o, long l)182 public GetTaggedObjectsExpectation add(Object o, long l) { 183 expectations.add(new Pair(o, l)); 184 return this; 185 } 186 } 187 188 private static class Pair implements Comparable<Pair> { 189 Object obj; 190 long tag; 191 Pair(Object o, long t)192 public Pair(Object o, long t) { 193 obj = o; 194 tag = t; 195 } 196 197 @Override equals(Object obj)198 public boolean equals(Object obj) { 199 if (obj instanceof Pair) { 200 Pair p = (Pair)obj; 201 return tag == p.tag && (p.obj == null ? this.obj == null : p.obj.equals(this.obj)); 202 } 203 return false; 204 } 205 206 @Override 207 @SuppressWarnings("unchecked") compareTo(Pair p)208 public int compareTo(Pair p) { 209 if (tag != p.tag) { 210 return Long.compare(tag, p.tag); 211 } 212 213 if ((obj instanceof Comparable) && (p.obj instanceof Comparable)) { 214 // It's not really correct, but w/e, best effort. 215 int result = ((Comparable<Object>) obj).compareTo(p.obj); 216 if (result != 0) { 217 return result; 218 } 219 } 220 221 if (obj != null && p.obj != null) { 222 return obj.hashCode() - p.obj.hashCode(); 223 } 224 225 if (obj != null) { 226 return 1; 227 } 228 229 if (p.obj != null) { 230 return -1; 231 } 232 233 return hashCode() - p.hashCode(); 234 } 235 236 @Override toString()237 public String toString() { 238 return "<" + obj + ";" + tag + ">"; 239 } 240 } 241 getTaggedObjects(long[] searchTags, boolean returnObjects, boolean returnTags)242 private static native Object[] getTaggedObjects(long[] searchTags, boolean returnObjects, 243 boolean returnTags); 244 } 245