unified-heap: Provide names for internal classes in heap snapshot

Provide a name for internal nodes in non-production builds.

This is very useful for manual debugging builds but may confuse people
without providing better DevTools integration.

Bug: 843903
Change-Id: Ifd7359575beb3c916a86fc6091abfc20c76e6b64
Reviewed-on: https://chromium-review.googlesource.com/c/1412472
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#623177}
diff --git a/third_party/blink/renderer/platform/heap/name_trait_test.cc b/third_party/blink/renderer/platform/heap/name_trait_test.cc
index 4e4a43b..fac0052 100644
--- a/third_party/blink/renderer/platform/heap/name_trait_test.cc
+++ b/third_party/blink/renderer/platform/heap/name_trait_test.cc
@@ -4,8 +4,8 @@
 
 #include <string.h>
 
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
-
 #include "third_party/blink/renderer/platform/heap/name_traits.h"
 
 namespace blink {
@@ -29,10 +29,20 @@
 
 }  // namespace
 
+TEST(NameTraitTest, InternalNamesHiddenInOfficialBuild) {
+#if defined(OFFICIAL_BUILD)
+  EXPECT_TRUE(NameTrait<ClassWithoutName>::HideInternalName());
+#endif
+}
+
 TEST(NameTraitTest, DefaultName) {
   ClassWithoutName no_name;
   const char* name = NameTrait<ClassWithoutName>::GetName(&no_name);
-  EXPECT_EQ(0, strcmp(name, "InternalNode"));
+  if (NameTrait<ClassWithoutName>::HideInternalName()) {
+    EXPECT_EQ(0, strcmp(name, "InternalNode"));
+  } else {
+    EXPECT_NE(nullptr, strstr(name, "ClassWithoutName"));
+  }
 }
 
 TEST(NameTraitTest, CustomName) {
diff --git a/third_party/blink/renderer/platform/heap/name_traits.h b/third_party/blink/renderer/platform/heap/name_traits.h
index d126181..941fc88 100644
--- a/third_party/blink/renderer/platform/heap/name_traits.h
+++ b/third_party/blink/renderer/platform/heap/name_traits.h
@@ -5,8 +5,10 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_NAME_TRAITS_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_NAME_TRAITS_H_
 
+#include "build/build_config.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/type_traits.h"
 
 namespace blink {
 
@@ -15,6 +17,14 @@
   STATIC_ONLY(NameTrait);
 
  public:
+  static constexpr bool HideInternalName() {
+#if defined(OFFICIAL_BUILD) || !(defined(COMPILER_GCC) || defined(__clang__))
+    return true;
+#else
+    return false;
+#endif
+  }
+
   static const char* GetName(const void* obj) {
     return GetNameFor(static_cast<const T*>(obj));
   }
@@ -24,7 +34,34 @@
     return wrapper_tracable->NameInHeapSnapshot();
   }
 
-  static const char* GetNameFor(...) { return "InternalNode"; }
+  static const char* GetNameFor(...) {
+    // For non-official builds construct the name of a type from a compiler
+    // intrinsic.
+    //
+    // Do not include such type information in official builds to
+    // (a) safe binary size on string literals, and
+    // (b) avoid exposing internal types until a proper DevTools frontend
+    //     implementation is present.
+#if defined(OFFICIAL_BUILD) || !(defined(COMPILER_GCC) || defined(__clang__))
+    return "InternalNode";
+#else
+    DCHECK(!HideInternalName());
+    static const char* leaky_class_name = nullptr;
+    if (leaky_class_name)
+      return leaky_class_name;
+
+    // Parsing string of structure:
+    //   const char *WTF::GetStringWithTypeName<TYPE>() [T = TYPE]
+    // Note that this only works on clang or GCC builds.
+    const std::string raw(WTF::GetStringWithTypeName<T>());
+    const auto start_pos = raw.rfind("T = ") + 4;
+    DCHECK(std::string::npos != start_pos);
+    const auto len = raw.length() - start_pos - 1;
+    const std::string name = raw.substr(start_pos, len).c_str();
+    leaky_class_name = strcpy(new char[name.length() + 1], name.c_str());
+    return leaky_class_name;
+#endif
+  }
 };
 
 }  // namespace blink
diff --git a/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-merged-nodes.js b/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-merged-nodes.js
index f804ff2..efbe73c9 100644
--- a/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-merged-nodes.js
+++ b/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-merged-nodes.js
@@ -31,7 +31,9 @@
   else
     return testRunner.fail('cannot find leaking node');
 
-  var retainers = helper.firstRetainingPath(node).map(node => node.name());
+  var retainers = helper.firstRetainingPath(node).map(
+      node => (node.name().includes("::"))
+          ? "Detached InternalNode" : node.name());
   var actual = retainers.join(', ');
   testRunner.log(`SUCCESS: retaining path = [${actual}]`);
   testRunner.completeTest();
diff --git a/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-with-event-listener.js b/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-with-event-listener.js
index 1fa2023..fe52bd97 100644
--- a/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-with-event-listener.js
+++ b/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-with-event-listener.js
@@ -28,7 +28,8 @@
   else
     return testRunner.fail('cannot find myEventListener node');
 
-  var retainers = helper.firstRetainingPath(node).map(node => node.name());
+  var retainers = helper.firstRetainingPath(node).map(
+      node => (node.name().includes("::")) ? "InternalNode" : node.name());
   var actual = retainers.join(', ');
   testRunner.log(`SUCCESS: retaining path = [${actual}]`);
   testRunner.completeTest();
diff --git a/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-with-multiple-retainers.js b/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-with-multiple-retainers.js
index 94f3d82..0803db9 100644
--- a/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-with-multiple-retainers.js
+++ b/third_party/blink/web_tests/inspector-protocol/heap-profiler/heap-snapshot-with-multiple-retainers.js
@@ -55,7 +55,8 @@
   var retainingPaths = [];
   for (var iter = eventListener.retainers(); iter.hasNext(); iter.next()) {
     var path = helper.firstRetainingPath(iter.retainer.node());
-    path = path.map(node => node.name());
+    path = path.map(
+        node => (node.name().includes("::")) ? "InternalNode" : node.name());
     retainingPaths.push(path.join(', '));
   }