<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[197712] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/197712">197712</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-03-07 15:45:38 -0800 (Mon, 07 Mar 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Heap Snapshot should include different Edge types and data (Property, Index, Variable)
https://bugs.webkit.org/show_bug.cgi?id=154937

Patch by Joseph Pecoraro &lt;pecoraro@apple.com&gt; on 2016-03-07
Reviewed by Geoffrey Garen.

* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::appendHidden):
* heap/SlotVisitor.h:
* heap/SlotVisitorInlines.h:
(JSC::SlotVisitor::appendHidden):
(JSC::SlotVisitor::appendValuesHidden):
Add new visit methods to visit a reference without snapshotting the edge.

* heap/Heap.cpp:
(JSC::AddExtraHeapSnapshotEdges::AddExtraHeapSnapshotEdges):
(JSC::AddExtraHeapSnapshotEdges::operator()):
(JSC::Heap::addHeapSnapshotEdges):
(JSC::Heap::removeDeadHeapSnapshotNodes):
(JSC::Heap::collectImpl):
* heap/Heap.h:
After marking, visit the live cells for a chance to record extra
heap snapshotting information about the cell.

* heap/HeapSnapshotBuilder.cpp:
(JSC::HeapSnapshotBuilder::appendNode):
(JSC::HeapSnapshotBuilder::appendEdge):
(JSC::HeapSnapshotBuilder::appendPropertyNameEdge):
(JSC::HeapSnapshotBuilder::appendVariableNameEdge):
(JSC::HeapSnapshotBuilder::appendIndexEdge):
(JSC::HeapSnapshotBuilder::json):
* heap/HeapSnapshotBuilder.h:
(JSC::HeapSnapshotEdge::HeapSnapshotEdge):
Construct edges with extra data.

* runtime/ClassInfo.h:
* runtime/JSCell.cpp:
(JSC::JSCell::heapSnapshot):
* runtime/JSCell.h:
Add a new method to provide cells with an opportunity to provide
extra heap snapshotting information.

* runtime/JSObject.cpp:
(JSC::JSObject::visitButterfly):
(JSC::JSObject::visitChildren):
(JSC::JSObject::heapSnapshot):
(JSC::JSFinalObject::visitChildren):
* runtime/JSObject.h:
Capture object property names and index names when heap snapshotting.
Do not include them as internal edges in normal visitChildren.

* runtime/JSEnvironmentRecord.cpp:
(JSC::JSEnvironmentRecord::visitChildren):
(JSC::JSEnvironmentRecord::heapSnapshot):
* runtime/JSEnvironmentRecord.h:
* runtime/JSSegmentedVariableObject.cpp:
(JSC::JSSegmentedVariableObject::visitChildren):
(JSC::JSSegmentedVariableObject::heapSnapshot):
* runtime/JSSegmentedVariableObject.h:
Capture scope variable names when heap snapshotting.

* runtime/Structure.cpp:
(JSC::Structure::visitChildren):
* runtime/Structure.h:
* runtime/StructureInlines.h:
(JSC::Structure::propertyTable):
When performing a heap snapshotting collection, don't clear the
property table so that accessing the table during this GC is okay.

