18da6d03176651594b821cd3531894c372ca640d5Andreas Gampe/*
28da6d03176651594b821cd3531894c372ca640d5Andreas Gampe * Copyright (C) 2016 The Android Open Source Project
38da6d03176651594b821cd3531894c372ca640d5Andreas Gampe *
48da6d03176651594b821cd3531894c372ca640d5Andreas Gampe * Licensed under the Apache License, Version 2.0 (the "License");
58da6d03176651594b821cd3531894c372ca640d5Andreas Gampe * you may not use this file except in compliance with the License.
68da6d03176651594b821cd3531894c372ca640d5Andreas Gampe * You may obtain a copy of the License at
78da6d03176651594b821cd3531894c372ca640d5Andreas Gampe *
88da6d03176651594b821cd3531894c372ca640d5Andreas Gampe *      http://www.apache.org/licenses/LICENSE-2.0
98da6d03176651594b821cd3531894c372ca640d5Andreas Gampe *
108da6d03176651594b821cd3531894c372ca640d5Andreas Gampe * Unless required by applicable law or agreed to in writing, software
118da6d03176651594b821cd3531894c372ca640d5Andreas Gampe * distributed under the License is distributed on an "AS IS" BASIS,
128da6d03176651594b821cd3531894c372ca640d5Andreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138da6d03176651594b821cd3531894c372ca640d5Andreas Gampe * See the License for the specific language governing permissions and
148da6d03176651594b821cd3531894c372ca640d5Andreas Gampe * limitations under the License.
158da6d03176651594b821cd3531894c372ca640d5Andreas Gampe */
168da6d03176651594b821cd3531894c372ca640d5Andreas Gampe
174665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampepackage art;
184665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe
19037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampeimport java.io.BufferedReader;
20037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampeimport java.io.File;
21037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampeimport java.io.FileReader;
228da6d03176651594b821cd3531894c372ca640d5Andreas Gampeimport java.util.ArrayList;
238a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampeimport java.util.Arrays;
2470bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampeimport java.util.Collections;
255d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampeimport java.util.HashMap;
265d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampeimport java.util.HashSet;
27e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampeimport java.util.concurrent.CountDownLatch;
288da6d03176651594b821cd3531894c372ca640d5Andreas Gampe
294665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampepublic class Test913 {
304665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe  public static void run() throws Exception {
318da6d03176651594b821cd3531894c372ca640d5Andreas Gampe    doTest();
32e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe
33e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe    // Use a countdown latch for synchronization, as join() will introduce more roots.
34e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe    final CountDownLatch cdl1 = new CountDownLatch(1);
35e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe
36e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe    // Run the follow-references tests on a dedicated thread so we know the specific Thread type.
37e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe    Thread t = new Thread() {
38e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe      @Override
39e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe      public void run() {
40e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe        try {
41e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe          Test913.runFollowReferences();
42e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe        } catch (Exception e) {
43e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe          throw new RuntimeException(e);
44e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe        }
45e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe        cdl1.countDown();
46e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe      }
47e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe    };
48e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe    t.start();
49e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe    cdl1.await();
50037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
51037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    doExtensionTests();
52e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe  }
53e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe
54e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe  public static void runFollowReferences() throws Exception {
558a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    new TestConfig().doFollowReferencesTest();
563ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe
575f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe    Runtime.getRuntime().gc();
585f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe    Runtime.getRuntime().gc();
595f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe
60c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe    new TestConfig(null, 0, 1, -1).doFollowReferencesTest();
61c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe
62c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe    Runtime.getRuntime().gc();
63c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe    Runtime.getRuntime().gc();
64c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe
65c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe    new TestConfig(null, 0, Integer.MAX_VALUE, 1).doFollowReferencesTest();
66c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe
67c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe    Runtime.getRuntime().gc();
68c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe    Runtime.getRuntime().gc();
69c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe
703ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe    doStringTest();
715f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe
725f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe    Runtime.getRuntime().gc();
735f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe    Runtime.getRuntime().gc();
745f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe
75becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    doPrimitiveArrayTest();
76e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    doPrimitiveFieldTest();
7738da9f2c12d5e094bebf9c0982a82aa7648c200aAndreas Gampe
785f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe    Runtime.getRuntime().gc();
795f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe    Runtime.getRuntime().gc();
805f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe
8138da9f2c12d5e094bebf9c0982a82aa7648c200aAndreas Gampe    // Test klass filter.
8238da9f2c12d5e094bebf9c0982a82aa7648c200aAndreas Gampe    System.out.println("--- klass ---");
8338da9f2c12d5e094bebf9c0982a82aa7648c200aAndreas Gampe    new TestConfig(A.class, 0).doFollowReferencesTest();
846ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe
856ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe    // Test heap filter.
866ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe    System.out.println("--- heap_filter ---");
876ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe    System.out.println("---- tagged objects");
886ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe    new TestConfig(null, 0x4).doFollowReferencesTest();
896ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe    System.out.println("---- untagged objects");
906ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe    new TestConfig(null, 0x8).doFollowReferencesTest();
916ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe    System.out.println("---- tagged classes");
926ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe    new TestConfig(null, 0x10).doFollowReferencesTest();
936ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe    System.out.println("---- untagged classes");
946ea0607fcda940748580b0b68a2da8ea61da4719Andreas Gampe    new TestConfig(null, 0x20).doFollowReferencesTest();
958da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  }
968da6d03176651594b821cd3531894c372ca640d5Andreas Gampe
978da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  public static void doTest() throws Exception {
988da6d03176651594b821cd3531894c372ca640d5Andreas Gampe    setupGcCallback();
998da6d03176651594b821cd3531894c372ca640d5Andreas Gampe
1008da6d03176651594b821cd3531894c372ca640d5Andreas Gampe    enableGcTracking(true);
1014665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe    runGc();
1028da6d03176651594b821cd3531894c372ca640d5Andreas Gampe    enableGcTracking(false);
1038da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  }
1048da6d03176651594b821cd3531894c372ca640d5Andreas Gampe
1053ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe  public static void doStringTest() throws Exception {
1065f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe    final String str = new String("HelloWorld");
1075f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe    final String str2 = new String("");
1083ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe    Object o = new Object() {
1093ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe      String s = str;
1105f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe      String s2 = str2;
1113ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe    };
1123ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe
1133ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe    setTag(str, 1);
1145f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe    setTag(str2, 2);
1153ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe    System.out.println(Arrays.toString(followReferencesString(o)));
1163ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe    System.out.println(getTag(str));
1175f942039b83ec9a54aaa0d6badec4d26a921027bAndreas Gampe    System.out.println(getTag(str2));
1183ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe  }
1193ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe
120becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe  public static void doPrimitiveArrayTest() throws Exception {
121becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    final boolean[] zArray = new boolean[] { false, true };
122becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    setTag(zArray, 1);
123becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe
124becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    final byte[] bArray = new byte[] { 1, 2, 3 };
125becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    setTag(bArray, 2);
126becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe
127becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    final char[] cArray = new char[] { 'A', 'Z' };
128becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    setTag(cArray, 3);
129becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe
130becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    final short[] sArray = new short[] { 1, 2, 3 };
131becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    setTag(sArray, 4);
132becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe
133becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    final int[] iArray = new int[] { 1, 2, 3 };
134becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    setTag(iArray, 5);
135becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe
136becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    final float[] fArray = new float[] { 0.0f, 1.0f };
137becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    setTag(fArray, 6);
138becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe
139becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    final long[] lArray = new long[] { 1, 2, 3 };
140becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    setTag(lArray, 7);
141becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe
142becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    final double[] dArray = new double[] { 0.0, 1.0 };
143becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    setTag(dArray, 8);
144becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe
145becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    Object o = new Object() {
146becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe      Object z = zArray;
147becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe      Object b = bArray;
148becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe      Object c = cArray;
149becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe      Object s = sArray;
150becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe      Object i = iArray;
151becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe      Object f = fArray;
152becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe      Object l = lArray;
153becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe      Object d = dArray;
154becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    };
155becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe
156becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    System.out.println(followReferencesPrimitiveArray(o));
157becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    System.out.print(getTag(zArray));
158becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    System.out.print(getTag(bArray));
159becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    System.out.print(getTag(cArray));
160becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    System.out.print(getTag(sArray));
161becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    System.out.print(getTag(iArray));
162becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    System.out.print(getTag(fArray));
163becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    System.out.print(getTag(lArray));
164becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe    System.out.println(getTag(dArray));
165becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe  }
166becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe
167e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  public static void doPrimitiveFieldTest() throws Exception {
168e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    // Force GCs to clean up dirt.
169e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    Runtime.getRuntime().gc();
170e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    Runtime.getRuntime().gc();
171e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
172e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    doTestPrimitiveFieldsClasses();
173e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
174e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    doTestPrimitiveFieldsIntegral();
175e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
176e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    // Force GCs to clean up dirt.
177e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    Runtime.getRuntime().gc();
178e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    Runtime.getRuntime().gc();
179e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
180e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    doTestPrimitiveFieldsFloat();
181e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
182e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    // Force GCs to clean up dirt.
183e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    Runtime.getRuntime().gc();
184e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    Runtime.getRuntime().gc();
185e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  }
186e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
187e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  private static void doTestPrimitiveFieldsClasses() {
188e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    setTag(IntObject.class, 10000);
189e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(followReferencesPrimitiveFields(IntObject.class));
190e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(getTag(IntObject.class));
191e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    setTag(IntObject.class, 0);
192e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
193e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    setTag(FloatObject.class, 10000);
194e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(followReferencesPrimitiveFields(FloatObject.class));
195e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(getTag(FloatObject.class));
196e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    setTag(FloatObject.class, 0);
197e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
198e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    setTag(Inf1.class, 10000);
199e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(followReferencesPrimitiveFields(Inf1.class));
200e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(getTag(Inf1.class));
201e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    setTag(Inf1.class, 0);
202e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
203e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    setTag(Inf2.class, 10000);
204e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(followReferencesPrimitiveFields(Inf2.class));
205e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(getTag(Inf2.class));
206e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    setTag(Inf2.class, 0);
207e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  }
208e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
209e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  private static void doTestPrimitiveFieldsIntegral() {
210e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    IntObject intObject = new IntObject();
211e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    setTag(intObject, 10000);
212e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(followReferencesPrimitiveFields(intObject));
213e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(getTag(intObject));
214e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  }
215e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
216e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  private static void doTestPrimitiveFieldsFloat() {
217e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    FloatObject floatObject = new FloatObject();
218e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    setTag(floatObject, 10000);
219e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(followReferencesPrimitiveFields(floatObject));
220e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    System.out.println(getTag(floatObject));
221e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  }
222e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
223037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe  static ArrayList<Object> extensionTestHolder;
224037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
225037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe  private static void doExtensionTests() {
226037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    checkForExtensionApis();
227037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
228037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    extensionTestHolder = new ArrayList<>();
229037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    System.out.println();
230037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
231037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    try {
232037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      getHeapName(-1);
233037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      System.out.println("Expected failure for -1");
234037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    } catch (Exception e) {
235037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    }
236037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    System.out.println(getHeapName(0));
237037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    System.out.println(getHeapName(1));
238037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    System.out.println(getHeapName(2));
239037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    System.out.println(getHeapName(3));
240037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    try {
241037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      getHeapName(4);
242037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      System.out.println("Expected failure for -1");
243037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    } catch (Exception e) {
244037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    }
245037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
246037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    System.out.println();
247037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
248037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    setTag(Object.class, 100000);
249037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    int objectClassHeapId = getObjectHeapId(100000);
250037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    int objClassExpectedHeapId = hasImage() ? 1 : 3;
251037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    if (objectClassHeapId != objClassExpectedHeapId) {
252037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      throw new RuntimeException("Expected object class in heap " + objClassExpectedHeapId +
253037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe          " but received " + objectClassHeapId);
254037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    }
255037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
256037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    A a = new A();
257037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    extensionTestHolder.add(a);
258037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    setTag(a, 100001);
259037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    System.out.println(getObjectHeapId(100001));
260037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
261037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    checkGetObjectHeapIdInCallback(100000, objClassExpectedHeapId);
262037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    checkGetObjectHeapIdInCallback(100001, 3);
263037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
2648b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe    long baseTag = 30000000;
2658b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe    setTag(Object.class, baseTag + objClassExpectedHeapId);
2668b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe    setTag(Class.class, baseTag + objClassExpectedHeapId);
2678b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe    Object o = new Object();
2688b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe    extensionTestHolder.add(o);
2698b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe    setTag(o, baseTag + 3);
2708b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe
2718b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe    iterateThroughHeapExt();
2728b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe
273037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    extensionTestHolder = null;
274037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe  }
275037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
2764665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe  private static void runGc() {
277ef3ace09cc19776afcd99e54e12f0b86b8866a7cAndreas Gampe    clearStats();
2788da6d03176651594b821cd3531894c372ca640d5Andreas Gampe    forceGarbageCollection();
2798da6d03176651594b821cd3531894c372ca640d5Andreas Gampe    printStats();
2808da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  }
2818da6d03176651594b821cd3531894c372ca640d5Andreas Gampe
282ef3ace09cc19776afcd99e54e12f0b86b8866a7cAndreas Gampe  private static void clearStats() {
283ef3ace09cc19776afcd99e54e12f0b86b8866a7cAndreas Gampe    getGcStarts();
284ef3ace09cc19776afcd99e54e12f0b86b8866a7cAndreas Gampe    getGcFinishes();
285ef3ace09cc19776afcd99e54e12f0b86b8866a7cAndreas Gampe  }
286ef3ace09cc19776afcd99e54e12f0b86b8866a7cAndreas Gampe
2878da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  private static void printStats() {
28870bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    System.out.println("---");
28970bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    int s = getGcStarts();
29070bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    int f = getGcFinishes();
29170bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    System.out.println((s > 0) + " " + (f > 0));
29270bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  }
29370bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
294037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe  private static boolean hasImage() {
295037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    try {
296037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
297037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      BufferedReader reader = new BufferedReader(new FileReader("/proc/" + pid + "/maps"));
298037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      String line;
299037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      while ((line = reader.readLine()) != null) {
300037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe        if (line.endsWith(".art")) {
301037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe          reader.close();
302037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe          return true;
303037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe        }
304037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      }
305037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      reader.close();
306037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      return false;
307037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    } catch (Exception e) {
308037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe      throw new RuntimeException(e);
309037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe    }
310037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe  }
311037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
3128a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe  private static class TestConfig {
3138a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    private Class<?> klass = null;
3148a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    private int heapFilter = 0;
315c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe    private int stopAfter = Integer.MAX_VALUE;
316c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe    private int followSet = -1;
31770bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
3188a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    public TestConfig() {
3198a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    }
3208a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    public TestConfig(Class<?> klass, int heapFilter) {
3218a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      this.klass = klass;
3228a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      this.heapFilter = heapFilter;
32370bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    }
324c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe    public TestConfig(Class<?> klass, int heapFilter, int stopAfter, int followSet) {
325c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe      this.klass = klass;
326c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe      this.heapFilter = heapFilter;
327c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe      this.stopAfter = stopAfter;
328c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe      this.followSet = followSet;
329c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe    }
33070bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
3318a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    public void doFollowReferencesTest() throws Exception {
3328a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      // Force GCs to clean up dirt.
3338a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      Runtime.getRuntime().gc();
3348a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      Runtime.getRuntime().gc();
33570bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
3368a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(Thread.currentThread(), 3000);
33770bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
3388a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      {
3398a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        ArrayList<Object> tmpStorage = new ArrayList<>();
3408a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        doFollowReferencesTestNonRoot(tmpStorage);
3418a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        tmpStorage = null;
3428a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      }
34370bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
3448a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      // Force GCs to clean up dirt.
3458a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      Runtime.getRuntime().gc();
3468a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      Runtime.getRuntime().gc();
3475d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
3488a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      doFollowReferencesTestRoot();
3495d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
3508a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      // Force GCs to clean up dirt.
3518a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      Runtime.getRuntime().gc();
3528a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      Runtime.getRuntime().gc();
3538a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    }
35470bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
3558a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    private void doFollowReferencesTestNonRoot(ArrayList<Object> tmpStorage) {
3568a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      Verifier v = new Verifier();
3578a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      tagClasses(v);
3588a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      A a = createTree(v);
3598a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      tmpStorage.add(a);
3608a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add("0@0", "1@1000");  // tmpStorage[0] --(array-element)--> a.
3615d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
362c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe      doFollowReferencesTestImpl(null, stopAfter, followSet, null, v, null);
363c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe      doFollowReferencesTestImpl(a.foo2, stopAfter, followSet, null, v, "3@1001");
36470bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
3658a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      tmpStorage.clear();
3668a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    }
36770bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
3688a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    private void doFollowReferencesTestRoot() {
3698a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      Verifier v = new Verifier();
3708a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      tagClasses(v);
3718a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      A a = createTree(v);
37270bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
373c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe      doFollowReferencesTestImpl(null, stopAfter, followSet, a, v, null);
374c756f08bdc8bd3ea397b85531f397b2b29cd419bAndreas Gampe      doFollowReferencesTestImpl(a.foo2, stopAfter, followSet, a, v, "3@1001");
3758a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    }
37670bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
3778a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    private void doFollowReferencesTestImpl(A root, int stopAfter, int followSet,
3788a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        Object asRoot, Verifier v, String additionalEnabled) {
3798a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      String[] lines =
3808a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe          followReferences(heapFilter, klass, root, stopAfter, followSet, asRoot);
3815d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
3828a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.process(lines, additionalEnabled, heapFilter != 0 || klass != null);
3838a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    }
3845d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
3858a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    private static void tagClasses(Verifier v) {
3868a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(A.class, 1000);
3875d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
3888a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(B.class, 1001);
3898a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add("1001@0", "1000@0");  // B.class --(superclass)--> A.class.
3905d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
3918a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(C.class, 1002);
3928a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add("1002@0", "1001@0");  // C.class --(superclass)--> B.class.
3938a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add("1002@0", "2001@0");  // C.class --(interface)--> I2.class.
3948a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
3958a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(I1.class, 2000);
39670bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
3978a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(I2.class, 2001);
3988a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add("2001@0", "2000@0");  // I2.class --(interface)--> I1.class.
3998a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    }
4008a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
4018a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    private static A createTree(Verifier v) {
4028a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      A aInst = new A();
4038a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(aInst, 1);
4048a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      String aInstStr = "1@1000";
4058a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      String aClassStr = "1000@0";
4068a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(aInstStr, aClassStr);  // A -->(class) --> A.class.
4078a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
4088a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      A a2Inst = new A();
4098a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(a2Inst, 2);
4108a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      aInst.foo = a2Inst;
4118a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      String a2InstStr = "2@1000";
4128a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(a2InstStr, aClassStr);  // A2 -->(class) --> A.class.
4138a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(aInstStr, a2InstStr);   // A -->(field) --> A2.
4148a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
4158a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      B bInst = new B();
4168a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(bInst, 3);
4178a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      aInst.foo2 = bInst;
4188a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      String bInstStr = "3@1001";
4198a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      String bClassStr = "1001@0";
4208a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(bInstStr, bClassStr);  // B -->(class) --> B.class.
4218a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(aInstStr, bInstStr);   // A -->(field) --> B.
4228a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
4238a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      A a3Inst = new A();
4248a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(a3Inst, 4);
4258a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      bInst.bar = a3Inst;
4268a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      String a3InstStr = "4@1000";
4278a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(a3InstStr, aClassStr);  // A3 -->(class) --> A.class.
4288a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(bInstStr, a3InstStr);   // B -->(field) --> A3.
4298a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
4308a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      C cInst = new C();
4318a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(cInst, 5);
4328a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      bInst.bar2 = cInst;
4338a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      String cInstStr = "5@1000";
4348a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      String cClassStr = "1002@0";
4358a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(cInstStr, cClassStr);  // C -->(class) --> C.class.
4368a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(bInstStr, cInstStr);   // B -->(field) --> C.
4378a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
4388a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      A a4Inst = new A();
4398a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      setTag(a4Inst, 6);
4408a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      cInst.baz = a4Inst;
4418a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      String a4InstStr = "6@1000";
4428a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(a4InstStr, aClassStr);  // A4 -->(class) --> A.class.
4438a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(cInstStr, a4InstStr);   // C -->(field) --> A4.
4448a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
4458a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      cInst.baz2 = aInst;
4468a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      v.add(cInstStr, aInstStr);  // C -->(field) --> A.
4478a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
4481dfd10ec49a0734d4f533a7cc2950102fbbbff89Andreas Gampe      A[] aArray = new A[2];
4491dfd10ec49a0734d4f533a7cc2950102fbbbff89Andreas Gampe      setTag(aArray, 500);
4501dfd10ec49a0734d4f533a7cc2950102fbbbff89Andreas Gampe      aArray[1] = a2Inst;
4511dfd10ec49a0734d4f533a7cc2950102fbbbff89Andreas Gampe      cInst.array = aArray;
4521dfd10ec49a0734d4f533a7cc2950102fbbbff89Andreas Gampe      String aArrayStr = "500@0";
4531dfd10ec49a0734d4f533a7cc2950102fbbbff89Andreas Gampe      v.add(cInstStr, aArrayStr);
4541dfd10ec49a0734d4f533a7cc2950102fbbbff89Andreas Gampe      v.add(aArrayStr, a2InstStr);
4551dfd10ec49a0734d4f533a7cc2950102fbbbff89Andreas Gampe
4568a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      return aInst;
4578a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    }
45870bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  }
45970bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
46070bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  public static class A {
46170bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public A foo;
46270bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public A foo2;
46370bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
46470bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public A() {}
46570bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public A(A a, A b) {
46670bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe      foo = a;
46770bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe      foo2 = b;
46870bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    }
46970bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  }
47070bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
47170bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  public static class B extends A {
47270bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public A bar;
47370bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public A bar2;
47470bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
47570bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public B() {}
47670bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public B(A a, A b) {
47770bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe      bar = a;
47870bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe      bar2 = b;
47970bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    }
48070bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  }
48170bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
48270bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  public static interface I1 {
48370bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public final static int i1Field = 1;
48470bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  }
48570bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
48670bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  public static interface I2 extends I1 {
48770bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public final static int i2Field = 2;
48870bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  }
48970bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
49070bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe  public static class C extends B implements I2 {
49170bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public A baz;
49270bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public A baz2;
4931dfd10ec49a0734d4f533a7cc2950102fbbbff89Andreas Gampe    public A[] array;
49470bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
49570bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public C() {}
49670bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    public C(A a, A b) {
49770bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe      baz = a;
49870bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe      baz2 = b;
49970bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe    }
5008da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  }
5018da6d03176651594b821cd3531894c372ca640d5Andreas Gampe
502e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  private static interface Inf1 {
503e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    public final static int A = 1;
504e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  }
505e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
506e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  private static interface Inf2 extends Inf1 {
507e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    public final static int B = 1;
508e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  }
509e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
510e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  private static class IntObject implements Inf1 {
511e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    byte b = (byte)1;
512e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    char c= 'a';
513e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    short s = (short)2;
514e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    int i = 3;
515e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    long l = 4;
516e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    Object o = new Object();
517e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    static int sI = 5;
518e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  }
519e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
520e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  private static class FloatObject extends IntObject implements Inf2 {
521e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    float f = 1.23f;
522e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    double d = 1.23;
523e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    Object p = new Object();
524e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe    static int sI = 6;
525e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  }
526e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe
5275d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe  public static class Verifier {
52858982d596d210dd93999826f5027f6583a0905ccAndreas Gampe    // Should roots with vreg=-1 be printed?
52958982d596d210dd93999826f5027f6583a0905ccAndreas Gampe    public final static boolean PRINT_ROOTS_WITH_UNKNOWN_VREG = false;
53058982d596d210dd93999826f5027f6583a0905ccAndreas Gampe
5315d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    public static class Node {
5325d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      public String referrer;
5335d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5345d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      public HashSet<String> referrees = new HashSet<>();
5355d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5365d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      public Node(String r) {
5375d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        referrer = r;
5385d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
5395d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5405d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      public boolean isRoot() {
5415d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        return referrer.startsWith("root@");
5425d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
5435d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    }
5445d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5455d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    HashMap<String, Node> nodes = new HashMap<>();
5465d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5475d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    public Verifier() {
5485d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    }
5495d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5505d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    public void add(String referrer, String referree) {
5515d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      if (!nodes.containsKey(referrer)) {
5525d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        nodes.put(referrer, new Node(referrer));
5535d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
5545d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      if (referree != null) {
5555d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        nodes.get(referrer).referrees.add(referree);
5565d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
5575d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    }
5585d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5598a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe    public void process(String[] lines, String additionalEnabledReferrer, boolean filtered) {
5605d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      // This method isn't optimal. The loops could be merged. However, it's more readable if
5615d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      // the different parts are separated.
5625d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5635d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      ArrayList<String> rootLines = new ArrayList<>();
5645d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      ArrayList<String> nonRootLines = new ArrayList<>();
5655d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5665d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      // Check for consecutive chunks of referrers. Also ensure roots come first.
5675d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      {
5685d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        String currentHead = null;
5695d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        boolean rootsDone = false;
5705d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        HashSet<String> completedReferrers = new HashSet<>();
5715d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        for (String l : lines) {
5725d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          String referrer = getReferrer(l);
5735d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5745d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          if (isRoot(referrer)) {
5755d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe            if (rootsDone) {
5765d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe              System.out.println("ERROR: Late root " + l);
5775d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe              print(lines);
5785d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe              return;
5795d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe            }
5805d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe            rootLines.add(l);
5815d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe            continue;
5825d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          }
5835d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5845d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          rootsDone = true;
5855d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
5865d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          if (currentHead == null) {
5875d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe            currentHead = referrer;
5885d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          } else {
589e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe            // Ignore 0@0, as it can happen at any time (as it stands for all other objects).
590e0f8ed966a22834815c8ec1a9ddbf0bfd35865eaAndreas Gampe            if (!currentHead.equals(referrer) && !referrer.equals("0@0")) {
5915d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe              completedReferrers.add(currentHead);
5925d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe              currentHead = referrer;
5935d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe              if (completedReferrers.contains(referrer)) {
5945d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe                System.out.println("Non-contiguous referrer " + l);
5955d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe                print(lines);
5965d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe                return;
5975d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe              }
5985d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe            }
5995d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          }
6005d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          nonRootLines.add(l);
6015d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        }
6025d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
6035d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
6045d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      // Sort (root order is not specified) and print the roots.
6055d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      // TODO: What about extra roots? JNI and the interpreter seem to introduce those (though it
6065d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      //       isn't clear why a debuggable-AoT test doesn't have the same, at least for locals).
6075d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      //       For now, swallow duplicates, and resolve once we have the metadata for the roots.
6085d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      {
6095d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        Collections.sort(rootLines);
6105d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        String lastRoot = null;
6115d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        for (String l : rootLines) {
6125d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          if (lastRoot != null && lastRoot.equals(l)) {
6135d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe            continue;
6145d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          }
6155d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          lastRoot = l;
61658982d596d210dd93999826f5027f6583a0905ccAndreas Gampe          if (!PRINT_ROOTS_WITH_UNKNOWN_VREG && l.indexOf("vreg=-1") > 0) {
61758982d596d210dd93999826f5027f6583a0905ccAndreas Gampe            continue;
61858982d596d210dd93999826f5027f6583a0905ccAndreas Gampe          }
6195d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          System.out.println(l);
6205d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        }
6215d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
6225d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
6238a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      if (filtered) {
6248a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        // If we aren't tracking dependencies, just sort the lines and print.
6258a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        // TODO: As the verifier is currently using the output lines to track dependencies, we
6268a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        //       cannot verify that output is correct when parts of it are suppressed by filters.
6278a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        //       To correctly track this we need to take node information into account, and
6288a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        //       actually analyze the graph.
6298a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        Collections.sort(nonRootLines);
6308a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        for (String l : nonRootLines) {
6318a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe          System.out.println(l);
6328a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        }
6338a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
6348a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        System.out.println("---");
6358a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe        return;
6368a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe      }
6378a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe
6385d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      // Iterate through the lines, keeping track of which referrers are visited, to ensure the
6395d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      // order is acceptable.
6405d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      HashSet<String> enabled = new HashSet<>();
6415d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      if (additionalEnabledReferrer != null) {
6425d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        enabled.add(additionalEnabledReferrer);
6435d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
6445d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      // Always add "0@0".
6455d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      enabled.add("0@0");
6465d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
6475d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      for (String l : lines) {
6485d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        String referrer = getReferrer(l);
6495d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        String referree = getReferree(l);
6505d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        if (isRoot(referrer)) {
6515d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          // For a root src, just enable the referree.
6525d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          enabled.add(referree);
6535d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        } else {
6545d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          // Check that the referrer is enabled (may be visited).
6555d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          if (!enabled.contains(referrer)) {
6565d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe            System.out.println("Referrer " + referrer + " not enabled: " + l);
6575d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe            print(lines);
6585d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe            return;
6595d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          }
6605d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe          enabled.add(referree);
6615d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        }
6625d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
6635d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
6645d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      // Now just sort the non-root lines and output them
6655d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      Collections.sort(nonRootLines);
6665d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      for (String l : nonRootLines) {
6675d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        System.out.println(l);
6685d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
6695d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
6705d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      System.out.println("---");
6715d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    }
6725d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
6735d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    public static boolean isRoot(String ref) {
6745d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      return ref.startsWith("root@");
6755d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    }
6765d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
6775d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    private static String getReferrer(String line) {
6785d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      int i = line.indexOf(" --");
6795d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      if (i <= 0) {
6805d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        throw new IllegalArgumentException(line);
6815d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
6825d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      int j = line.indexOf(' ');
6835d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      if (i != j) {
6845d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        throw new IllegalArgumentException(line);
6855d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
6865d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      return line.substring(0, i);
6875d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    }
6885d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
6895d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    private static String getReferree(String line) {
6905d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      int i = line.indexOf("--> ");
6915d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      if (i <= 0) {
6925d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        throw new IllegalArgumentException(line);
6935d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
6945d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      int j = line.indexOf(' ', i + 4);
6955d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      if (j < 0) {
6965d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        throw new IllegalArgumentException(line);
6975d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
6985d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      return line.substring(i + 4, j);
6995d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    }
7005d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
7015d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    private static void print(String[] lines) {
7025d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      for (String l : lines) {
7035d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe        System.out.println(l);
7045d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe      }
7055d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe    }
7065d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe  }
7075d139fc3898bad69b95a5e8583e4a7b2cc00c0b0Andreas Gampe
7084665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe  private static void setTag(Object o, long tag) {
7094665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe    Main.setTag(o, tag);
7104665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe  }
7114665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe  private static long getTag(Object o) {
7124665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe    return Main.getTag(o);
7134665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe  }
7144665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe
7158da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  private static native void setupGcCallback();
7168da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  private static native void enableGcTracking(boolean enable);
7178da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  private static native int getGcStarts();
7188da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  private static native int getGcFinishes();
7198da6d03176651594b821cd3531894c372ca640d5Andreas Gampe  private static native void forceGarbageCollection();
72070bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe
721037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe  private static native void checkForExtensionApis();
722037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe  private static native int getObjectHeapId(long tag);
723037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe  private static native String getHeapName(int heapId);
724037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe  private static native void checkGetObjectHeapIdInCallback(long tag, int heapId);
725037b8b7503ce47dd39d554e85a0bcb904c9f2127Andreas Gampe
7268a5550dc29a69a5b3e246385bfe1c4cf26b9f39aAndreas Gampe  public static native String[] followReferences(int heapFilter, Class<?> klassFilter,
72770bfc8a5783044762cab864fc0ba26d9cc821ee3Andreas Gampe      Object initialObject, int stopAfter, int followSet, Object jniRef);
7283ec8e40930c87be425a4e74d6a617b6396cfe003Andreas Gampe  public static native String[] followReferencesString(Object initialObject);
729becd6addfe1cb8326cc8ada5828c83f201124797Andreas Gampe  public static native String followReferencesPrimitiveArray(Object initialObject);
730e731693fd63bfa7d528d8aeaccc1118b920af1dbAndreas Gampe  public static native String followReferencesPrimitiveFields(Object initialObject);
7318b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe
7328b3ce5ea35ee1a5965a39e9f3762aaa50437ce4dAndreas Gampe  private static native void iterateThroughHeapExt();
7338da6d03176651594b821cd3531894c372ca640d5Andreas Gampe}
734