blob: f463429ef4659d602aac52a866ef2a2b0490143d [file] [log] [blame]
Andreas Gampe8da6d032016-10-31 19:31:03 -07001/*
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
17import java.util.ArrayList;
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070018import java.util.Collections;
Andreas Gampe8da6d032016-10-31 19:31:03 -070019
20public class Main {
21 public static void main(String[] args) throws Exception {
22 System.loadLibrary(args[1]);
23
24 doTest();
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070025 doFollowReferencesTest();
Andreas Gampe8da6d032016-10-31 19:31:03 -070026 }
27
28 public static void doTest() throws Exception {
29 setupGcCallback();
30
31 enableGcTracking(true);
32 run();
33 enableGcTracking(false);
34 }
35
36 private static void run() {
Andreas Gampeef3ace02016-11-01 13:58:14 -070037 clearStats();
Andreas Gampe8da6d032016-10-31 19:31:03 -070038 forceGarbageCollection();
39 printStats();
40 }
41
Andreas Gampeef3ace02016-11-01 13:58:14 -070042 private static void clearStats() {
43 getGcStarts();
44 getGcFinishes();
45 }
46
Andreas Gampe8da6d032016-10-31 19:31:03 -070047 private static void printStats() {
Andreas Gampe70bfc8a2016-11-03 11:04:15 -070048 System.out.println("---");
49 int s = getGcStarts();
50 int f = getGcFinishes();
51 System.out.println((s > 0) + " " + (f > 0));
52 }
53
54 public static void doFollowReferencesTest() throws Exception {
55 // Force GCs to clean up dirt.
56 Runtime.getRuntime().gc();
57 Runtime.getRuntime().gc();
58
59 tagClasses();
60 setTag(Thread.currentThread(), 3000);
61
62 {
63 ArrayList<Object> tmpStorage = new ArrayList<>();
64 doFollowReferencesTestNonRoot(tmpStorage);
65 tmpStorage = null;
66 }
67
68 // Force GCs to clean up dirt.
69 Runtime.getRuntime().gc();
70 Runtime.getRuntime().gc();
71
72 doFollowReferencesTestRoot();
73
74 // Force GCs to clean up dirt.
75 Runtime.getRuntime().gc();
76 Runtime.getRuntime().gc();
77 }
78
79 private static void doFollowReferencesTestNonRoot(ArrayList<Object> tmpStorage) {
80 A a = createTree();
81 tmpStorage.add(a);
82 doFollowReferencesTestImpl(null, Integer.MAX_VALUE, -1, null);
83 doFollowReferencesTestImpl(a, Integer.MAX_VALUE, -1, null);
84 tmpStorage.clear();
85 }
86
87 private static void doFollowReferencesTestRoot() {
88 A a = createTree();
89 doFollowReferencesTestImpl(null, Integer.MAX_VALUE, -1, a);
90 doFollowReferencesTestImpl(a, Integer.MAX_VALUE, -1, a);
91 }
92
93 private static void doFollowReferencesTestImpl(A root, int stopAfter, int followSet,
94 Object asRoot) {
95 String[] lines =
96 followReferences(0, null, root == null ? null : root.foo, stopAfter, followSet, asRoot);
97 // Note: sort the roots, as stack locals visit order isn't defined, so may depend on compiled
98 // code. Do not sort non-roots, as the order here needs to be verified (elements are
99 // finished before a reference is followed). The test setup (and root visit order)
100 // luckily ensures that this is deterministic.
101
102 int i = 0;
103 ArrayList<String> rootLines = new ArrayList<>();
104 while (i < lines.length) {
105 if (lines[i].startsWith("root")) {
106 rootLines.add(lines[i]);
107 } else {
108 break;
109 }
110 i++;
111 }
112 Collections.sort(rootLines);
113 for (String l : rootLines) {
114 System.out.println(l);
115 }
116
117 // Print the non-root lines in order.
118 while (i < lines.length) {
119 System.out.println(lines[i]);
120 i++;
121 }
122
123 System.out.println("---");
124
125 // TODO: Test filters.
126 }
127
128 private static void tagClasses() {
129 setTag(A.class, 1000);
130 setTag(B.class, 1001);
131 setTag(C.class, 1002);
132 setTag(I1.class, 2000);
133 setTag(I2.class, 2001);
134 }
135
136 private static A createTree() {
137 A root = new A();
138 setTag(root, 1);
139
140 A foo = new A();
141 setTag(foo, 2);
142 root.foo = foo;
143
144 B foo2 = new B();
145 setTag(foo2, 3);
146 root.foo2 = foo2;
147
148 A bar = new A();
149 setTag(bar, 4);
150 foo2.bar = bar;
151
152 C bar2 = new C();
153 setTag(bar2, 5);
154 foo2.bar2 = bar2;
155
156 A baz = new A();
157 setTag(baz, 6);
158 bar2.baz = baz;
159 bar2.baz2 = root;
160
161 return root;
162 }
163
164 public static class A {
165 public A foo;
166 public A foo2;
167
168 public A() {}
169 public A(A a, A b) {
170 foo = a;
171 foo2 = b;
172 }
173 }
174
175 public static class B extends A {
176 public A bar;
177 public A bar2;
178
179 public B() {}
180 public B(A a, A b) {
181 bar = a;
182 bar2 = b;
183 }
184 }
185
186 public static interface I1 {
187 public final static int i1Field = 1;
188 }
189
190 public static interface I2 extends I1 {
191 public final static int i2Field = 2;
192 }
193
194 public static class C extends B implements I2 {
195 public A baz;
196 public A baz2;
197
198 public C() {}
199 public C(A a, A b) {
200 baz = a;
201 baz2 = b;
202 }
Andreas Gampe8da6d032016-10-31 19:31:03 -0700203 }
204
205 private static native void setupGcCallback();
206 private static native void enableGcTracking(boolean enable);
207 private static native int getGcStarts();
208 private static native int getGcFinishes();
209 private static native void forceGarbageCollection();
Andreas Gampe70bfc8a2016-11-03 11:04:15 -0700210
211 private static native void setTag(Object o, long tag);
212 private static native long getTag(Object o);
213
214 private static native String[] followReferences(int heapFilter, Class<?> klassFilter,
215 Object initialObject, int stopAfter, int followSet, Object jniRef);
Andreas Gampe8da6d032016-10-31 19:31:03 -0700216}