blob: f463429ef4659d602aac52a866ef2a2b0490143d [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.ArrayList;
import java.util.Collections;
public class Main {
public static void main(String[] args) throws Exception {
System.loadLibrary(args[1]);
doTest();
doFollowReferencesTest();
}
public static void doTest() throws Exception {
setupGcCallback();
enableGcTracking(true);
run();
enableGcTracking(false);
}
private static void run() {
clearStats();
forceGarbageCollection();
printStats();
}
private static void clearStats() {
getGcStarts();
getGcFinishes();
}
private static void printStats() {
System.out.println("---");
int s = getGcStarts();
int f = getGcFinishes();
System.out.println((s > 0) + " " + (f > 0));
}
public static void doFollowReferencesTest() throws Exception {
// Force GCs to clean up dirt.
Runtime.getRuntime().gc();
Runtime.getRuntime().gc();
tagClasses();
setTag(Thread.currentThread(), 3000);
{
ArrayList<Object> tmpStorage = new ArrayList<>();
doFollowReferencesTestNonRoot(tmpStorage);
tmpStorage = null;
}
// Force GCs to clean up dirt.
Runtime.getRuntime().gc();
Runtime.getRuntime().gc();
doFollowReferencesTestRoot();
// Force GCs to clean up dirt.
Runtime.getRuntime().gc();
Runtime.getRuntime().gc();
}
private static void doFollowReferencesTestNonRoot(ArrayList<Object> tmpStorage) {
A a = createTree();
tmpStorage.add(a);
doFollowReferencesTestImpl(null, Integer.MAX_VALUE, -1, null);
doFollowReferencesTestImpl(a, Integer.MAX_VALUE, -1, null);
tmpStorage.clear();
}
private static void doFollowReferencesTestRoot() {
A a = createTree();
doFollowReferencesTestImpl(null, Integer.MAX_VALUE, -1, a);
doFollowReferencesTestImpl(a, Integer.MAX_VALUE, -1, a);
}
private static void doFollowReferencesTestImpl(A root, int stopAfter, int followSet,
Object asRoot) {
String[] lines =
followReferences(0, null, root == null ? null : root.foo, stopAfter, followSet, asRoot);
// Note: sort the roots, as stack locals visit order isn't defined, so may depend on compiled
// code. Do not sort non-roots, as the order here needs to be verified (elements are
// finished before a reference is followed). The test setup (and root visit order)
// luckily ensures that this is deterministic.
int i = 0;
ArrayList<String> rootLines = new ArrayList<>();
while (i < lines.length) {
if (lines[i].startsWith("root")) {
rootLines.add(lines[i]);
} else {
break;
}
i++;
}
Collections.sort(rootLines);
for (String l : rootLines) {
System.out.println(l);
}
// Print the non-root lines in order.
while (i < lines.length) {
System.out.println(lines[i]);
i++;
}
System.out.println("---");
// TODO: Test filters.
}
private static void tagClasses() {
setTag(A.class, 1000);
setTag(B.class, 1001);
setTag(C.class, 1002);
setTag(I1.class, 2000);
setTag(I2.class, 2001);
}
private static A createTree() {
A root = new A();
setTag(root, 1);
A foo = new A();
setTag(foo, 2);
root.foo = foo;
B foo2 = new B();
setTag(foo2, 3);
root.foo2 = foo2;
A bar = new A();
setTag(bar, 4);
foo2.bar = bar;
C bar2 = new C();
setTag(bar2, 5);
foo2.bar2 = bar2;
A baz = new A();
setTag(baz, 6);
bar2.baz = baz;
bar2.baz2 = root;
return root;
}
public static class A {
public A foo;
public A foo2;
public A() {}
public A(A a, A b) {
foo = a;
foo2 = b;
}
}
public static class B extends A {
public A bar;
public A bar2;
public B() {}
public B(A a, A b) {
bar = a;
bar2 = b;
}
}
public static interface I1 {
public final static int i1Field = 1;
}
public static interface I2 extends I1 {
public final static int i2Field = 2;
}
public static class C extends B implements I2 {
public A baz;
public A baz2;
public C() {}
public C(A a, A b) {
baz = a;
baz2 = b;
}
}
private static native void setupGcCallback();
private static native void enableGcTracking(boolean enable);
private static native int getGcStarts();
private static native int getGcFinishes();
private static native void forceGarbageCollection();
private static native void setTag(Object o, long tag);
private static native long getTag(Object o);
private static native String[] followReferences(int heapFilter, Class<?> klassFilter,
Object initialObject, int stopAfter, int followSet, Object jniRef);
}