Add a heap dump utility

Change-Id: Ic86c3a252b654be384ca74325c33fe99407fa96a
diff --git a/src/main/java/com/android/tools/r8/utils/HeapUtils.java b/src/main/java/com/android/tools/r8/utils/HeapUtils.java
new file mode 100644
index 0000000..6834f66
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/HeapUtils.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.nio.file.Path;
+import javax.management.MBeanServer;
+
+public class HeapUtils {
+
+  private static final String HOTSPOT_MBEAN_NAME = "com.sun.management:type=HotSpotDiagnostic";
+  private static volatile HotSpotDiagnosticMXBean hotSpotDiagnosticMXBean;
+
+  private static void initHotSpotMBean() throws IOException {
+    if (hotSpotDiagnosticMXBean == null) {
+      synchronized (HeapUtils.class) {
+        if (hotSpotDiagnosticMXBean == null) {
+          hotSpotDiagnosticMXBean = getHotSpotDiagnosticMXBean();
+        }
+      }
+    }
+  }
+
+  private static HotSpotDiagnosticMXBean getHotSpotDiagnosticMXBean() throws IOException {
+    MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+    return ManagementFactory.newPlatformMXBeanProxy(
+        server, HOTSPOT_MBEAN_NAME, HotSpotDiagnosticMXBean.class);
+  }
+
+  public static void dumpHeap(Path fileName, boolean live) throws IOException {
+    initHotSpotMBean();
+    hotSpotDiagnosticMXBean.dumpHeap(fileName.toString(), live);
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/heap/HeapDumpTest.java b/src/test/java/com/android/tools/r8/heap/HeapDumpTest.java
new file mode 100644
index 0000000..19a3c15
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/heap/HeapDumpTest.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.heap;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.HeapUtils;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.Test;
+
+public class HeapDumpTest extends TestBase {
+
+  @Test
+  public void testHeapDump() throws Exception {
+    Path heapDumpDir = temp.newFolder().toPath();
+    Path heapDump = heapDumpDir.resolve("test.hprof");
+    HeapUtils.dumpHeap(heapDump, true);
+    assertTrue(heapDump.toFile().exists());
+    String header = "JAVA PROFILE 1.0.2";
+    assertTrue(heapDump.toFile().length() > header.length());
+    try (InputStream is = Files.newInputStream(heapDump)) {
+      byte[] buffer = new byte[header.length()];
+      int bytes = is.read(buffer);
+      assertEquals(buffer.length, bytes);
+      assertEquals(header, new String(buffer));
+    }
+  }
+}