* tests/heapProfiler/driver/driver.js:
* tests/heapProfiler/property-edge-types.js: Added.
* tests/heapProfiler/variable-edge-types.js: Added.
Tests covering the different edge types and data we capture.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapSnapshotBuildercpp">trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapSnapshotBuilderh">trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorcpp">trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorh">trunk/Source/JavaScriptCore/heap/SlotVisitor.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorInlinesh">trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejsccpp">trunk/Source/JavaScriptCore/jsc.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeClassInfoh">trunk/Source/JavaScriptCore/runtime/ClassInfo.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCellcpp">trunk/Source/JavaScriptCore/runtime/JSCell.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCellh">trunk/Source/JavaScriptCore/runtime/JSCell.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSEnvironmentRecordcpp">trunk/Source/JavaScriptCore/runtime/JSEnvironmentRecord.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSEnvironmentRecordh">trunk/Source/JavaScriptCore/runtime/JSEnvironmentRecord.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectcpp">trunk/Source/JavaScriptCore/runtime/JSObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjecth">trunk/Source/JavaScriptCore/runtime/JSObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSSegmentedVariableObjectcpp">trunk/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSSegmentedVariableObjecth">trunk/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructurecpp">trunk/Source/JavaScriptCore/runtime/Structure.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureh">trunk/Source/JavaScriptCore/runtime/Structure.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureInlinesh">trunk/Source/JavaScriptCore/runtime/StructureInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsheapProfilerdriverdriverjs">trunk/Source/JavaScriptCore/tests/heapProfiler/driver/driver.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsheapProfilerpropertyedgetypesjs">trunk/Source/JavaScriptCore/tests/heapProfiler/property-edge-types.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsheapProfilervariableedgetypesjs">trunk/Source/JavaScriptCore/tests/heapProfiler/variable-edge-types.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -1,3 +1,78 @@
</span><ins>+2016-03-07  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
+
+        Heap Snapshot should include different Edge types and data (Property, Index, Variable)
+        https://bugs.webkit.org/show_bug.cgi?id=154937
+
+        Reviewed by Geoffrey Garen.
+
+        * heap/SlotVisitor.cpp:
+        (JSC::SlotVisitor::appendHidden):
+        * heap/SlotVisitor.h:
+        * heap/SlotVisitorInlines.h:
+        (JSC::SlotVisitor::appendHidden):
+        (JSC::SlotVisitor::appendValuesHidden):
+        Add new visit methods to visit a reference without snapshotting the edge.
+
+        * heap/Heap.cpp:
+        (JSC::AddExtraHeapSnapshotEdges::AddExtraHeapSnapshotEdges):
+        (JSC::AddExtraHeapSnapshotEdges::operator()):
+        (JSC::Heap::addHeapSnapshotEdges):
+        (JSC::Heap::removeDeadHeapSnapshotNodes):
+        (JSC::Heap::collectImpl):
+        * heap/Heap.h:
+        After marking, visit the live cells for a chance to record extra
+        heap snapshotting information about the cell.
+
+        * heap/HeapSnapshotBuilder.cpp:
+        (JSC::HeapSnapshotBuilder::appendNode):
+        (JSC::HeapSnapshotBuilder::appendEdge):
+        (JSC::HeapSnapshotBuilder::appendPropertyNameEdge):
+        (JSC::HeapSnapshotBuilder::appendVariableNameEdge):
+        (JSC::HeapSnapshotBuilder::appendIndexEdge):
+        (JSC::HeapSnapshotBuilder::json):
+        * heap/HeapSnapshotBuilder.h:
+        (JSC::HeapSnapshotEdge::HeapSnapshotEdge):
+        Construct edges with extra data.
+
+        * runtime/ClassInfo.h:
+        * runtime/JSCell.cpp:
+        (JSC::JSCell::heapSnapshot):
+        * runtime/JSCell.h:
+        Add a new method to provide cells with an opportunity to provide
+        extra heap snapshotting information.
+
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::visitButterfly):
+        (JSC::JSObject::visitChildren):
+        (JSC::JSObject::heapSnapshot):
+        (JSC::JSFinalObject::visitChildren):
+        * runtime/JSObject.h:
+        Capture object property names and index names when heap snapshotting.
+        Do not include them as internal edges in normal visitChildren.
+
+        * runtime/JSEnvironmentRecord.cpp:
+        (JSC::JSEnvironmentRecord::visitChildren):
+        (JSC::JSEnvironmentRecord::heapSnapshot):
+        * runtime/JSEnvironmentRecord.h:
+        * runtime/JSSegmentedVariableObject.cpp:
+        (JSC::JSSegmentedVariableObject::visitChildren):
+        (JSC::JSSegmentedVariableObject::heapSnapshot):
+        * runtime/JSSegmentedVariableObject.h:
+        Capture scope variable names when heap snapshotting.
+
+        * runtime/Structure.cpp:
+        (JSC::Structure::visitChildren):
+        * runtime/Structure.h:
+        * runtime/StructureInlines.h:
+        (JSC::Structure::propertyTable):
+        When performing a heap snapshotting collection, don't clear the
+        property table so that accessing the table during this GC is okay.
+
+        * tests/heapProfiler/driver/driver.js:
+        * tests/heapProfiler/property-edge-types.js: Added.
+        * tests/heapProfiler/variable-edge-types.js: Added.
+        Tests covering the different edge types and data we capture.
+
</ins><span class="cx"> 2016-03-07  Saam barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [ES6] Implement Proxy.[[GetPrototypeOf]]
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -768,6 +768,31 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+struct GatherHeapSnapshotData : MarkedBlock::CountFunctor {
+    GatherHeapSnapshotData(HeapSnapshotBuilder&amp; builder)
+        : m_builder(builder)
+    {
+    }
+
+    IterationStatus operator()(JSCell* cell)
+    {
+        cell-&gt;methodTable()-&gt;heapSnapshot(cell, m_builder);
+        return IterationStatus::Continue;
+    }
+
+    HeapSnapshotBuilder&amp; m_builder;
+};
+
+void Heap::gatherExtraHeapSnapshotData(HeapProfiler&amp; heapProfiler)
+{
+    GCPHASE(GatherExtraHeapSnapshotData);
+    if (HeapSnapshotBuilder* builder = heapProfiler.activeSnapshotBuilder()) {
+        HeapIterationScope heapIterationScope(*this);
+        GatherHeapSnapshotData functor(*builder);
+        m_objectSpace.forEachLiveCell(heapIterationScope, functor);
+    }
+}
+
</ins><span class="cx"> struct RemoveDeadHeapSnapshotNodes : MarkedBlock::CountFunctor {
</span><span class="cx">     RemoveDeadHeapSnapshotNodes(HeapSnapshot&amp; snapshot)
</span><span class="cx">         : m_snapshot(snapshot)
</span><span class="lines">@@ -783,17 +808,14 @@
</span><span class="cx">     HeapSnapshot&amp; m_snapshot;
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-void Heap::removeDeadHeapSnapshotNodes()
</del><ins>+void Heap::removeDeadHeapSnapshotNodes(HeapProfiler&amp; heapProfiler)
</ins><span class="cx"> {
</span><span class="cx">     GCPHASE(RemoveDeadHeapSnapshotNodes);
</span><del>-    HeapProfiler* heapProfiler = m_vm-&gt;heapProfiler();
-    if (UNLIKELY(heapProfiler)) {
-        if (HeapSnapshot* snapshot = heapProfiler-&gt;mostRecentSnapshot()) {
-            HeapIterationScope heapIterationScope(*this);
-            RemoveDeadHeapSnapshotNodes functor(*snapshot);
-            m_objectSpace.forEachDeadCell(heapIterationScope, functor);
-            snapshot-&gt;shrinkToFit();
-        }
</del><ins>+    if (HeapSnapshot* snapshot = heapProfiler.mostRecentSnapshot()) {
+        HeapIterationScope heapIterationScope(*this);
+        RemoveDeadHeapSnapshotNodes functor(*snapshot);
+        m_objectSpace.forEachDeadCell(heapIterationScope, functor);
+        snapshot-&gt;shrinkToFit();
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1163,7 +1185,12 @@
</span><span class="cx">     removeDeadCompilerWorklistEntries();
</span><span class="cx">     deleteUnmarkedCompiledCode();
</span><span class="cx">     deleteSourceProviderCaches();
</span><del>-    removeDeadHeapSnapshotNodes();
</del><ins>+
+    if (HeapProfiler* heapProfiler = m_vm-&gt;heapProfiler()) {
+        gatherExtraHeapSnapshotData(*heapProfiler);
+        removeDeadHeapSnapshotNodes(*heapProfiler);
+    }
+
</ins><span class="cx">     notifyIncrementalSweeper();
</span><span class="cx">     writeBarrierCurrentlyExecutingCodeBlocks();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -60,6 +60,7 @@
</span><span class="cx"> class GCActivityCallback;
</span><span class="cx"> class GCAwareJITStubRoutine;
</span><span class="cx"> class Heap;
</span><ins>+class HeapProfiler;
</ins><span class="cx"> class HeapRootVisitor;
</span><span class="cx"> class HeapVerifier;
</span><span class="cx"> class IncrementalSweeper;
</span><span class="lines">@@ -329,7 +330,6 @@
</span><span class="cx">     void sweepArrayBuffers();
</span><span class="cx">     void snapshotMarkedSpace();
</span><span class="cx">     void deleteSourceProviderCaches();
</span><del>-    void removeDeadHeapSnapshotNodes();
</del><span class="cx">     void notifyIncrementalSweeper();
</span><span class="cx">     void writeBarrierCurrentlyExecutingCodeBlocks();
</span><span class="cx">     void resetAllocators();
</span><span class="lines">@@ -344,6 +344,8 @@
</span><span class="cx">     void resumeCompilerThreads();
</span><span class="cx">     void zombifyDeadObjects();
</span><span class="cx">     void markDeadObjects();
</span><ins>+    void gatherExtraHeapSnapshotData(HeapProfiler&amp;);
+    void removeDeadHeapSnapshotNodes(HeapProfiler&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void sweepAllLogicallyEmptyWeakBlocks();
</span><span class="cx">     bool sweepNextLogicallyEmptyWeakBlock();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapSnapshotBuildercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -70,7 +70,7 @@
</span><span class="cx">     if (hasExistingNodeForCell(cell))
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    std::lock_guard&lt;Lock&gt; lock(m_appendingNodeMutex);
</del><ins>+    std::lock_guard&lt;Lock&gt; lock(m_buildingNodeMutex);
</ins><span class="cx"> 
</span><span class="cx">     m_snapshot-&gt;appendNode(HeapSnapshotNode(cell, getNextObjectIdentifier()));
</span><span class="cx"> }
</span><span class="lines">@@ -84,11 +84,41 @@
</span><span class="cx">     if (from == to)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    std::lock_guard&lt;Lock&gt; lock(m_appendingEdgeMutex);
</del><ins>+    std::lock_guard&lt;Lock&gt; lock(m_buildingEdgeMutex);
</ins><span class="cx"> 
</span><span class="cx">     m_edges.append(HeapSnapshotEdge(from, to));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void HeapSnapshotBuilder::appendPropertyNameEdge(JSCell* from, JSCell* to, UniquedStringImpl* propertyName)
+{
+    ASSERT(m_profiler.activeSnapshotBuilder() == this);
+    ASSERT(to);
+
+    std::lock_guard&lt;Lock&gt; lock(m_buildingEdgeMutex);
+
+    m_edges.append(HeapSnapshotEdge(from, to, EdgeType::Property, propertyName));
+}
+
+void HeapSnapshotBuilder::appendVariableNameEdge(JSCell* from, JSCell* to, UniquedStringImpl* variableName)
+{
+    ASSERT(m_profiler.activeSnapshotBuilder() == this);
+    ASSERT(to);
+
+    std::lock_guard&lt;Lock&gt; lock(m_buildingEdgeMutex);
+
+    m_edges.append(HeapSnapshotEdge(from, to, EdgeType::Variable, variableName));
+}
+
+void HeapSnapshotBuilder::appendIndexEdge(JSCell* from, JSCell* to, uint32_t index)
+{
+    ASSERT(m_profiler.activeSnapshotBuilder() == this);
+    ASSERT(to);
+
+    std::lock_guard&lt;Lock&gt; lock(m_buildingEdgeMutex);
+
+    m_edges.append(HeapSnapshotEdge(from, to, index));
+}
+
</ins><span class="cx"> bool HeapSnapshotBuilder::hasExistingNodeForCell(JSCell* cell)
</span><span class="cx"> {
</span><span class="cx">     if (!m_snapshot-&gt;previous())
</span><span class="lines">@@ -221,6 +251,20 @@
</span><span class="cx">         json.appendNumber(toIdentifier);
</span><span class="cx">         json.append(',');
</span><span class="cx">         json.appendNumber(edgeTypeToNumber(edge.type));
</span><ins>+        switch (edge.type) {
+        case EdgeType::Property:
+        case EdgeType::Variable:
+            json.append(',');
+            json.appendQuotedJSONString(edge.u.name);
+            break;
+        case EdgeType::Index:
+            json.append(',');
+            json.appendNumber(edge.u.index);
+            break;
+        default:
+            // No data for this edge type.
+            break;
+        }
</ins><span class="cx">         json.append(']');
</span><span class="cx">     };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapSnapshotBuilderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/heap/HeapSnapshotBuilder.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #include &lt;functional&gt;
</span><span class="cx"> #include &lt;wtf/Lock.h&gt;
</span><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><ins>+#include &lt;wtf/text/UniquedStringImpl.h&gt;
</ins><span class="cx"> #include &lt;wtf/text/WTFString.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -62,9 +63,30 @@
</span><span class="cx">         , type(EdgeType::Internal)
</span><span class="cx">     { }
</span><span class="cx"> 
</span><ins>+    HeapSnapshotEdge(JSCell* from, JSCell* to, EdgeType type, UniquedStringImpl* name)
+        : from(from)
+        , to(to)
+        , type(type)
+    {
+        ASSERT(type == EdgeType::Property || type == EdgeType::Variable);
+        u.name = name;
+    }
+
+    HeapSnapshotEdge(JSCell* from, JSCell* to, uint32_t index)
+        : from(from)
+        , to(to)
+        , type(EdgeType::Index)
+    {
+        u.index = index;
+    }
+
</ins><span class="cx">     JSCell* from;
</span><span class="cx">     JSCell* to;
</span><span class="cx">     EdgeType type;
</span><ins>+    union {
+        UniquedStringImpl* name;
+        uint32_t index;
+    } u;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class JS_EXPORT_PRIVATE HeapSnapshotBuilder {
</span><span class="lines">@@ -84,6 +106,9 @@
</span><span class="cx"> 
</span><span class="cx">     // A reference from one cell to another.
</span><span class="cx">     void appendEdge(JSCell* from, JSCell* to);
</span><ins>+    void appendPropertyNameEdge(JSCell* from, JSCell* to, UniquedStringImpl* propertyName);
+    void appendVariableNameEdge(JSCell* from, JSCell* to, UniquedStringImpl* variableName);
+    void appendIndexEdge(JSCell* from, JSCell* to, uint32_t index);
</ins><span class="cx"> 
</span><span class="cx">     String json();
</span><span class="cx">     String json(std::function&lt;bool (const HeapSnapshotNode&amp;)&gt; allowNodeCallback);
</span><span class="lines">@@ -96,9 +121,9 @@
</span><span class="cx">     HeapProfiler&amp; m_profiler;
</span><span class="cx"> 
</span><span class="cx">     // SlotVisitors run in parallel.
</span><del>-    Lock m_appendingNodeMutex;
</del><ins>+    Lock m_buildingNodeMutex;
</ins><span class="cx">     std::unique_ptr&lt;HeapSnapshot&gt; m_snapshot;
</span><del>-    Lock m_appendingEdgeMutex;
</del><ins>+    Lock m_buildingEdgeMutex;
</ins><span class="cx">     Vector&lt;HeapSnapshotEdge&gt; m_edges;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -129,12 +129,20 @@
</span><span class="cx">     if (!value || !value.isCell())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    if (m_heapSnapshotBuilder)
</del><ins>+    if (UNLIKELY(m_heapSnapshotBuilder))
</ins><span class="cx">         m_heapSnapshotBuilder-&gt;appendEdge(m_currentCell, value.asCell());
</span><span class="cx"> 
</span><span class="cx">     setMarkedAndAppendToMarkStack(value.asCell());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SlotVisitor::appendHidden(JSValue value)
+{
+    if (!value || !value.isCell())
+        return;
+
+    setMarkedAndAppendToMarkStack(value.asCell());
+}
+
</ins><span class="cx"> void SlotVisitor::setMarkedAndAppendToMarkStack(JSCell* cell)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!m_isCheckingForDefaultMarkViolation);
</span><span class="lines">@@ -167,7 +175,7 @@
</span><span class="cx">     m_bytesVisited += MarkedBlock::blockFor(cell)-&gt;cellSize();
</span><span class="cx">     m_stack.append(cell);
</span><span class="cx"> 
</span><del>-    if (m_heapSnapshotBuilder)
</del><ins>+    if (UNLIKELY(m_heapSnapshotBuilder))
</ins><span class="cx">         m_heapSnapshotBuilder-&gt;appendNode(cell);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitor.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitor.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitor.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -67,8 +67,10 @@
</span><span class="cx">     
</span><span class="cx">     template&lt;typename T&gt; void append(JITWriteBarrier&lt;T&gt;*);
</span><span class="cx">     template&lt;typename T&gt; void append(WriteBarrierBase&lt;T&gt;*);
</span><ins>+    template&lt;typename T&gt; void appendHidden(WriteBarrierBase&lt;T&gt;*);
</ins><span class="cx">     template&lt;typename Iterator&gt; void append(Iterator begin , Iterator end);
</span><span class="cx">     void appendValues(WriteBarrierBase&lt;Unknown&gt;*, size_t count);
</span><ins>+    void appendValuesHidden(WriteBarrierBase&lt;Unknown&gt;*, size_t count);
</ins><span class="cx">     
</span><span class="cx">     template&lt;typename T&gt;
</span><span class="cx">     void appendUnbarrieredPointer(T**);
</span><span class="lines">@@ -119,6 +121,7 @@
</span><span class="cx">     friend class ParallelModeEnabler;
</span><span class="cx">     
</span><span class="cx">     JS_EXPORT_PRIVATE void append(JSValue); // This is private to encourage clients to use WriteBarrier&lt;T&gt;.
</span><ins>+    void appendHidden(JSValue);
</ins><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE void setMarkedAndAppendToMarkStack(JSCell*);
</span><span class="cx">     void appendToMarkStack(JSCell*);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -69,6 +69,12 @@
</span><span class="cx">     append(slot-&gt;get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;typename T&gt;
+inline void SlotVisitor::appendHidden(WriteBarrierBase&lt;T&gt;* slot)
+{
+    appendHidden(slot-&gt;get());
+}
+
</ins><span class="cx"> template&lt;typename Iterator&gt;
</span><span class="cx"> inline void SlotVisitor::append(Iterator begin, Iterator end)
</span><span class="cx"> {
</span><span class="lines">@@ -82,6 +88,12 @@
</span><span class="cx">         append(&amp;barriers[i]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline void SlotVisitor::appendValuesHidden(WriteBarrierBase&lt;Unknown&gt;* barriers, size_t count)
+{
+    for (size_t i = 0; i &lt; count; ++i)
+        appendHidden(&amp;barriers[i]);
+}
+
</ins><span class="cx"> inline void SlotVisitor::addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester)
</span><span class="cx"> {
</span><span class="cx">     m_heap.m_weakReferenceHarvesters.addThreadSafe(weakReferenceHarvester);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jsc.cpp (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jsc.cpp        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/jsc.cpp        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -485,11 +485,6 @@
</span><span class="cx">         return simpleObject;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void finishCreation(VM&amp; vm)
-    {
-        Base::finishCreation(vm);
-    }
-
</del><span class="cx">     static void visitChildren(JSCell* cell, SlotVisitor&amp; visitor)
</span><span class="cx">     {
</span><span class="cx">         SimpleObject* thisObject = jsCast&lt;SimpleObject*&gt;(cell);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeClassInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ClassInfo.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ClassInfo.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/ClassInfo.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+class HeapSnapshotBuilder;
</ins><span class="cx"> class JSArrayBufferView;
</span><span class="cx"> struct HashTable;
</span><span class="cx"> 
</span><span class="lines">@@ -118,6 +119,9 @@
</span><span class="cx">     typedef void (*DumpToStreamFunctionPtr)(const JSCell*, PrintStream&amp;);
</span><span class="cx">     DumpToStreamFunctionPtr dumpToStream;
</span><span class="cx"> 
</span><ins>+    typedef void (*HeapSnapshotFunctionPtr)(JSCell*, HeapSnapshotBuilder&amp;);
+    HeapSnapshotFunctionPtr heapSnapshot;
+
</ins><span class="cx">     typedef size_t (*EstimatedSizeFunctionPtr)(JSCell*);
</span><span class="cx">     EstimatedSizeFunctionPtr estimatedSize;
</span><span class="cx"> };
</span><span class="lines">@@ -171,6 +175,7 @@
</span><span class="cx">         &amp;ClassName::setPrototype, \
</span><span class="cx">         &amp;ClassName::getPrototype, \
</span><span class="cx">         &amp;ClassName::dumpToStream, \
</span><ins>+        &amp;ClassName::heapSnapshot, \
</ins><span class="cx">         &amp;ClassName::estimatedSize \
</span><span class="cx">     }, \
</span><span class="cx">     ClassName::TypedArrayStorageType
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCellcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCell.cpp (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCell.cpp        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/JSCell.cpp        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -65,6 +65,10 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void JSCell::heapSnapshot(JSCell*, HeapSnapshotBuilder&amp;)
+{
+}
+
</ins><span class="cx"> bool JSCell::getString(ExecState* exec, String&amp; stringValue) const
</span><span class="cx"> {
</span><span class="cx">     if (!isString())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCellh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCell.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCell.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/JSCell.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -141,6 +141,8 @@
</span><span class="cx">     static void visitChildren(JSCell*, SlotVisitor&amp;);
</span><span class="cx">     JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&amp;, CopyToken);
</span><span class="cx"> 
</span><ins>+    JS_EXPORT_PRIVATE static void heapSnapshot(JSCell*, HeapSnapshotBuilder&amp;);
+
</ins><span class="cx">     // Object operations, with the toObject operation included.
</span><span class="cx">     const ClassInfo* classInfo() const;
</span><span class="cx">     const MethodTable* methodTable() const;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSEnvironmentRecordcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSEnvironmentRecord.cpp (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSEnvironmentRecord.cpp        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/JSEnvironmentRecord.cpp        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;JSEnvironmentRecord.h&quot;
</span><span class="cx"> 
</span><ins>+#include &quot;HeapSnapshotBuilder.h&quot;
</ins><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -40,7 +41,27 @@
</span><span class="cx">     JSEnvironmentRecord* thisObject = jsCast&lt;JSEnvironmentRecord*&gt;(cell);
</span><span class="cx">     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
</span><span class="cx">     Base::visitChildren(thisObject, visitor);
</span><del>-    visitor.appendValues(thisObject-&gt;variables(), thisObject-&gt;symbolTable()-&gt;scopeSize());
</del><ins>+    visitor.appendValuesHidden(thisObject-&gt;variables(), thisObject-&gt;symbolTable()-&gt;scopeSize());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void JSEnvironmentRecord::heapSnapshot(JSCell* cell, HeapSnapshotBuilder&amp; builder)
+{
+    JSEnvironmentRecord* thisObject = jsCast&lt;JSEnvironmentRecord*&gt;(cell);
+    Base::heapSnapshot(cell, builder);
+
+    ConcurrentJITLocker locker(thisObject-&gt;symbolTable()-&gt;m_lock);
+    SymbolTable::Map::iterator end = thisObject-&gt;symbolTable()-&gt;end(locker);
+    for (SymbolTable::Map::iterator it = thisObject-&gt;symbolTable()-&gt;begin(locker); it != end; ++it) {
+        SymbolTableEntry::Fast entry = it-&gt;value;
+        ASSERT(!entry.isNull());
+        ScopeOffset offset = entry.scopeOffset();
+        if (!thisObject-&gt;isValidScopeOffset(offset))
+            continue;
+
+        JSValue toValue = thisObject-&gt;variableAt(offset).get();
+        if (toValue &amp;&amp; toValue.isCell())
+            builder.appendVariableNameEdge(thisObject, toValue.asCell(), it-&gt;key.get());
+    }
+}
+
</ins><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSEnvironmentRecordh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSEnvironmentRecord.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSEnvironmentRecord.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/JSEnvironmentRecord.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -111,6 +111,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static void visitChildren(JSCell*, SlotVisitor&amp;);
</span><ins>+    static void heapSnapshot(JSCell*, HeapSnapshotBuilder&amp;);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.cpp (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.cpp        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.cpp        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -35,15 +35,16 @@
</span><span class="cx"> #include &quot;Exception.h&quot;
</span><span class="cx"> #include &quot;Executable.h&quot;
</span><span class="cx"> #include &quot;GetterSetter.h&quot;
</span><ins>+#include &quot;HeapSnapshotBuilder.h&quot;
</ins><span class="cx"> #include &quot;IndexingHeaderInlines.h&quot;
</span><span class="cx"> #include &quot;JSBoundSlotBaseFunction.h&quot;
</span><ins>+#include &quot;JSCInlines.h&quot;
</ins><span class="cx"> #include &quot;JSFunction.h&quot;
</span><span class="cx"> #include &quot;JSGlobalObject.h&quot;
</span><span class="cx"> #include &quot;Lookup.h&quot;
</span><span class="cx"> #include &quot;NativeErrorConstructor.h&quot;
</span><span class="cx"> #include &quot;Nodes.h&quot;
</span><span class="cx"> #include &quot;ObjectPrototype.h&quot;
</span><del>-#include &quot;JSCInlines.h&quot;
</del><span class="cx"> #include &quot;PropertyDescriptor.h&quot;
</span><span class="cx"> #include &quot;PropertyNameArray.h&quot;
</span><span class="cx"> #include &quot;ProxyObject.h&quot;
</span><span class="lines">@@ -157,12 +158,11 @@
</span><span class="cx">     } 
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor&amp; visitor, Butterfly* butterfly, size_t storageSize)
</del><ins>+ALWAYS_INLINE void JSObject::visitButterfly(SlotVisitor&amp; visitor, Butterfly* butterfly, Structure* structure)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(butterfly);
</span><span class="cx">     
</span><del>-    Structure* structure = this-&gt;structure(visitor.vm());
-    
</del><ins>+    size_t storageSize = structure-&gt;outOfLineSize();
</ins><span class="cx">     size_t propertyCapacity = structure-&gt;outOfLineCapacity();
</span><span class="cx">     size_t preCapacity;
</span><span class="cx">     size_t indexingPayloadSizeInBytes;
</span><span class="lines">@@ -177,7 +177,7 @@
</span><span class="cx">     size_t capacityInBytes = Butterfly::totalSize(preCapacity, propertyCapacity, hasIndexingHeader, indexingPayloadSizeInBytes);
</span><span class="cx"> 
</span><span class="cx">     // Mark the properties.
</span><del>-    visitor.appendValues(butterfly-&gt;propertyStorage() - storageSize, storageSize);
</del><ins>+    visitor.appendValuesHidden(butterfly-&gt;propertyStorage() - storageSize, storageSize);
</ins><span class="cx">     visitor.copyLater(
</span><span class="cx">         this, ButterflyCopyToken,
</span><span class="cx">         butterfly-&gt;base(preCapacity, propertyCapacity), capacityInBytes);
</span><span class="lines">@@ -185,10 +185,10 @@
</span><span class="cx">     // Mark the array if appropriate.
</span><span class="cx">     switch (this-&gt;indexingType()) {
</span><span class="cx">     case ALL_CONTIGUOUS_INDEXING_TYPES:
</span><del>-        visitor.appendValues(butterfly-&gt;contiguous().data(), butterfly-&gt;publicLength());
</del><ins>+        visitor.appendValuesHidden(butterfly-&gt;contiguous().data(), butterfly-&gt;publicLength());
</ins><span class="cx">         break;
</span><span class="cx">     case ALL_ARRAY_STORAGE_INDEXING_TYPES:
</span><del>-        visitor.appendValues(butterfly-&gt;arrayStorage()-&gt;m_vector, butterfly-&gt;arrayStorage()-&gt;vectorLength());
</del><ins>+        visitor.appendValuesHidden(butterfly-&gt;arrayStorage()-&gt;m_vector, butterfly-&gt;arrayStorage()-&gt;vectorLength());
</ins><span class="cx">         if (butterfly-&gt;arrayStorage()-&gt;m_sparseMap)
</span><span class="cx">             visitor.append(&amp;butterfly-&gt;arrayStorage()-&gt;m_sparseMap);
</span><span class="cx">         break;
</span><span class="lines">@@ -217,7 +217,7 @@
</span><span class="cx"> 
</span><span class="cx">     Butterfly* butterfly = thisObject-&gt;m_butterfly.getWithoutBarrier();
</span><span class="cx">     if (butterfly)
</span><del>-        thisObject-&gt;visitButterfly(visitor, butterfly, thisObject-&gt;structure(visitor.vm())-&gt;outOfLineSize());
</del><ins>+        thisObject-&gt;visitButterfly(visitor, butterfly, thisObject-&gt;structure(visitor.vm()));
</ins><span class="cx"> 
</span><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx">     visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
</span><span class="lines">@@ -237,6 +237,44 @@
</span><span class="cx">         thisObject-&gt;copyButterfly(visitor, butterfly, thisObject-&gt;structure()-&gt;outOfLineSize());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void JSObject::heapSnapshot(JSCell* cell, HeapSnapshotBuilder&amp; builder)
+{
+    JSObject* thisObject = jsCast&lt;JSObject*&gt;(cell);
+    Base::heapSnapshot(cell, builder);
+
+    Structure* structure = thisObject-&gt;structure();
+    for (auto&amp; entry : structure-&gt;getPropertiesConcurrently()) {
+        JSValue toValue = thisObject-&gt;getDirect(entry.offset);
+        if (toValue &amp;&amp; toValue.isCell())
+            builder.appendPropertyNameEdge(thisObject, toValue.asCell(), entry.key);
+    }
+
+    Butterfly* butterfly = thisObject-&gt;m_butterfly.getWithoutBarrier();
+    if (butterfly) {
+        WriteBarrier&lt;Unknown&gt;* data;
+        uint32_t count = 0;
+
+        switch (thisObject-&gt;indexingType()) {
+        case ALL_CONTIGUOUS_INDEXING_TYPES:
+            data = butterfly-&gt;contiguous().data();
+            count = butterfly-&gt;publicLength();
+            break;
+        case ALL_ARRAY_STORAGE_INDEXING_TYPES:
+            data = butterfly-&gt;arrayStorage()-&gt;m_vector;
+            count = butterfly-&gt;arrayStorage()-&gt;vectorLength();
+            break;
+        default:
+            break;
+        }
+
+        for (uint32_t i = 0; i &lt; count; ++i) {
+            JSValue toValue = data[i].get();
+            if (toValue &amp;&amp; toValue.isCell())
+                builder.appendIndexEdge(thisObject, toValue.asCell(), i);
+        }
+    }
+}
+
</ins><span class="cx"> void JSFinalObject::visitChildren(JSCell* cell, SlotVisitor&amp; visitor)
</span><span class="cx"> {
</span><span class="cx">     JSFinalObject* thisObject = jsCast&lt;JSFinalObject*&gt;(cell);
</span><span class="lines">@@ -248,13 +286,13 @@
</span><span class="cx">     
</span><span class="cx">     JSCell::visitChildren(thisObject, visitor);
</span><span class="cx"> 
</span><del>-    Structure* structure = thisObject-&gt;structure();
</del><ins>+    Structure* structure = thisObject-&gt;structure(visitor.vm());
</ins><span class="cx">     Butterfly* butterfly = thisObject-&gt;butterfly();
</span><span class="cx">     if (butterfly)
</span><del>-        thisObject-&gt;visitButterfly(visitor, butterfly, structure-&gt;outOfLineSize());
</del><ins>+        thisObject-&gt;visitButterfly(visitor, butterfly, structure);
</ins><span class="cx"> 
</span><span class="cx">     size_t storageSize = structure-&gt;inlineSize();
</span><del>-    visitor.appendValues(thisObject-&gt;inlineStorage(), storageSize);
</del><ins>+    visitor.appendValuesHidden(thisObject-&gt;inlineStorage(), storageSize);
</ins><span class="cx"> 
</span><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx">     visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -99,6 +99,7 @@
</span><span class="cx">     JS_EXPORT_PRIVATE static size_t estimatedSize(JSCell*);
</span><span class="cx">     JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&amp;);
</span><span class="cx">     JS_EXPORT_PRIVATE static void copyBackingStore(JSCell*, CopyVisitor&amp;, CopyToken);
</span><ins>+    JS_EXPORT_PRIVATE static void heapSnapshot(JSCell*, HeapSnapshotBuilder&amp;);
</ins><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE static String className(const JSObject*);
</span><span class="cx">     JS_EXPORT_PRIVATE static String calculatedClassName(JSObject*);
</span><span class="lines">@@ -785,7 +786,7 @@
</span><span class="cx">     // To create derived types you likely want JSNonFinalObject, below.
</span><span class="cx">     JSObject(VM&amp;, Structure*, Butterfly* = 0);
</span><span class="cx">         
</span><del>-    void visitButterfly(SlotVisitor&amp;, Butterfly*, size_t storageSize);
</del><ins>+    void visitButterfly(SlotVisitor&amp;, Butterfly*, Structure*);
</ins><span class="cx">     void copyButterfly(CopyVisitor&amp;, Butterfly*, size_t storageSize);
</span><span class="cx"> 
</span><span class="cx">     // Call this if you know that the object is in a mode where it has array
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSSegmentedVariableObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.cpp        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;JSSegmentedVariableObject.h&quot;
</span><span class="cx"> 
</span><ins>+#include &quot;HeapSnapshotBuilder.h&quot;
</ins><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -63,11 +64,31 @@
</span><span class="cx"> {
</span><span class="cx">     JSSegmentedVariableObject* thisObject = jsCast&lt;JSSegmentedVariableObject*&gt;(cell);
</span><span class="cx">     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
</span><del>-    JSSymbolTableObject::visitChildren(thisObject, slotVisitor);
</del><ins>+    Base::visitChildren(thisObject, slotVisitor);
</ins><span class="cx">     
</span><span class="cx">     for (unsigned i = thisObject-&gt;m_variables.size(); i--;)
</span><del>-        slotVisitor.append(&amp;thisObject-&gt;m_variables[i]);
</del><ins>+        slotVisitor.appendHidden(&amp;thisObject-&gt;m_variables[i]);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void JSSegmentedVariableObject::heapSnapshot(JSCell* cell, HeapSnapshotBuilder&amp; builder)
+{
+    JSSegmentedVariableObject* thisObject = jsCast&lt;JSSegmentedVariableObject*&gt;(cell);
+    Base::heapSnapshot(cell, builder);
+
+    ConcurrentJITLocker locker(thisObject-&gt;symbolTable()-&gt;m_lock);
+    SymbolTable::Map::iterator end = thisObject-&gt;symbolTable()-&gt;end(locker);
+    for (SymbolTable::Map::iterator it = thisObject-&gt;symbolTable()-&gt;begin(locker); it != end; ++it) {
+        SymbolTableEntry::Fast entry = it-&gt;value;
+        ASSERT(!entry.isNull());
+        ScopeOffset offset = entry.scopeOffset();
+        if (!thisObject-&gt;isValidScopeOffset(offset))
+            continue;
+
+        JSValue toValue = thisObject-&gt;variableAt(offset).get();
+        if (toValue &amp;&amp; toValue.isCell())
+            builder.appendVariableNameEdge(thisObject, toValue.asCell(), it-&gt;key.get());
+    }
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSSegmentedVariableObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/JSSegmentedVariableObject.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -85,6 +85,7 @@
</span><span class="cx">     JS_EXPORT_PRIVATE ScopeOffset addVariables(unsigned numberOfVariablesToAdd, JSValue);
</span><span class="cx">     
</span><span class="cx">     JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&amp;);
</span><ins>+    JS_EXPORT_PRIVATE static void heapSnapshot(JSCell*, HeapSnapshotBuilder&amp;);
</ins><span class="cx"> 
</span><span class="cx"> protected:
</span><span class="cx">     JSSegmentedVariableObject(VM&amp; vm, Structure* structure, JSScope* scope)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructurecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.cpp (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.cpp        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/Structure.cpp        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -1127,7 +1127,9 @@
</span><span class="cx">     if (thisObject-&gt;isPinnedPropertyTable()) {
</span><span class="cx">         ASSERT(thisObject-&gt;m_propertyTableUnsafe);
</span><span class="cx">         visitor.append(&amp;thisObject-&gt;m_propertyTableUnsafe);
</span><del>-    } else if (thisObject-&gt;m_propertyTableUnsafe)
</del><ins>+    } else if (visitor.isBuildingHeapSnapshot())
+        visitor.append(&amp;thisObject-&gt;m_propertyTableUnsafe);
+    else if (thisObject-&gt;m_propertyTableUnsafe)
</ins><span class="cx">         thisObject-&gt;m_propertyTableUnsafe.clear();
</span><span class="cx"> 
</span><span class="cx">     visitor.append(&amp;thisObject-&gt;m_inferredTypeTable);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/Structure.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -720,6 +720,7 @@
</span><span class="cx">     StructureTransitionTable m_transitionTable;
</span><span class="cx"> 
</span><span class="cx">     // Should be accessed through propertyTable(). During GC, it may be set to 0 by another thread.
</span><ins>+    // During a Heap Snapshot GC we avoid clearing the table so it is safe to use.
</ins><span class="cx">     WriteBarrier&lt;PropertyTable&gt; m_propertyTableUnsafe;
</span><span class="cx"> 
</span><span class="cx">     WriteBarrier&lt;InferredTypeTable&gt; m_inferredTypeTable;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructureInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StructureInlines.h (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StructureInlines.h        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/runtime/StructureInlines.h        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -242,7 +242,7 @@
</span><span class="cx"> 
</span><span class="cx"> ALWAYS_INLINE WriteBarrier&lt;PropertyTable&gt;&amp; Structure::propertyTable()
</span><span class="cx"> {
</span><del>-    ASSERT(!globalObject() || !globalObject()-&gt;vm().heap.isCollecting());
</del><ins>+    ASSERT(!globalObject() || (!globalObject()-&gt;vm().heap.isCollecting() || globalObject()-&gt;vm().heap.isHeapSnapshotting()));
</ins><span class="cx">     return m_propertyTableUnsafe;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsheapProfilerdriverdriverjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/heapProfiler/driver/driver.js (197711 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/heapProfiler/driver/driver.js        2016-03-07 23:27:44 UTC (rev 197711)
+++ trunk/Source/JavaScriptCore/tests/heapProfiler/driver/driver.js        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -240,3 +240,17 @@
</span><span class="cx"> 
</span><span class="cx">     return new HeapSnapshot(json);
</span><span class="cx"> }
</span><ins>+
+function followPath(node, path) {
+    let current = node;
+    for (let component of path) {
+        let edges = null;
+        if (component.edge)
+            edges = current.outgoingEdges.filter((e) =&gt; e.data === component.edge);
+        else if (component.node)
+            edges = current.outgoingEdges.filter((e) =&gt; e.to.className === component.node);
+        assert(edges.length === 1, &quot;Ambiguous or bad path component: &quot; + JSON.stringify(component));
+        current = edges[0].to;
+    }
+    return current;
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsheapProfilerpropertyedgetypesjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/heapProfiler/property-edge-types.js (0 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/heapProfiler/property-edge-types.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/heapProfiler/property-edge-types.js        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -0,0 +1,98 @@
</span><ins>+load(&quot;./driver/driver.js&quot;);
+
+let simpleObject = new SimpleObject;
+setHiddenValue(simpleObject, &quot;hiddenValue&quot;); // Internal
+simpleObject.propertyName1 = &quot;propertyValue1&quot;; // Property
+simpleObject[&quot;propertyName2&quot;] = &quot;propertyValue2&quot;; // Property
+simpleObject[100] = &quot;indexedValue&quot;; // Index
+simpleObject[0xffffffff + 100] = &quot;largeIndexValueBecomingProperty&quot;; // Property
+simpleObject.point = {x:&quot;x1&quot;, y:&quot;y1&quot;}; // Property =&gt; object with 2 inline properties.
+
+// ----------
+
+function excludeStructure(edges) {
+    return edges.filter((x) =&gt; x.to.className !== &quot;Structure&quot;);
+}
+
+let snapshot = createHeapSnapshot();
+
+// Internal, Property, and Index edges on an Object.
+let nodes = snapshot.nodesWithClassName(&quot;SimpleObject&quot;);
+assert(nodes.length === 1, &quot;Snapshot should contain 1 'SimpleObject' instance&quot;);
+let simpleObjectNode = nodes[0];
+let edges = excludeStructure(simpleObjectNode.outgoingEdges);
+let pointNode = null;
+
+let seenHiddenValue = false;
+let seenPropertyName1 = false;
+let seenPropertyName2 = false;
+let seenIndex100 = false;
+let seenLargeIndex = false;
+let seenObjectWithInlineStorage = false;
+let largeIndexName = (0xffffffff + 100).toString();
+
+for (let edge of edges) {
+    switch (edge.type) {
+    case &quot;Internal&quot;:
+        assert(!seenHiddenValue);
+        seenHiddenValue = true;
+        break;
+    case &quot;Property&quot;:
+        if (edge.data === &quot;propertyName1&quot;)
+            seenPropertyName1 = true;
+        else if (edge.data === &quot;propertyName2&quot;)
+            seenPropertyName2 = true;
+        else if (edge.data === largeIndexName)
+            seenLargeIndex = true;
+        else if (edge.data === &quot;point&quot;) {
+            seenPoint = true;
+            pointNode = edge.to;
+        } else
+            assert(false, &quot;Unexpected property name&quot;);
+        break;
+    case &quot;Index&quot;:
+        if (edge.data === 100)
+            seenIndex100 = true;
+        break;
+    case &quot;Variable&quot;:
+        assert(false, &quot;Should not see a variable edge for SimpleObject instance&quot;);
+        break;
+    default:
+        assert(false, &quot;Unexpected edge type&quot;);
+        break;
+    }
+}
+
+assert(seenHiddenValue, &quot;Should see Internal edge for hidden value&quot;);
+assert(seenPropertyName1, &quot;Should see Property edge for propertyName1&quot;);
+assert(seenPropertyName2, &quot;Should see Property edge for propertyName2&quot;);
+assert(seenIndex100, &quot;Should see Index edge for index 100&quot;);
+assert(seenLargeIndex, &quot;Should see Property edge for index &quot; + largeIndexName);
+
+
+// Property on an Object's inline storage.
+let pointEdges = excludeStructure(pointNode.outgoingEdges);
+
+let seenPropertyX = false;
+let seenPropertyY = false;
+
+for (let edge of pointEdges) {
+    switch (edge.type) {
+    case &quot;Property&quot;:
+        if (edge.data === &quot;x&quot;)
+            seenPropertyX = true;
+        else if (edge.data === &quot;y&quot;)
+            seenPropertyY = true;
+        else
+            assert(false, &quot;Unexpected property name&quot;);
+        break;
+    case &quot;Index&quot;:
+    case &quot;Variable&quot;:
+    case &quot;Internal&quot;:
+        assert(false, &quot;Unexpected edge type&quot;);
+        break;
+    }
+}
+
+assert(seenPropertyX, &quot;Should see Property edge for x&quot;);
+assert(seenPropertyY, &quot;Should see Property edge for y&quot;);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsheapProfilervariableedgetypesjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/heapProfiler/variable-edge-types.js (0 => 197712)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/heapProfiler/variable-edge-types.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/heapProfiler/variable-edge-types.js        2016-03-07 23:45:38 UTC (rev 197712)
</span><span class="lines">@@ -0,0 +1,69 @@
</span><ins>+load(&quot;./driver/driver.js&quot;);
+
+let globalScopeVariable = &quot;globalScopeVariableValue&quot;;
+let simpleObject = new SimpleObject;
+
+(function() {
+    let closureVariable = {};
+    simpleObject.f = function() { closureVariable.x = 0; }
+})();
+
+// ----------
+
+let snapshot = createHeapSnapshot();
+
+// Global Scope =&gt; &quot;globalScopeVariable&quot;
+let nodes = snapshot.nodesWithClassName(&quot;JSGlobalLexicalEnvironment&quot;);
+assert(nodes.length === 1, &quot;Should be only 1 'JSGlobalLexicalEnvironment' instance&quot;);
+let globalScopeNode = nodes[0];
+
+let seenGlobalScopeVariable = false;
+let seenSimpleObjectVariable = false;
+
+for (let edge of globalScopeNode.outgoingEdges) {
+    switch (edge.type) {
+    case &quot;Variable&quot;:
+        if (edge.data === &quot;globalScopeVariable&quot;)
+            seenGlobalScopeVariable = true;
+        else if (edge.data === &quot;simpleObject&quot;)
+            seenSimpleObjectVariable = true;
+        else
+            assert(false, &quot;Unexpected variable name: &quot; + edge.data);
+        break;
+    case &quot;Index&quot;:
+    case &quot;Property&quot;:
+        assert(false, &quot;Unexpected edge type&quot;);
+        break;
+    case &quot;Internal&quot;:
+        break;
+    }
+}
+
+assert(seenGlobalScopeVariable, &quot;Should see Variable edge for variable 'globalScopeVariable'&quot;);
+assert(seenSimpleObjectVariable, &quot;Should see Variable edge for variable 'simpleObject'&quot;);
+
+// Function Scope =&gt; &quot;closureVariable&quot;
+nodes = snapshot.nodesWithClassName(&quot;SimpleObject&quot;);
+assert(nodes.length === 1, &quot;Should be only 1 'SimpleObject' instance&quot;);
+let scopeNode = followPath(nodes[0], [{edge: &quot;f&quot;}, {node: &quot;JSLexicalEnvironment&quot;}]);
+
+let seenClosureVariable = false;
+
+for (let edge of scopeNode.outgoingEdges) {
+    switch (edge.type) {
+    case &quot;Variable&quot;:
+        if (edge.data === &quot;closureVariable&quot;)
+            seenClosureVariable = true;
+        else
+            assert(false, &quot;Unexpected variable name: &quot; + edge.data);
+        break;
+    case &quot;Index&quot;:
+    case &quot;Property&quot;:
+        assert(false, &quot;Unexpected edge type&quot;);
+        break;
+    case &quot;Internal&quot;:
+        break;
+    }
+}
+
+assert(seenClosureVariable, &quot;Should see Variable edge for closure variable 'closureVariable'&quot;);
</ins></span></pre>
</div>
</div>

</body>
</html>