1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package art; 18 19 import java.util.ArrayList; 20 import java.util.Collections; 21 import java.util.Random; 22 23 public class Test906 { run()24 public static void run() throws Exception { 25 doTest(); 26 } 27 28 // Number of times we will try to count the heap in various ways. If we are unlucky and end up in 29 // the middle of a GC we could incorrectly fail. This is expected to be incredibly rare so 10 30 // retries should be more than sufficient. 31 private static final int ITERATE_RETRIES = 10; 32 private static final class Foobar {} 33 testHeapCount()34 private static void testHeapCount() throws Exception { 35 IllegalStateException lastThrow = new IllegalStateException( 36 "Failed to get consistent counts after " + ITERATE_RETRIES + " retries"); 37 Foobar[] foobars = new Foobar[123]; 38 for (int i = 0; i < foobars.length; i++) { 39 foobars[i] = new Foobar(); 40 } 41 for (int i = 0; i < ITERATE_RETRIES; i++) { 42 try { 43 int all = iterateThroughHeapCount(0, null, Integer.MAX_VALUE); 44 int tagged = iterateThroughHeapCount(HEAP_FILTER_OUT_UNTAGGED, null, Integer.MAX_VALUE); 45 int untagged = iterateThroughHeapCount(HEAP_FILTER_OUT_TAGGED, null, Integer.MAX_VALUE); 46 int taggedClass = iterateThroughHeapCount(HEAP_FILTER_OUT_CLASS_UNTAGGED, null, 47 Integer.MAX_VALUE); 48 int untaggedClass = iterateThroughHeapCount(HEAP_FILTER_OUT_CLASS_TAGGED, null, 49 Integer.MAX_VALUE); 50 int filteredClass = iterateThroughHeapCount(0, Foobar.class, Integer.MAX_VALUE); 51 52 if (all != tagged + untagged) { 53 throw new IllegalStateException("Instances: " + all + " != " + tagged + " + " + untagged); 54 } 55 if (all != taggedClass + untaggedClass) { 56 throw new IllegalStateException("By class: " + all + " != " + taggedClass + " + " + 57 untaggedClass); 58 } 59 if (filteredClass != foobars.length) { 60 throw new IllegalStateException( 61 "Missed objects of foobar type. " + filteredClass + " != " + foobars.length); 62 } 63 if (tagged != 6) { 64 throw new IllegalStateException(tagged + " tagged objects"); 65 } 66 if (taggedClass != 2) { 67 throw new IllegalStateException(tagged + " objects with tagged class"); 68 } 69 if (all == tagged) { 70 throw new IllegalStateException("All objects tagged"); 71 } 72 if (all == taggedClass) { 73 throw new IllegalStateException("All objects have tagged class"); 74 } 75 // Everything worked! 76 return; 77 } catch (IllegalStateException e) { 78 lastThrow.addSuppressed(e); 79 } 80 } 81 throw lastThrow; 82 } 83 GenTs(Class<?> k)84 private static Object[] GenTs(Class<?> k) throws Exception { 85 Object[] ret = new Object[new Random().nextInt(100) + 10]; 86 for (int i = 0; i < ret.length; i++) { 87 ret[i] = k.newInstance(); 88 } 89 return ret; 90 } 91 checkEq(int a, int b)92 private static void checkEq(int a, int b) { 93 if (a != b) { 94 Error e = new Error("Failed: Expected equal " + a + " and " + b); 95 System.out.println(e); 96 e.printStackTrace(System.out); 97 } 98 } 99 100 public static class Foo {} 101 public static class Bar extends Foo {} 102 public static class Baz extends Bar {} 103 public static class Alpha extends Bar {} 104 public static class MISSING extends Baz {} 105 public interface Iface {} 106 public static class Beta implements Iface {} 107 public static class Gamma implements Iface {} 108 public static class Delta extends Beta {} testIterateOverInstances()109 private static void testIterateOverInstances() throws Exception { 110 Object[] foos = GenTs(Foo.class); 111 Object[] bars = GenTs(Bar.class); 112 Object[] bazs = GenTs(Baz.class); 113 Object[] alphas = GenTs(Alpha.class); 114 Object[] betas = GenTs(Beta.class); 115 Object[] gammas = GenTs(Gamma.class); 116 Object[] deltas = GenTs(Delta.class); 117 checkEq(0, iterateOverInstancesCount(MISSING.class)); 118 checkEq(alphas.length, iterateOverInstancesCount(Alpha.class)); 119 checkEq(bazs.length, iterateOverInstancesCount(Baz.class)); 120 checkEq(bazs.length + alphas.length + bars.length, iterateOverInstancesCount(Bar.class)); 121 checkEq(bazs.length + alphas.length + bars.length + foos.length, 122 iterateOverInstancesCount(Foo.class)); 123 checkEq(betas.length + gammas.length + deltas.length, 124 iterateOverInstancesCount(Iface.class)); 125 } 126 doTest()127 public static void doTest() throws Exception { 128 A a = new A(); 129 B b = new B(); 130 B b2 = new B(); 131 C c = new C(); 132 A[] aArray = new A[5]; 133 String s = "Hello World"; 134 135 setTag(a, 1); 136 setTag(b, 2); 137 setTag(b2, 3); 138 setTag(aArray, 4); 139 setTag(s, 5); 140 setTag(B.class, 100); 141 142 testHeapCount(); 143 144 testIterateOverInstances(); 145 146 long classTags[] = new long[100]; 147 long sizes[] = new long[100]; 148 long tags[] = new long[100]; 149 int lengths[] = new int[100]; 150 151 int n = iterateThroughHeapData(HEAP_FILTER_OUT_UNTAGGED, null, classTags, sizes, tags, lengths); 152 System.out.println(sort(n, classTags, sizes, tags, lengths)); 153 154 iterateThroughHeapAdd(HEAP_FILTER_OUT_UNTAGGED, null); 155 n = iterateThroughHeapData(HEAP_FILTER_OUT_UNTAGGED, null, classTags, sizes, tags, lengths); 156 System.out.println(sort(n, classTags, sizes, tags, lengths)); 157 158 System.out.println(iterateThroughHeapString(getTag(s))); 159 System.out.println(getTag(s)); 160 161 boolean[] zArray = new boolean[] { false, true }; 162 setTag(zArray, 1); 163 System.out.println(iterateThroughHeapPrimitiveArray(getTag(zArray))); 164 System.out.println(getTag(zArray)); 165 166 byte[] bArray = new byte[] { 1, 2, 3 }; 167 setTag(bArray, 1); 168 System.out.println(iterateThroughHeapPrimitiveArray(getTag(bArray))); 169 System.out.println(getTag(bArray)); 170 171 char[] cArray = new char[] { 'A', 'Z' }; 172 setTag(cArray, 1); 173 System.out.println(iterateThroughHeapPrimitiveArray(getTag(cArray))); 174 System.out.println(getTag(cArray)); 175 176 short[] sArray = new short[] { 1, 2, 3 }; 177 setTag(sArray, 1); 178 System.out.println(iterateThroughHeapPrimitiveArray(getTag(sArray))); 179 System.out.println(getTag(sArray)); 180 181 int[] iArray = new int[] { 1, 2, 3 }; 182 setTag(iArray, 1); 183 System.out.println(iterateThroughHeapPrimitiveArray(getTag(iArray))); 184 System.out.println(getTag(iArray)); 185 186 float[] fArray = new float[] { 0.0f, 1.0f }; 187 setTag(fArray, 1); 188 System.out.println(iterateThroughHeapPrimitiveArray(getTag(fArray))); 189 System.out.println(getTag(fArray)); 190 191 long[] lArray = new long[] { 1, 2, 3 }; 192 setTag(lArray, 1); 193 System.out.println(iterateThroughHeapPrimitiveArray(getTag(lArray))); 194 System.out.println(getTag(lArray)); 195 196 double[] dArray = new double[] { 0.0, 1.0 }; 197 setTag(dArray, 1); 198 System.out.println(iterateThroughHeapPrimitiveArray(getTag(dArray))); 199 System.out.println(getTag(dArray)); 200 201 // Force GCs to clean up dirt. 202 Runtime.getRuntime().gc(); 203 Runtime.getRuntime().gc(); 204 205 doTestPrimitiveFieldsClasses(); 206 207 doTestPrimitiveFieldsIntegral(); 208 209 // Force GCs to clean up dirt. 210 Runtime.getRuntime().gc(); 211 Runtime.getRuntime().gc(); 212 213 doTestPrimitiveFieldsFloat(); 214 215 // Force GCs to clean up dirt. 216 Runtime.getRuntime().gc(); 217 Runtime.getRuntime().gc(); 218 } 219 doTestPrimitiveFieldsClasses()220 private static void doTestPrimitiveFieldsClasses() { 221 System.out.println("doTestPrimitiveFieldsClasses"); 222 setTag(IntObject.class, 10000); 223 System.out.println(iterateThroughHeapPrimitiveFields(10000)); 224 System.out.println(getTag(IntObject.class)); 225 setTag(IntObject.class, 0); 226 227 setTag(FloatObject.class, 10000); 228 System.out.println(iterateThroughHeapPrimitiveFields(10000)); 229 System.out.println(getTag(FloatObject.class)); 230 setTag(FloatObject.class, 0); 231 232 boolean correctHeapValue = false; 233 setTag(Inf1.class, 10000); 234 String heapTrace = iterateThroughHeapPrimitiveFields(10000); 235 236 if (!checkInitialized(Inf1.class)) { 237 correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000000"); 238 } else { 239 correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000001"); 240 } 241 242 if (!correctHeapValue) 243 System.out.println("Heap Trace for Inf1 is not as expected:\n" + heapTrace); 244 245 System.out.println(getTag(Inf1.class)); 246 setTag(Inf1.class, 0); 247 248 setTag(Inf2.class, 10000); 249 heapTrace = iterateThroughHeapPrimitiveFields(10000); 250 251 if (!checkInitialized(Inf2.class)) { 252 correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000000"); 253 } else { 254 correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000001"); 255 } 256 257 if (!correctHeapValue) 258 System.out.println("Heap Trace for Inf2 is not as expected:\n" + heapTrace); 259 System.out.println(getTag(Inf2.class)); 260 261 setTag(Inf2.class, 0); 262 } 263 doTestPrimitiveFieldsIntegral()264 private static void doTestPrimitiveFieldsIntegral() { 265 System.out.println("doTestPrimitiveFieldsIntegral"); 266 IntObject intObject = new IntObject(); 267 setTag(intObject, 10000); 268 System.out.println(iterateThroughHeapPrimitiveFields(10000)); 269 System.out.println(getTag(intObject)); 270 } 271 doTestPrimitiveFieldsFloat()272 private static void doTestPrimitiveFieldsFloat() { 273 System.out.println("doTestPrimitiveFieldsFloat"); 274 FloatObject floatObject = new FloatObject(); 275 setTag(floatObject, 10000); 276 System.out.println(iterateThroughHeapPrimitiveFields(10000)); 277 System.out.println(getTag(floatObject)); 278 } 279 280 static class A { 281 } 282 283 static class B { 284 } 285 286 static class C { 287 } 288 289 static class HeapElem implements Comparable<HeapElem> { 290 long classTag; 291 long size; 292 long tag; 293 int length; 294 compareTo(HeapElem other)295 public int compareTo(HeapElem other) { 296 if (tag != other.tag) { 297 return Long.compare(tag, other.tag); 298 } 299 if (classTag != other.classTag) { 300 return Long.compare(classTag, other.classTag); 301 } 302 if (size != other.size) { 303 return Long.compare(size, other.size); 304 } 305 return Integer.compare(length, other.length); 306 } 307 toString()308 public String toString() { 309 return "{tag=" + tag + ", class-tag=" + classTag + ", size=" + 310 (tag >= 100 ? "<class>" : size) // Class size is dependent on 32-bit vs 64-bit, 311 // so strip it. 312 + ", length=" + length + "}"; 313 } 314 } 315 sort(int n, long classTags[], long sizes[], long tags[], int lengths[])316 private static ArrayList<HeapElem> sort(int n, long classTags[], long sizes[], long tags[], 317 int lengths[]) { 318 ArrayList<HeapElem> ret = new ArrayList<HeapElem>(n); 319 for (int i = 0; i < n; i++) { 320 HeapElem elem = new HeapElem(); 321 elem.classTag = classTags[i]; 322 elem.size = sizes[i]; 323 elem.tag = tags[i]; 324 elem.length = lengths[i]; 325 ret.add(elem); 326 } 327 Collections.sort(ret); 328 return ret; 329 } 330 331 private static interface Inf1 { 332 public final static int A = 1; 333 } 334 335 private static interface Inf2 extends Inf1 { 336 public final static int B = 1; 337 } 338 339 private static class IntObject implements Inf1 { 340 byte b = (byte)1; 341 char c= 'a'; 342 short s = (short)2; 343 int i = 3; 344 long l = 4; 345 Object o = new Object(); 346 static int sI = 5; 347 } 348 349 private static class FloatObject extends IntObject implements Inf2 { 350 float f = 1.23f; 351 double d = 1.23; 352 Object p = new Object(); 353 static int sI = 6; 354 } 355 356 private final static int HEAP_FILTER_OUT_TAGGED = 0x4; 357 private final static int HEAP_FILTER_OUT_UNTAGGED = 0x8; 358 private final static int HEAP_FILTER_OUT_CLASS_TAGGED = 0x10; 359 private final static int HEAP_FILTER_OUT_CLASS_UNTAGGED = 0x20; 360 setTag(Object o, long tag)361 private static void setTag(Object o, long tag) { 362 Main.setTag(o, tag); 363 } getTag(Object o)364 private static long getTag(Object o) { 365 return Main.getTag(o); 366 } 367 iterateOverInstancesCount(Class<?> klass)368 private static native int iterateOverInstancesCount(Class<?> klass); 369 checkInitialized(Class<?> klass)370 private static native boolean checkInitialized(Class<?> klass); iterateThroughHeapCount(int heapFilter, Class<?> klassFilter, int stopAfter)371 private static native int iterateThroughHeapCount(int heapFilter, 372 Class<?> klassFilter, int stopAfter); iterateThroughHeapData(int heapFilter, Class<?> klassFilter, long classTags[], long sizes[], long tags[], int lengths[])373 private static native int iterateThroughHeapData(int heapFilter, 374 Class<?> klassFilter, long classTags[], long sizes[], long tags[], int lengths[]); iterateThroughHeapAdd(int heapFilter, Class<?> klassFilter)375 private static native int iterateThroughHeapAdd(int heapFilter, 376 Class<?> klassFilter); iterateThroughHeapString(long tag)377 private static native String iterateThroughHeapString(long tag); iterateThroughHeapPrimitiveArray(long tag)378 private static native String iterateThroughHeapPrimitiveArray(long tag); iterateThroughHeapPrimitiveFields(long tag)379 private static native String iterateThroughHeapPrimitiveFields(long tag); 380 } 381