Remove perflib-based native allocation registry identification.

In preparation for removing dependency on perflib.

Test: m ahat-test, change covered by NativeAllocationTest.
Change-Id: Id91c2be4910699f9d4c90b44210f8d9bdb9c2318
diff --git a/tools/ahat/src/heapdump/AhatClassInstance.java b/tools/ahat/src/heapdump/AhatClassInstance.java
index a2f61ca..0224025 100644
--- a/tools/ahat/src/heapdump/AhatClassInstance.java
+++ b/tools/ahat/src/heapdump/AhatClassInstance.java
@@ -248,6 +248,49 @@
     return bitmap;
   }
 
+  @Override
+  public RegisteredNativeAllocation asRegisteredNativeAllocation() {
+    if (!isInstanceOfClass("sun.misc.Cleaner")) {
+      return null;
+    }
+
+    Value vthunk = getField("thunk");
+    if (vthunk == null || !vthunk.isAhatInstance()) {
+      return null;
+    }
+
+    AhatClassInstance thunk = vthunk.asAhatInstance().asClassInstance();
+    if (thunk == null
+        || !thunk.isInstanceOfClass("libcore.util.NativeAllocationRegistry$CleanerThunk")) {
+      return null;
+    }
+
+    Value vregistry = thunk.getField("this$0");
+    if (vregistry == null || !vregistry.isAhatInstance()) {
+      return null;
+    }
+
+    AhatClassInstance registry = vregistry.asAhatInstance().asClassInstance();
+    if (registry == null || !registry.isInstanceOfClass("libcore.util.NativeAllocationRegistry")) {
+      return null;
+    }
+
+    Value size = registry.getField("size");
+    if (!size.isLong()) {
+      return null;
+    }
+
+    Value referent = getField("referent");
+    if (referent == null || !referent.isAhatInstance()) {
+      return null;
+    }
+
+    RegisteredNativeAllocation rna = new RegisteredNativeAllocation();
+    rna.referent = referent.asAhatInstance();
+    rna.size = size.asLong();
+    return rna;
+  }
+
   private static class InstanceFieldIterator implements Iterable<FieldValue>,
                                                         Iterator<FieldValue> {
     // The complete list of instance field values to iterate over, including
diff --git a/tools/ahat/src/heapdump/AhatInstance.java b/tools/ahat/src/heapdump/AhatInstance.java
index 0e78558..05dcc68 100644
--- a/tools/ahat/src/heapdump/AhatInstance.java
+++ b/tools/ahat/src/heapdump/AhatInstance.java
@@ -363,6 +363,19 @@
     return null;
   }
 
