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