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.io.BufferedReader;
20 import java.io.File;
21 import java.io.FileReader;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.concurrent.CountDownLatch;
28 
29 public class Test913 {
run()30   public static void run() throws Exception {
31     doTest();
32 
33     // Use a countdown latch for synchronization, as join() will introduce more roots.
34     final CountDownLatch cdl1 = new CountDownLatch(1);
35 
36     // Run the follow-references tests on a dedicated thread so we know the specific Thread type.
37     Thread t = new Thread() {
38       @Override
39       public void run() {
40         try {
41           Test913.runFollowReferences();
42         } catch (Exception e) {
43           throw new RuntimeException(e);
44         }
45         cdl1.countDown();
46       }
47     };
48     t.start();
49     cdl1.await();
50 
51     doExtensionTests();
52   }
53 
runFollowReferences()54   public static void runFollowReferences() throws Exception {
55     new TestConfig().doFollowReferencesTest();
56 
57     Runtime.getRuntime().gc();
58     Runtime.getRuntime().gc();
59 
60     new TestConfig(null, 0, 1, -1).doFollowReferencesTest();
61 
62     Runtime.getRuntime().gc();
63     Runtime.getRuntime().gc();
64 
65     new TestConfig(null, 0, Integer.MAX_VALUE, 1).doFollowReferencesTest();
66 
67     Runtime.getRuntime().gc();
68     Runtime.getRuntime().gc();
69 
70     doStringTest();
71 
72     Runtime.getRuntime().gc();
73     Runtime.getRuntime().gc();
74 
75     doPrimitiveArrayTest();
76     doPrimitiveFieldTest();
77 
78     Runtime.getRuntime().gc();
79     Runtime.getRuntime().gc();
80 
81     // Test klass filter.
82     System.out.println("--- klass ---");
83     new TestConfig(A.class, 0).doFollowReferencesTest();
84 
85     // Test heap filter.
86     System.out.println("--- heap_filter ---");
87     System.out.println("---- tagged objects");
88     new TestConfig(null, 0x4).doFollowReferencesTest();
89     System.out.println("---- untagged objects");
90     new TestConfig(null, 0x8).doFollowReferencesTest();
91     System.out.println("---- tagged classes");
92     new TestConfig(null, 0x10).doFollowReferencesTest();
93     System.out.println("---- untagged classes");
94     new TestConfig(null, 0x20).doFollowReferencesTest();
95   }
96 
doTest()97   public static void doTest() throws Exception {
98     setupGcCallback();
99 
100     enableGcTracking(true);
101     runGc();
102     enableGcTracking(false);
103   }
104 
doStringTest()105   public static void doStringTest() throws Exception {
106     final String str = new String("HelloWorld");
107     final String str2 = new String("");
108     Object o = new Object() {
109       String s = str;
110       String s2 = str2;
111     };
112 
113     setTag(str, 1);
114     setTag(str2, 2);
115     System.out.println(Arrays.toString(followReferencesString(o)));
116     System.out.println(getTag(str));
117     System.out.println(getTag(str2));
118   }
119 
doPrimitiveArrayTest()120   public static void doPrimitiveArrayTest() throws Exception {
121     final boolean[] zArray = new boolean[] { false, true };
122     setTag(zArray, 1);
123 
124     final byte[] bArray = new byte[] { 1, 2, 3 };
125     setTag(bArray, 2);
126 
127     final char[] cArray = new char[] { 'A', 'Z' };
128     setTag(cArray, 3);
129 
130     final short[] sArray = new short[] { 1, 2, 3 };
131     setTag(sArray, 4);
132 
133     final int[] iArray = new int[] { 1, 2, 3 };
134     setTag(iArray, 5);
135 
136     final float[] fArray = new float[] { 0.0f, 1.0f };
137     setTag(fArray, 6);
138 
139     final long[] lArray = new long[] { 1, 2, 3 };
140     setTag(lArray, 7);
141 
142     final double[] dArray = new double[] { 0.0, 1.0 };
143     setTag(dArray, 8);
144 
145     Object o = new Object() {
146       Object z = zArray;
147       Object b = bArray;
148       Object c = cArray;
149       Object s = sArray;
150       Object i = iArray;
151       Object f = fArray;
152       Object l = lArray;
153       Object d = dArray;
154     };
155 
156     System.out.println(followReferencesPrimitiveArray(o));
157     System.out.print(getTag(zArray));
158     System.out.print(getTag(bArray));
159     System.out.print(getTag(cArray));
160     System.out.print(getTag(sArray));
161     System.out.print(getTag(iArray));
162     System.out.print(getTag(fArray));
163     System.out.print(getTag(lArray));
164     System.out.println(getTag(dArray));
165   }
166 
doPrimitiveFieldTest()167   public static void doPrimitiveFieldTest() throws Exception {
168     // Force GCs to clean up dirt.
169     Runtime.getRuntime().gc();
170     Runtime.getRuntime().gc();
171 
172     doTestPrimitiveFieldsClasses();
173 
174     doTestPrimitiveFieldsIntegral();
175 
176     // Force GCs to clean up dirt.
177     Runtime.getRuntime().gc();
178     Runtime.getRuntime().gc();
179 
180     doTestPrimitiveFieldsFloat();
181 
182     // Force GCs to clean up dirt.
183     Runtime.getRuntime().gc();
184     Runtime.getRuntime().gc();
185   }
186 
doTestPrimitiveFieldsClasses()187   private static void doTestPrimitiveFieldsClasses() {
188     setTag(IntObject.class, 10000);
189     System.out.println(followReferencesPrimitiveFields(IntObject.class));
190     System.out.println(getTag(IntObject.class));
191     setTag(IntObject.class, 0);
192 
193     setTag(FloatObject.class, 10000);
194     System.out.println(followReferencesPrimitiveFields(FloatObject.class));
195     System.out.println(getTag(FloatObject.class));
196     setTag(FloatObject.class, 0);
197 
198     boolean correctHeapValue = false;
199     setTag(Inf1.class, 10000);
200     String heapTrace = followReferencesPrimitiveFields(Inf1.class);
201 
202     if (!checkInitialized(Inf1.class)) {
203       correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000000");
204     } else {
205       correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000001");
206     }
207 
208     if (!correctHeapValue)
209       System.out.println("Heap Trace for Inf1 is not as expected:\n" + heapTrace);
210 
211     System.out.println(getTag(Inf1.class));
212     setTag(Inf1.class, 0);
213 
214     setTag(Inf2.class, 10000);
215     heapTrace = followReferencesPrimitiveFields(Inf2.class);
216 
217     if (!checkInitialized(Inf2.class)) {
218       correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000000");
219     } else {
220       correctHeapValue = heapTrace.equals("10000@0 (static, int, index=1) 0000000000000001");
221     }
222 
223     if (!correctHeapValue)
224       System.out.println("Heap Trace for Inf2 is not as expected:\n" + heapTrace);
225     System.out.println(getTag(Inf2.class));
226     setTag(Inf2.class, 0);
227   }
228 
doTestPrimitiveFieldsIntegral()229   private static void doTestPrimitiveFieldsIntegral() {
230     IntObject intObject = new IntObject();
231     setTag(intObject, 10000);
232     System.out.println(followReferencesPrimitiveFields(intObject));
233     System.out.println(getTag(intObject));
234   }
235 
doTestPrimitiveFieldsFloat()236   private static void doTestPrimitiveFieldsFloat() {
237     FloatObject floatObject = new FloatObject();
238     setTag(floatObject, 10000);
239     System.out.println(followReferencesPrimitiveFields(floatObject));
240     System.out.println(getTag(floatObject));
241   }
242 
243   static ArrayList<Object> extensionTestHolder;
244 
doExtensionTests()245   private static void doExtensionTests() {
246     checkForExtensionApis();
247 
248     extensionTestHolder = new ArrayList<>();
249     System.out.println();
250 
251     try {
252       getHeapName(-1);
253       System.out.println("Expected failure for -1");
254     } catch (Exception e) {
255     }
256     System.out.println(getHeapName(0));
257     System.out.println(getHeapName(1));
258     System.out.println(getHeapName(2));
259     System.out.println(getHeapName(3));
260     try {
261       getHeapName(4);
262       System.out.println("Expected failure for -1");
263     } catch (Exception e) {
264     }
265 
266     System.out.println();
267 
268     setTag(Object.class, 100000);
269     int objectClassHeapId = getObjectHeapId(100000);
270     int objClassExpectedHeapId = hasImage() ? 1 : 3;
271     if (objectClassHeapId != objClassExpectedHeapId) {
272       throw new RuntimeException("Expected object class in heap " + objClassExpectedHeapId +
273           " but received " + objectClassHeapId);
274     }
275 
276     A a = new A();
277     extensionTestHolder.add(a);
278     setTag(a, 100001);
279     System.out.println(getObjectHeapId(100001));
280 
281     checkGetObjectHeapIdInCallback(100000, objClassExpectedHeapId);
282     checkGetObjectHeapIdInCallback(100001, 3);
283 
284     long baseTag = 30000000;
285     setTag(Object.class, baseTag + objClassExpectedHeapId);
286     setTag(Class.class, baseTag + objClassExpectedHeapId);
287     Object o = new Object();
288     extensionTestHolder.add(o);
289     setTag(o, baseTag + 3);
290 
291     iterateThroughHeapExt();
292 
293     extensionTestHolder = null;
294   }
295 
runGc()296   private static void runGc() {
297     clearStats();
298     forceGarbageCollection();
299     printStats();
300   }
301 
clearStats()302   private static void clearStats() {
303     getGcStarts();
304     getGcFinishes();
305   }
306 
printStats()307   private static void printStats() {
308     System.out.println("---");
309     int s = getGcStarts();
310     int f = getGcFinishes();
311     System.out.println((s > 0) + " " + (f > 0));
312   }
313 
hasImage()314   private static boolean hasImage() {
315     try {
316       int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
317       BufferedReader reader = new BufferedReader(new FileReader("/proc/" + pid + "/maps"));
318       String line;
319       while ((line = reader.readLine()) != null) {
320         // On host the mappings end with .art and on device they end with .art]
321         if (line.endsWith(".art]") || line.endsWith(".art")) {
322           reader.close();
323           return true;
324         }
325       }
326       reader.close();
327       return false;
328     } catch (Exception e) {
329       throw new RuntimeException(e);
330     }
331   }
332 
333   private static class TestConfig {
334     private Class<?> klass = null;
335     private int heapFilter = 0;
336     private int stopAfter = Integer.MAX_VALUE;
337     private int followSet = -1;
338 
TestConfig()339     public TestConfig() {
340     }
TestConfig(Class<?> klass, int heapFilter)341     public TestConfig(Class<?> klass, int heapFilter) {
342       this.klass = klass;
343       this.heapFilter = heapFilter;
344     }
TestConfig(Class<?> klass, int heapFilter, int stopAfter, int followSet)345     public TestConfig(Class<?> klass, int heapFilter, int stopAfter, int followSet) {
346       this.klass = klass;
347       this.heapFilter = heapFilter;
348       this.stopAfter = stopAfter;
349       this.followSet = followSet;
350     }
351 
doFollowReferencesTest()352     public void doFollowReferencesTest() throws Exception {
353       // Force GCs to clean up dirt.
354       Runtime.getRuntime().gc();
355       Runtime.getRuntime().gc();
356 
357       setTag(Thread.currentThread(), 3000);
358 
359       {
360         ArrayList<Object> tmpStorage = new ArrayList<>();
361         doFollowReferencesTestNonRoot(tmpStorage);
362         tmpStorage = null;
363       }
364 
365       // Force GCs to clean up dirt.
366       Runtime.getRuntime().gc();
367       Runtime.getRuntime().gc();
368 
369       doFollowReferencesTestRoot();
370 
371       // Force GCs to clean up dirt.
372       Runtime.getRuntime().gc();
373       Runtime.getRuntime().gc();
374     }
375 
doFollowReferencesTestNonRoot(ArrayList<Object> tmpStorage)376     private void doFollowReferencesTestNonRoot(ArrayList<Object> tmpStorage) {
377       Verifier v = new Verifier();
378       tagClasses(v);
379       A a = createTree(v);
380       tmpStorage.add(a);
381       v.add("0@0", "1@1000");  // tmpStorage[0] --(array-element)--> a.
382 
383       doFollowReferencesTestImpl(null, stopAfter, followSet, null, v, null);
384       doFollowReferencesTestImpl(a.foo2, stopAfter, followSet, null, v, "3@1001");
385 
386       tmpStorage.clear();
387     }
388 
doFollowReferencesTestRoot()389     private void doFollowReferencesTestRoot() {
390       Verifier v = new Verifier();
391       tagClasses(v);
392       A a = createTree(v);
393 
394       doFollowReferencesTestImpl(null, stopAfter, followSet, a, v, null);
395       doFollowReferencesTestImpl(a.foo2, stopAfter, followSet, a, v, "3@1001");
396     }
397 
doFollowReferencesTestImpl(A root, int stopAfter, int followSet, Object asRoot, Verifier v, String additionalEnabled)398     private void doFollowReferencesTestImpl(A root, int stopAfter, int followSet,
399         Object asRoot, Verifier v, String additionalEnabled) {
400       String[] lines =
401           followReferences(heapFilter, klass, root, stopAfter, followSet, asRoot);
402 
403       v.process(lines, additionalEnabled, heapFilter != 0 || klass != null);
404     }
405 
tagClasses(Verifier v)406     private static void tagClasses(Verifier v) {
407       setTag(A.class, 1000);
408       registerClass(1000, A.class);
409 
410       setTag(B.class, 1001);
411       registerClass(1001, B.class);
412       v.add("1001@0", "1000@0");  // B.class --(superclass)--> A.class.
413 
414       setTag(C.class, 1002);
415       registerClass(1002, C.class);
416       v.add("1002@0", "1001@0");  // C.class --(superclass)--> B.class.
417       v.add("1002@0", "2001@0");  // C.class --(interface)--> I2.class.
418 
419       setTag(I1.class, 2000);
420       registerClass(2000, I1.class);
421 
422       setTag(I2.class, 2001);
423       registerClass(2001, I2.class);
424       v.add("2001@0", "2000@0");  // I2.class --(interface)--> I1.class.
425     }
426 
createTree(Verifier v)427     private static A createTree(Verifier v) {
428       A aInst = new A();
429       setTag(aInst, 1);
430       String aInstStr = "1@1000";
431       String aClassStr = "1000@0";
432       v.add(aInstStr, aClassStr);  // A -->(class) --> A.class.
433 
434       A a2Inst = new A();
435       setTag(a2Inst, 2);
436       aInst.foo = a2Inst;
437       String a2InstStr = "2@1000";
438       v.add(a2InstStr, aClassStr);  // A2 -->(class) --> A.class.
439       v.add(aInstStr, a2InstStr);   // A -->(field) --> A2.
440 
441       B bInst = new B();
442       setTag(bInst, 3);
443       aInst.foo2 = bInst;
444       String bInstStr = "3@1001";
445       String bClassStr = "1001@0";
446       v.add(bInstStr, bClassStr);  // B -->(class) --> B.class.
447       v.add(aInstStr, bInstStr);   // A -->(field) --> B.
448 
449       A a3Inst = new A();
450       setTag(a3Inst, 4);
451       bInst.bar = a3Inst;
452       String a3InstStr = "4@1000";
453       v.add(a3InstStr, aClassStr);  // A3 -->(class) --> A.class.
454       v.add(bInstStr, a3InstStr);   // B -->(field) --> A3.
455 
456       C cInst = new C();
457       setTag(cInst, 5);
458       bInst.bar2 = cInst;
459       String cInstStr = "5@1000";
460       String cClassStr = "1002@0";
461       v.add(cInstStr, cClassStr);  // C -->(class) --> C.class.
462       v.add(bInstStr, cInstStr);   // B -->(field) --> C.
463 
464       A a4Inst = new A();
465       setTag(a4Inst, 6);
466       cInst.baz = a4Inst;
467       String a4InstStr = "6@1000";
468       v.add(a4InstStr, aClassStr);  // A4 -->(class) --> A.class.
469       v.add(cInstStr, a4InstStr);   // C -->(field) --> A4.
470 
471       cInst.baz2 = aInst;
472       v.add(cInstStr, aInstStr);  // C -->(field) --> A.
473 
474       A[] aArray = new A[2];
475       setTag(aArray, 500);
476       aArray[1] = a2Inst;
477       cInst.array = aArray;
478       String aArrayStr = "500@0";
479       v.add(cInstStr, aArrayStr);
480       v.add(aArrayStr, a2InstStr);
481 
482       return aInst;
483     }
484   }
485 
486   public static class A {
487     public A foo;
488     public A foo2;
489 
A()490     public A() {}
A(A a, A b)491     public A(A a, A b) {
492       foo = a;
493       foo2 = b;
494     }
495   }
496 
497   public static class B extends A {
498     public A bar;
499     public A bar2;
500 
B()501     public B() {}
B(A a, A b)502     public B(A a, A b) {
503       bar = a;
504       bar2 = b;
505     }
506   }
507 
508   public static interface I1 {
509     public final static int i1Field = 1;
510   }
511 
512   public static interface I2 extends I1 {
513     public final static int i2Field = 2;
514   }
515 
516   public static class C extends B implements I2 {
517     public A baz;
518     public A baz2;
519     public A[] array;
520 
C()521     public C() {}
C(A a, A b)522     public C(A a, A b) {
523       baz = a;
524       baz2 = b;
525     }
526   }
527 
528   private static interface Inf1 {
529     public final static int A = 1;
530   }
531 
532   private static interface Inf2 extends Inf1 {
533     public final static int B = 1;
534   }
535 
536   private static class IntObject implements Inf1 {
537     byte b = (byte)1;
538     char c= 'a';
539     short s = (short)2;
540     int i = 3;
541     long l = 4;
542     Object o = new Object();
543     static int sI = 5;
544   }
545 
546   private static class FloatObject extends IntObject implements Inf2 {
547     float f = 1.23f;
548     double d = 1.23;
549     Object p = new Object();
550     static int sI = 6;
551   }
552 
553   public static class Verifier {
554     // Should roots with vreg=-1 be printed?
555     public final static boolean PRINT_ROOTS_WITH_UNKNOWN_VREG = false;
556 
557     public static class Node {
558       public String referrer;
559 
560       public HashSet<String> referrees = new HashSet<>();
561 
Node(String r)562       public Node(String r) {
563         referrer = r;
564       }
565 
isRoot()566       public boolean isRoot() {
567         return referrer.startsWith("root@");
568       }
569     }
570 
571     HashMap<String, Node> nodes = new HashMap<>();
572 
Verifier()573     public Verifier() {
574     }
575 
add(String referrer, String referree)576     public void add(String referrer, String referree) {
577       if (!nodes.containsKey(referrer)) {
578         nodes.put(referrer, new Node(referrer));
579       }
580       if (referree != null) {
581         nodes.get(referrer).referrees.add(referree);
582       }
583     }
584 
process(String[] lines, String additionalEnabledReferrer, boolean filtered)585     public void process(String[] lines, String additionalEnabledReferrer, boolean filtered) {
586       // This method isn't optimal. The loops could be merged. However, it's more readable if
587       // the different parts are separated.
588 
589       ArrayList<String> rootLines = new ArrayList<>();
590       ArrayList<String> nonRootLines = new ArrayList<>();
591 
592       // Check for consecutive chunks of referrers. Also ensure roots come first.
593       {
594         String currentHead = null;
595         boolean rootsDone = false;
596         HashSet<String> completedReferrers = new HashSet<>();
597         for (String l : lines) {
598           String referrer = getReferrer(l);
599 
600           if (isRoot(referrer)) {
601             if (rootsDone) {
602               System.out.println("ERROR: Late root " + l);
603               print(lines);
604               return;
605             }
606             rootLines.add(l);
607             continue;
608           }
609 
610           rootsDone = true;
611 
612           if (currentHead == null) {
613             currentHead = referrer;
614           } else {
615             // Ignore 0@0, as it can happen at any time (as it stands for all other objects).
616             if (!currentHead.equals(referrer) && !referrer.equals("0@0")) {
617               completedReferrers.add(currentHead);
618               currentHead = referrer;
619               if (completedReferrers.contains(referrer)) {
620                 System.out.println("Non-contiguous referrer " + l);
621                 print(lines);
622                 return;
623               }
624             }
625           }
626           nonRootLines.add(l);
627         }
628       }
629 
630       // Sort (root order is not specified) and print the roots.
631       // TODO: What about extra roots? JNI and the interpreter seem to introduce those (though it
632       //       isn't clear why a debuggable-AoT test doesn't have the same, at least for locals).
633       //       For now, swallow duplicates, and resolve once we have the metadata for the roots.
634       {
635         Collections.sort(rootLines);
636         String lastRoot = null;
637         for (String l : rootLines) {
638           if (lastRoot != null && lastRoot.equals(l)) {
639             continue;
640           }
641           lastRoot = l;
642           if (!PRINT_ROOTS_WITH_UNKNOWN_VREG && l.indexOf("vreg=-1") > 0) {
643             continue;
644           }
645           System.out.println(l);
646         }
647       }
648 
649       if (filtered) {
650         // If we aren't tracking dependencies, just sort the lines and print.
651         // TODO: As the verifier is currently using the output lines to track dependencies, we
652         //       cannot verify that output is correct when parts of it are suppressed by filters.
653         //       To correctly track this we need to take node information into account, and
654         //       actually analyze the graph.
655         Collections.sort(nonRootLines);
656         for (String l : nonRootLines) {
657           System.out.println(l);
658         }
659 
660         System.out.println("---");
661         return;
662       }
663 
664       // Iterate through the lines, keeping track of which referrers are visited, to ensure the
665       // order is acceptable.
666       HashSet<String> enabled = new HashSet<>();
667       if (additionalEnabledReferrer != null) {
668         enabled.add(additionalEnabledReferrer);
669       }
670       // Always add "0@0".
671       enabled.add("0@0");
672 
673       for (String l : lines) {
674         String referrer = getReferrer(l);
675         String referree = getReferree(l);
676         if (isRoot(referrer)) {
677           // For a root src, just enable the referree.
678           enabled.add(referree);
679         } else {
680           // Check that the referrer is enabled (may be visited).
681           if (!enabled.contains(referrer)) {
682             System.out.println("Referrer " + referrer + " not enabled: " + l);
683             print(lines);
684             return;
685           }
686           enabled.add(referree);
687         }
688       }
689 
690       // Now just sort the non-root lines and output them
691       Collections.sort(nonRootLines);
692       for (String l : nonRootLines) {
693         System.out.println(l);
694       }
695 
696       System.out.println("---");
697     }
698 
isRoot(String ref)699     public static boolean isRoot(String ref) {
700       return ref.startsWith("root@");
701     }
702 
getReferrer(String line)703     private static String getReferrer(String line) {
704       int i = line.indexOf(" --");
705       if (i <= 0) {
706         throw new IllegalArgumentException(line);
707       }
708       int j = line.indexOf(' ');
709       if (i != j) {
710         throw new IllegalArgumentException(line);
711       }
712       return line.substring(0, i);
713     }
714 
getReferree(String line)715     private static String getReferree(String line) {
716       int i = line.indexOf("--> ");
717       if (i <= 0) {
718         throw new IllegalArgumentException(line);
719       }
720       int j = line.indexOf(' ', i + 4);
721       if (j < 0) {
722         throw new IllegalArgumentException(line);
723       }
724       return line.substring(i + 4, j);
725     }
726 
print(String[] lines)727     private static void print(String[] lines) {
728       for (String l : lines) {
729         System.out.println(l);
730       }
731     }
732   }
733 
setTag(Object o, long tag)734   private static void setTag(Object o, long tag) {
735     Main.setTag(o, tag);
736   }
getTag(Object o)737   private static long getTag(Object o) {
738     return Main.getTag(o);
739   }
740 
checkInitialized(Class<?> klass)741   private static native boolean checkInitialized(Class<?> klass);
setupGcCallback()742   private static native void setupGcCallback();
enableGcTracking(boolean enable)743   private static native void enableGcTracking(boolean enable);
getGcStarts()744   private static native int getGcStarts();
getGcFinishes()745   private static native int getGcFinishes();
forceGarbageCollection()746   private static native void forceGarbageCollection();
747 
checkForExtensionApis()748   private static native void checkForExtensionApis();
getObjectHeapId(long tag)749   private static native int getObjectHeapId(long tag);
getHeapName(int heapId)750   private static native String getHeapName(int heapId);
checkGetObjectHeapIdInCallback(long tag, int heapId)751   private static native void checkGetObjectHeapIdInCallback(long tag, int heapId);
752 
followReferences(int heapFilter, Class<?> klassFilter, Object initialObject, int stopAfter, int followSet, Object jniRef)753   public static native String[] followReferences(int heapFilter, Class<?> klassFilter,
754       Object initialObject, int stopAfter, int followSet, Object jniRef);
followReferencesString(Object initialObject)755   public static native String[] followReferencesString(Object initialObject);
followReferencesPrimitiveArray(Object initialObject)756   public static native String followReferencesPrimitiveArray(Object initialObject);
followReferencesPrimitiveFields(Object initialObject)757   public static native String followReferencesPrimitiveFields(Object initialObject);
758 
iterateThroughHeapExt()759   private static native void iterateThroughHeapExt();
760 
registerClass(long tag, Object obj)761   private static native void registerClass(long tag, Object obj);
762 }
763