+  public static class RegisteredNativeAllocation {
+    public AhatInstance referent;
+    public long size;
+  };
+
+  /**
+   * Return the registered native allocation that this instance represents, if
+   * any. This is relevant for instances of sun.misc.Cleaner.
+   */
+  public RegisteredNativeAllocation asRegisteredNativeAllocation() {
+    return null;
+  }
+
   /**
    * Returns a sample path from a GC root to this instance.
    * This instance is included as the last element of the path with an empty
diff --git a/tools/ahat/src/heapdump/AhatSnapshot.java b/tools/ahat/src/heapdump/AhatSnapshot.java
index 1b2cf3c..703ba25 100644
--- a/tools/ahat/src/heapdump/AhatSnapshot.java
+++ b/tools/ahat/src/heapdump/AhatSnapshot.java
@@ -36,7 +36,6 @@
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Map;
 
 public class AhatSnapshot implements Diffable<AhatSnapshot> {
   private final Site mRootSite = new Site("ROOT");
@@ -128,10 +127,9 @@
       }
     });
 
-    Map<Instance, Long> registeredNative = Perflib.getRegisteredNativeAllocations(snapshot);
-
     // Initialize ahat snapshot and instances based on the perflib snapshot
     // and instances.
+    List<AhatInstance> cleaners = new ArrayList<AhatInstance>();
     for (AhatInstance ahat : mInstances) {
       Instance inst = snapshot.findInstance(ahat.getId());
 
@@ -142,9 +140,9 @@
       }
       ahat.initialize(this, inst, mRootSite.getSite(frames));
 
-      Long registeredNativeSize = registeredNative.get(inst);
-      if (registeredNativeSize != null) {
-        ahat.addRegisteredNativeSize(registeredNativeSize);
+      ClassObj classObj = inst.getClassObj();
+      if (classObj != null && "sun.misc.Cleaner".equals(classObj.getClassName())) {
+        cleaners.add(ahat);
       }
     }
 
@@ -162,6 +160,14 @@
     }
     snapshot.dispose();
 
+    // Update registered native allocation size.
+    for (AhatInstance cleaner : cleaners) {
+      AhatInstance.RegisteredNativeAllocation nra = cleaner.asRegisteredNativeAllocation();
+      if (nra != null) {
+        nra.referent.addRegisteredNativeSize(nra.size);
+      }
+    }
+
     AhatInstance.computeReverseReferences(superRoot);
     DominatorsComputation.computeDominators(superRoot);
     AhatInstance.computeRetainedSize(superRoot, mHeaps.size());
diff --git a/tools/ahat/src/heapdump/Perflib.java b/tools/ahat/src/heapdump/Perflib.java
deleted file mode 100644
index d0264a3..0000000
--- a/tools/ahat/src/heapdump/Perflib.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-package com.android.ahat.heapdump;
-
-import com.android.tools.perflib.heap.ClassInstance;
-import com.android.tools.perflib.heap.ClassObj;
-import com.android.tools.perflib.heap.Instance;
-import com.android.tools.perflib.heap.Snapshot;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Collection of utilities that may be suitable to have in perflib instead of
- * ahat.
- */
-public class Perflib {
-  /**
-   * Return a collection of instances in the given snapshot that are tied to
-   * registered native allocations and their corresponding registered native
-   * sizes.
-   */
-  public static Map<Instance, Long> getRegisteredNativeAllocations(Snapshot snapshot) {
-    Map<Instance, Long> allocs = new HashMap<Instance, Long>();
-    ClassObj cleanerClass = snapshot.findClass("sun.misc.Cleaner");
-    if (cleanerClass != null) {
-      for (Instance cleanerInst : cleanerClass.getInstancesList()) {
-        ClassInstance cleaner = (ClassInstance)cleanerInst;
-        Object referent = getField(cleaner, "referent");
-        if (referent instanceof Instance) {
-          Instance inst = (Instance)referent;
-          Object thunkValue = getField(cleaner, "thunk");
-          if (thunkValue instanceof ClassInstance) {
-            ClassInstance thunk = (ClassInstance)thunkValue;
-            ClassObj thunkClass = thunk.getClassObj();
-            String cleanerThunkClassName = "libcore.util.NativeAllocationRegistry$CleanerThunk";
-            if (thunkClass != null && cleanerThunkClassName.equals(thunkClass.getClassName())) {
-              for (ClassInstance.FieldValue thunkField : thunk.getValues()) {
-                if (thunkField.getValue() instanceof ClassInstance) {
-                  ClassInstance registry = (ClassInstance)thunkField.getValue();
-                  ClassObj registryClass = registry.getClassObj();
-                  String registryClassName = "libcore.util.NativeAllocationRegistry";
-                  if (registryClass != null
-                      && registryClassName.equals(registryClass.getClassName())) {
-                    Object sizeValue = getField(registry, "size");
-                    if (sizeValue instanceof Long) {
-                      long size = (Long)sizeValue;
-                      if (size > 0) {
-                        Long old = allocs.get(inst);
-                        allocs.put(inst, old == null ? size : old + size);
-                      }
-                    }
-                    break;
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-    return allocs;
-  }
-
-  /**
-   * Helper function to read a single field from a perflib class instance.
-   * Returns null if field not found. Note there is no way to distinguish
-   * between field not found an a field value of null.
-   */
-  private static Object getField(ClassInstance cls, String name) {
-    for (ClassInstance.FieldValue field : cls.getValues()) {
-      if (name.equals(field.getField().getName())) {
-        return field.getValue();
-      }
-    }
-    return null;
-  }
-}