Changeset 197489 in webkit


Ignore:
Timestamp:
Mar 2, 2016 9:15:56 PM (8 years ago)
Author:
commit-queue@webkit.org
Message:

Add ability to generate a Heap Snapshot
https://bugs.webkit.org/show_bug.cgi?id=154847

Patch by Joseph Pecoraro <Joseph Pecoraro> on 2016-03-02
Reviewed by Mark Lam.

This adds HeapSnapshot, HeapSnapshotBuilder, and HeapProfiler.

HeapProfiler hangs off of the VM and holds the list of snapshots.
I expect to add other HeapProfiling features, such as allocation
tracking, to the profiler.

HeapSnapshot contains a collection of live cells and their identifiers.
It can point to a previous HeapSnapshot, to ensure that a cell that
already received an identifier maintains the same identifier across
multiple snapshots. When a snapshotted cell gets garbage collected,
the cell will be swept from the HeapSnapshot at the end of collection
to ensure the list contains only live cells.

When building a HeapSnapshot nodes are added in increasing node
identifier order. When done building, the list of nodes is complete
and the snapshot is finalized. At this point the nodes are sorted
by JSCell* address to allow for quick lookup of a JSCell*.

HeapSnapshotBuilder is where snapshotting begins. The builder
will initiate a specialized heap snapshotting garbage collection.
During this collection the builder will be notified of all marked
(live) cells, and connections between cells, as seen by SlotVisitors.
The builder can reference the previous, readonly, HeapSnapshots to
avoid creating new nodes for cells that have already been snapshotted.
When it is determined that we are visiting a live cell for the first
time, we give the cell a unique identifier and add it to the the
snapshot we are building.

Since edge data is costly, and of little long term utility, this
data is only held by the builder for serialization, and not stored
long term with the HeapSnapshot node data.

The goals of HeapSnapshotting at this time are:

  • minimal impact on performance when not profiling the heap
  • unique identifier for cells, so they may be identified across multiple snapshots
  • nodes and edges to be able to construct a graph of which nodes reference/retain which other nodes
  • node data - identifier, type (class name), size
  • edge data - from cell, to cell, type / data (to come in a follow-up patch)

Add new files to the build.

  • heap/Heap.cpp:

(JSC::Heap::isHeapSnapshotting):
(JSC::RemoveDeadHeapSnapshotNodes::RemoveDeadHeapSnapshotNodes):
(JSC::RemoveDeadHeapSnapshotNodes::operator()):
(JSC::Heap::removeDeadHeapSnapshotNodes):
(JSC::Heap::collectImpl):
After every collection, sweep dead cells from in memory snapshots.

  • runtime/VM.cpp:

(JSC::VM::ensureHeapProfiler):

  • runtime/VM.h:

(JSC::VM::heapProfiler):

  • heap/Heap.h:
  • heap/HeapProfiler.cpp: Added.

(JSC::HeapProfiler::HeapProfiler):
(JSC::HeapProfiler::~HeapProfiler):
(JSC::HeapProfiler::mostRecentSnapshot):
(JSC::HeapProfiler::appendSnapshot):
(JSC::HeapProfiler::clearSnapshots):
(JSC::HeapProfiler::setActiveSnapshotBuilder):

  • heap/HeapProfiler.h: Added.

(JSC::HeapProfiler::vm):
(JSC::HeapProfiler::activeSnapshotBuilder):
VM and Heap can look at the profiler to determine if we are building a
snapshot, or the "head" snapshot to use for sweeping.

  • heap/HeapSnapshot.cpp: Added.

(JSC::HeapSnapshot::HeapSnapshot):
(JSC::HeapSnapshot::~HeapSnapshot):
(JSC::HeapSnapshot::appendNode):
Add a node to the unfinalized list of new cells.

(JSC::HeapSnapshot::sweepCell):
(JSC::HeapSnapshot::shrinkToFit):
Collect a list of cells for sweeping and then remove them all at once
in shrinkToFit. This is done to avoid thrashing of individual removes
that could cause many overlapping moves within the Vector.

(JSC::HeapSnapshot::finalize):
Sort the list, and also cache the bounding start/stop identifiers.
No other snapshot can contain an identifier in this range, so it will
improve lookup of a node from an identifier.

(JSC::HeapSnapshot::nodeForCell):
(JSC::HeapSnapshot::nodeForObjectIdentifier):
Search helpers.

  • heap/HeapSnapshotBuilder.h: Added.

(JSC::HeapSnapshotNode::HeapSnapshotNode):
(JSC::HeapSnapshotEdge::HeapSnapshotEdge):
Node and Edge struct types the builder creates.

  • heap/HeapSnapshotBuilder.cpp: Added.

(JSC::HeapSnapshotBuilder::getNextObjectIdentifier):
(JSC::HeapSnapshotBuilder::HeapSnapshotBuilder):
(JSC::HeapSnapshotBuilder::~HeapSnapshotBuilder):
(JSC::HeapSnapshotBuilder::buildSnapshot):
(JSC::HeapSnapshotBuilder::appendNode):
(JSC::HeapSnapshotBuilder::appendEdge):
When building the snapshot, generating the next identifier, and
appending to any of the lists must be guarded by a lock because
SlotVisitors running in parallel may be accessing the builder.

(JSC::HeapSnapshotBuilder::hasExistingNodeForCell):
Looking up if a node already exists in a previous snapshot can be
done without a lock because at this point the data is readonly.

(JSC::edgeTypeToNumber):
(JSC::edgeTypeToString):
(JSC::HeapSnapshotBuilder::json):
JSON serialization of a heap snapshot contains node and edge data.

  • heap/SlotVisitor.h:
  • heap/SlotVisitor.cpp:

(JSC::SlotVisitor::didStartMarking):
(JSC::SlotVisitor::reset):
Set/clear the active snapshot builder to know if this will be a
snapshotting GC or not.

(JSC::SlotVisitor::append):
(JSC::SlotVisitor::setMarkedAndAppendToMarkStack):
Inform the builder of a new node or edge.

(JSC::SlotVisitor::visitChildren):
Remember the current cell we are visiting so that if we need to
inform the builder of edges we know the "from" cell.

  • jsc.cpp:

(SimpleObject::SimpleObject):
(SimpleObject::create):
(SimpleObject::finishCreation):
(SimpleObject::visitChildren):
(SimpleObject::createStructure):
(SimpleObject::hiddenValue):
(SimpleObject::setHiddenValue):
Create a new class "SimpleObject" that can be used by heap snapshotting
tests. It is easy to filter for this new class name and test internal
edge relationships created by garbage collection visiting the cell.

(functionCreateSimpleObject):
(functionGetHiddenValue):
(functionSetHiddenValue):
Expose methods to create and interact with a SimpleObject.

(functionGenerateHeapSnapshot):
Expose methods to create a heap snapshot. This currently automatically
turns the serialized string into a JSON object. That may change.

  • tests/heapProfiler.yaml: Added.
  • tests/heapProfiler/basic-edges.js: Added.

(excludeStructure):

  • tests/heapProfiler/basic-nodes.js: Added.

(hasDifferentSizeNodes):
(hasAllInternalNodes):
Add tests for basic node and edge data.

  • tests/heapProfiler/driver/driver.js: Added.

(assert):
(CheapHeapSnapshotNode):
(CheapHeapSnapshotEdge):
(CheapHeapSnapshotEdge.prototype.get from):
(CheapHeapSnapshotEdge.prototype.get to):
(CheapHeapSnapshot):
(CheapHeapSnapshot.prototype.get nodes):
(CheapHeapSnapshot.prototype.get edges):
(CheapHeapSnapshot.prototype.nodeWithIdentifier):
(CheapHeapSnapshot.prototype.nodesWithClassName):
(CheapHeapSnapshot.prototype.classNameFromTableIndex):
(CheapHeapSnapshot.prototype.edgeTypeFromTableIndex):
(createCheapHeapSnapshot):
(HeapSnapshotNode):
(HeapSnapshotEdge):
(HeapSnapshot):
(HeapSnapshot.prototype.nodesWithClassName):
(createHeapSnapshot):
Add two HeapSnapshot representations.
CheapHeapSnapshot creates two lists of node and edge data that
lazily creates objects as needed.
HeapSnapshot creates an object for each node and edge. This
is wasteful but easier to use.

Location:
trunk/Source/JavaScriptCore
Files:
12 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r197468 r197489  
    444444    heap/Heap.cpp
    445445    heap/HeapHelperPool.cpp
     446    heap/HeapProfiler.cpp
     447    heap/HeapSnapshot.cpp
     448    heap/HeapSnapshotBuilder.cpp
    446449    heap/HeapStatistics.cpp
    447450    heap/HeapTimer.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r197485 r197489  
     12016-03-02  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Add ability to generate a Heap Snapshot
     4        https://bugs.webkit.org/show_bug.cgi?id=154847
     5
     6        Reviewed by Mark Lam.
     7
     8        This adds HeapSnapshot, HeapSnapshotBuilder, and HeapProfiler.
     9
     10        HeapProfiler hangs off of the VM and holds the list of snapshots.
     11        I expect to add other HeapProfiling features, such as allocation
     12        tracking, to the profiler.
     13
     14        HeapSnapshot contains a collection of live cells and their identifiers.
     15        It can point to a previous HeapSnapshot, to ensure that a cell that
     16        already received an identifier maintains the same identifier across
     17        multiple snapshots. When a snapshotted cell gets garbage collected,
     18        the cell will be swept from the HeapSnapshot at the end of collection
     19        to ensure the list contains only live cells.
     20
     21        When building a HeapSnapshot nodes are added in increasing node
     22        identifier order. When done building, the list of nodes is complete
     23        and the snapshot is finalized. At this point the nodes are sorted
     24        by JSCell* address to allow for quick lookup of a JSCell*.
     25
     26        HeapSnapshotBuilder is where snapshotting begins. The builder
     27        will initiate a specialized heap snapshotting garbage collection.
     28        During this collection the builder will be notified of all marked
     29        (live) cells, and connections between cells, as seen by SlotVisitors.
     30        The builder can reference the previous, readonly, HeapSnapshots to
     31        avoid creating new nodes for cells that have already been snapshotted.
     32        When it is determined that we are visiting a live cell for the first
     33        time, we give the cell a unique identifier and add it to the the
     34        snapshot we are building.
     35
     36        Since edge data is costly, and of little long term utility, this
     37        data is only held by the builder for serialization, and not stored
     38        long term with the HeapSnapshot node data.
     39
     40        The goals of HeapSnapshotting at this time are:
     41        - minimal impact on performance when not profiling the heap
     42        - unique identifier for cells, so they may be identified across multiple snapshots
     43        - nodes and edges to be able to construct a graph of which nodes reference/retain which other nodes
     44        - node data - identifier, type (class name), size
     45        - edge data - from cell, to cell, type / data (to come in a follow-up patch)
     46
     47        * CMakeLists.txt:
     48        * JavaScriptCore.xcodeproj/project.pbxproj:
     49        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
     50        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
     51        Add new files to the build.
     52
     53        * heap/Heap.cpp:
     54        (JSC::Heap::isHeapSnapshotting):
     55        (JSC::RemoveDeadHeapSnapshotNodes::RemoveDeadHeapSnapshotNodes):
     56        (JSC::RemoveDeadHeapSnapshotNodes::operator()):
     57        (JSC::Heap::removeDeadHeapSnapshotNodes):
     58        (JSC::Heap::collectImpl):
     59        After every collection, sweep dead cells from in memory snapshots.
     60
     61        * runtime/VM.cpp:
     62        (JSC::VM::ensureHeapProfiler):
     63        * runtime/VM.h:
     64        (JSC::VM::heapProfiler):
     65        * heap/Heap.h:
     66        * heap/HeapProfiler.cpp: Added.
     67        (JSC::HeapProfiler::HeapProfiler):
     68        (JSC::HeapProfiler::~HeapProfiler):
     69        (JSC::HeapProfiler::mostRecentSnapshot):
     70        (JSC::HeapProfiler::appendSnapshot):
     71        (JSC::HeapProfiler::clearSnapshots):
     72        (JSC::HeapProfiler::setActiveSnapshotBuilder):
     73        * heap/HeapProfiler.h: Added.
     74        (JSC::HeapProfiler::vm):
     75        (JSC::HeapProfiler::activeSnapshotBuilder):
     76        VM and Heap can look at the profiler to determine if we are building a
     77        snapshot, or the "head" snapshot to use for sweeping.
     78
     79        * heap/HeapSnapshot.cpp: Added.
     80        (JSC::HeapSnapshot::HeapSnapshot):
     81        (JSC::HeapSnapshot::~HeapSnapshot):
     82        (JSC::HeapSnapshot::appendNode):
     83        Add a node to the unfinalized list of new cells.
     84
     85        (JSC::HeapSnapshot::sweepCell):
     86        (JSC::HeapSnapshot::shrinkToFit):
     87        Collect a list of cells for sweeping and then remove them all at once
     88        in shrinkToFit. This is done to avoid thrashing of individual removes
     89        that could cause many overlapping moves within the Vector.
     90
     91        (JSC::HeapSnapshot::finalize):
     92        Sort the list, and also cache the bounding start/stop identifiers.
     93        No other snapshot can contain an identifier in this range, so it will
     94        improve lookup of a node from an identifier.
     95
     96        (JSC::HeapSnapshot::nodeForCell):
     97        (JSC::HeapSnapshot::nodeForObjectIdentifier):
     98        Search helpers.
     99
     100        * heap/HeapSnapshotBuilder.h: Added.
     101        (JSC::HeapSnapshotNode::HeapSnapshotNode):
     102        (JSC::HeapSnapshotEdge::HeapSnapshotEdge):
     103        Node and Edge struct types the builder creates.
     104
     105        * heap/HeapSnapshotBuilder.cpp: Added.
     106        (JSC::HeapSnapshotBuilder::getNextObjectIdentifier):
     107        (JSC::HeapSnapshotBuilder::HeapSnapshotBuilder):
     108        (JSC::HeapSnapshotBuilder::~HeapSnapshotBuilder):
     109        (JSC::HeapSnapshotBuilder::buildSnapshot):
     110        (JSC::HeapSnapshotBuilder::appendNode):
     111        (JSC::HeapSnapshotBuilder::appendEdge):
     112        When building the snapshot, generating the next identifier, and
     113        appending to any of the lists must be guarded by a lock because
     114        SlotVisitors running in parallel may be accessing the builder.
     115
     116        (JSC::HeapSnapshotBuilder::hasExistingNodeForCell):
     117        Looking up if a node already exists in a previous snapshot can be
     118        done without a lock because at this point the data is readonly.
     119
     120        (JSC::edgeTypeToNumber):
     121        (JSC::edgeTypeToString):
     122        (JSC::HeapSnapshotBuilder::json):
     123        JSON serialization of a heap snapshot contains node and edge data.
     124
     125        * heap/SlotVisitor.h:
     126        * heap/SlotVisitor.cpp:
     127        (JSC::SlotVisitor::didStartMarking):
     128        (JSC::SlotVisitor::reset):
     129        Set/clear the active snapshot builder to know if this will be a
     130        snapshotting GC or not.
     131
     132        (JSC::SlotVisitor::append):
     133        (JSC::SlotVisitor::setMarkedAndAppendToMarkStack):
     134        Inform the builder of a new node or edge.
     135
     136        (JSC::SlotVisitor::visitChildren):
     137        Remember the current cell we are visiting so that if we need to
     138        inform the builder of edges we know the "from" cell.
     139
     140        * jsc.cpp:
     141        (SimpleObject::SimpleObject):
     142        (SimpleObject::create):
     143        (SimpleObject::finishCreation):
     144        (SimpleObject::visitChildren):
     145        (SimpleObject::createStructure):
     146        (SimpleObject::hiddenValue):
     147        (SimpleObject::setHiddenValue):
     148        Create a new class "SimpleObject" that can be used by heap snapshotting
     149        tests. It is easy to filter for this new class name and test internal
     150        edge relationships created by garbage collection visiting the cell.
     151
     152        (functionCreateSimpleObject):
     153        (functionGetHiddenValue):
     154        (functionSetHiddenValue):
     155        Expose methods to create and interact with a SimpleObject.
     156
     157        (functionGenerateHeapSnapshot):
     158        Expose methods to create a heap snapshot. This currently automatically
     159        turns the serialized string into a JSON object. That may change.
     160
     161        * tests/heapProfiler.yaml: Added.
     162        * tests/heapProfiler/basic-edges.js: Added.
     163        (excludeStructure):
     164        * tests/heapProfiler/basic-nodes.js: Added.
     165        (hasDifferentSizeNodes):
     166        (hasAllInternalNodes):
     167        Add tests for basic node and edge data.
     168
     169        * tests/heapProfiler/driver/driver.js: Added.
     170        (assert):
     171        (CheapHeapSnapshotNode):
     172        (CheapHeapSnapshotEdge):
     173        (CheapHeapSnapshotEdge.prototype.get from):
     174        (CheapHeapSnapshotEdge.prototype.get to):
     175        (CheapHeapSnapshot):
     176        (CheapHeapSnapshot.prototype.get nodes):
     177        (CheapHeapSnapshot.prototype.get edges):
     178        (CheapHeapSnapshot.prototype.nodeWithIdentifier):
     179        (CheapHeapSnapshot.prototype.nodesWithClassName):
     180        (CheapHeapSnapshot.prototype.classNameFromTableIndex):
     181        (CheapHeapSnapshot.prototype.edgeTypeFromTableIndex):
     182        (createCheapHeapSnapshot):
     183        (HeapSnapshotNode):
     184        (HeapSnapshotEdge):
     185        (HeapSnapshot):
     186        (HeapSnapshot.prototype.nodesWithClassName):
     187        (createHeapSnapshot):
     188        Add two HeapSnapshot representations.
     189        CheapHeapSnapshot creates two lists of node and edge data that
     190        lazily creates objects as needed.
     191        HeapSnapshot creates an object for each node and edge. This
     192        is wasteful but easier to use.
     193
    11942016-03-02  Filip Pizlo  <fpizlo@apple.com>
    2195
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj

    r197441 r197489  
    576576    <ClCompile Include="..\heap\Heap.cpp" />
    577577    <ClCompile Include="..\heap\HeapHelperPool.cpp" />
     578    <ClCompile Include="..\heap\HeapProfiler.cpp" />
     579    <ClCompile Include="..\heap\HeapSnapshot.cpp" />
     580    <ClCompile Include="..\heap\HeapSnapshotBuilder.cpp" />
    578581    <ClCompile Include="..\heap\HeapStatistics.cpp" />
    579582    <ClCompile Include="..\heap\HeapTimer.cpp" />
     
    13871390    <ClInclude Include="..\heap\HeapOperation.h" />
    13881391    <ClInclude Include="..\heap\HeapRootVisitor.h" />
     1392    <ClInclude Include="..\heap\HeapProfiler.h" />
     1393    <ClInclude Include="..\heap\HeapSnapshot.h" />
     1394    <ClInclude Include="..\heap\HeapSnapshotBuilder.h" />
    13891395    <ClInclude Include="..\heap\HeapStatistics.h" />
    13901396    <ClInclude Include="..\heap\HeapTimer.h" />
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters

    r197441 r197489  
    295295      <Filter>heap</Filter>
    296296    </ClCompile>
     297    <ClCompile Include="..\heap\HeapProfiler.cpp">
     298      <Filter>heap</Filter>
     299    </ClCompile>
     300    <ClCompile Include="..\heap\HeapSnapshot.cpp">
     301      <Filter>heap</Filter>
     302    </ClCompile>
     303    <ClCompile Include="..\heap\HeapSnapshotBuilder.cpp">
     304      <Filter>heap</Filter>
     305    </ClCompile>
    297306    <ClCompile Include="..\heap\HeapStatistics.cpp">
    298307      <Filter>heap</Filter>
     
    23672376    </ClInclude>
    23682377    <ClInclude Include="..\heap\HeapRootVisitor.h">
     2378      <Filter>heap</Filter>
     2379    </ClInclude>
     2380    <ClInclude Include="..\heap\HeapProfiler.h">
     2381      <Filter>heap</Filter>
     2382    </ClInclude>
     2383    <ClInclude Include="..\heap\HeapSnapshot.h">
     2384      <Filter>heap</Filter>
     2385    </ClInclude>
     2386    <ClInclude Include="..\heap\HeapSnapshotBuilder.h">
    23692387      <Filter>heap</Filter>
    23702388    </ClInclude>
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r197441 r197489  
    15491549                A514B2C2185A684400F3C7CB /* InjectedScriptBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A514B2C0185A684400F3C7CB /* InjectedScriptBase.cpp */; };
    15501550                A514B2C3185A684400F3C7CB /* InjectedScriptBase.h in Headers */ = {isa = PBXBuildFile; fileRef = A514B2C1185A684400F3C7CB /* InjectedScriptBase.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1551                A5311C361C77CEC500E6B1B6 /* HeapSnapshotBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = A5311C351C77CEAC00E6B1B6 /* HeapSnapshotBuilder.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1552                A5311C371C77CECA00E6B1B6 /* HeapSnapshotBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5311C341C77CEAC00E6B1B6 /* HeapSnapshotBuilder.cpp */; };
    15511553                A532438718568335002ED692 /* InspectorBackendDispatchers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A532438118568317002ED692 /* InspectorBackendDispatchers.cpp */; };
    15521554                A532438818568335002ED692 /* InspectorBackendDispatchers.h in Headers */ = {isa = PBXBuildFile; fileRef = A532438218568317002ED692 /* InspectorBackendDispatchers.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    15591561                A5339EC71BB399A90054F005 /* InspectorHeapAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5339EC41BB399900054F005 /* InspectorHeapAgent.cpp */; };
    15601562                A5339EC91BB4B4600054F005 /* HeapObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = A5339EC81BB4B4510054F005 /* HeapObserver.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1563                A5398FAB1C750DA40060A963 /* HeapProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = A5398FAA1C750D950060A963 /* HeapProfiler.h */; };
     1564                A5398FAC1C750DA60060A963 /* HeapProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5398FA91C750D950060A963 /* HeapProfiler.cpp */; };
    15611565                A53CE08518BC1A5600BEDF76 /* ConsolePrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A53CE08118BC1A5600BEDF76 /* ConsolePrototype.cpp */; };
    15621566                A53CE08618BC1A5600BEDF76 /* ConsolePrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = A53CE08218BC1A5600BEDF76 /* ConsolePrototype.h */; };
     
    15671571                A54982031891D0B00081E5B8 /* EventLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A54982011891D0B00081E5B8 /* EventLoop.cpp */; };
    15681572                A54982041891D0B00081E5B8 /* EventLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = A54982021891D0B00081E5B8 /* EventLoop.h */; };
     1573                A54C2AB01C6544EE00A18D78 /* HeapSnapshot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A54C2AAE1C6544D100A18D78 /* HeapSnapshot.cpp */; };
     1574                A54C2AB11C6544F200A18D78 /* HeapSnapshot.h in Headers */ = {isa = PBXBuildFile; fileRef = A54C2AAF1C6544D100A18D78 /* HeapSnapshot.h */; settings = {ATTRIBUTES = (Private, ); }; };
    15691575                A54CF2F5184EAB2400237F19 /* ScriptValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A54CF2F2184EAB2400237F19 /* ScriptValue.cpp */; };
    15701576                A54CF2F6184EAB2400237F19 /* ScriptValue.h in Headers */ = {isa = PBXBuildFile; fileRef = A54CF2F3184EAB2400237F19 /* ScriptValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    37443750                A514B2C0185A684400F3C7CB /* InjectedScriptBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedScriptBase.cpp; sourceTree = "<group>"; };
    37453751                A514B2C1185A684400F3C7CB /* InjectedScriptBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedScriptBase.h; sourceTree = "<group>"; };
     3752                A5311C341C77CEAC00E6B1B6 /* HeapSnapshotBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapSnapshotBuilder.cpp; sourceTree = "<group>"; };
     3753                A5311C351C77CEAC00E6B1B6 /* HeapSnapshotBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapSnapshotBuilder.h; sourceTree = "<group>"; };
    37463754                A532438118568317002ED692 /* InspectorBackendDispatchers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorBackendDispatchers.cpp; sourceTree = "<group>"; };
    37473755                A532438218568317002ED692 /* InspectorBackendDispatchers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InspectorBackendDispatchers.h; sourceTree = "<group>"; };
     
    37563764                A5339EC51BB399900054F005 /* InspectorHeapAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorHeapAgent.h; sourceTree = "<group>"; };
    37573765                A5339EC81BB4B4510054F005 /* HeapObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapObserver.h; sourceTree = "<group>"; };
     3766                A5398FA91C750D950060A963 /* HeapProfiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapProfiler.cpp; sourceTree = "<group>"; };
     3767                A5398FAA1C750D950060A963 /* HeapProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapProfiler.h; sourceTree = "<group>"; };
    37583768                A53CE08118BC1A5600BEDF76 /* ConsolePrototype.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConsolePrototype.cpp; sourceTree = "<group>"; };
    37593769                A53CE08218BC1A5600BEDF76 /* ConsolePrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConsolePrototype.h; sourceTree = "<group>"; };
     
    37643774                A54982011891D0B00081E5B8 /* EventLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventLoop.cpp; sourceTree = "<group>"; };
    37653775                A54982021891D0B00081E5B8 /* EventLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventLoop.h; sourceTree = "<group>"; };
     3776                A54C2AAE1C6544D100A18D78 /* HeapSnapshot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapSnapshot.cpp; sourceTree = "<group>"; };
     3777                A54C2AAF1C6544D100A18D78 /* HeapSnapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapSnapshot.h; sourceTree = "<group>"; };
    37663778                A54CF2F2184EAB2400237F19 /* ScriptValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScriptValue.cpp; sourceTree = "<group>"; };
    37673779                A54CF2F3184EAB2400237F19 /* ScriptValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScriptValue.h; sourceTree = "<group>"; };
     
    50945106                                A5339EC81BB4B4510054F005 /* HeapObserver.h */,
    50955107                                2A6F462517E959CE00C45C98 /* HeapOperation.h */,
     5108                                A5398FA91C750D950060A963 /* HeapProfiler.cpp */,
     5109                                A5398FAA1C750D950060A963 /* HeapProfiler.h */,
    50965110                                14F97446138C853E00DA1C67 /* HeapRootVisitor.h */,
     5111                                A54C2AAE1C6544D100A18D78 /* HeapSnapshot.cpp */,
     5112                                A54C2AAF1C6544D100A18D78 /* HeapSnapshot.h */,
     5113                                A5311C341C77CEAC00E6B1B6 /* HeapSnapshotBuilder.cpp */,
     5114                                A5311C351C77CEAC00E6B1B6 /* HeapSnapshotBuilder.h */,
    50975115                                C24D31E0161CD695002AA4DB /* HeapStatistics.cpp */,
    50985116                                C24D31E1161CD695002AA4DB /* HeapStatistics.h */,
     
    69196937                                996B73171BDA067F00331B84 /* ArrayConstructor.lut.h in Headers */,
    69206938                                0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */,
     6939                                A5311C361C77CEC500E6B1B6 /* HeapSnapshotBuilder.h in Headers */,
    69216940                                A7BDAEC917F4EA1400F6140C /* ArrayIteratorPrototype.h in Headers */,
    69226941                                996B73181BDA068000331B84 /* ArrayIteratorPrototype.lut.h in Headers */,
     
    70917110                                BC1166020E1997B4008066DD /* DateInstance.h in Headers */,
    70927111                                14A1563210966365006FA260 /* DateInstanceCache.h in Headers */,
     7112                                A54C2AB11C6544F200A18D78 /* HeapSnapshot.h in Headers */,
    70937113                                BCD2034C0E17135E002C7E82 /* DatePrototype.h in Headers */,
    70947114                                BCD203E80E1718F4002C7E82 /* DatePrototype.lut.h in Headers */,
     
    75037523                                A1587D701B4DC14100D69849 /* IntlDateTimeFormatConstructor.h in Headers */,
    75047524                                A1587D751B4DC1C600D69849 /* IntlDateTimeFormatConstructor.lut.h in Headers */,
     7525                                A5398FAB1C750DA40060A963 /* HeapProfiler.h in Headers */,
    75057526                                A1587D721B4DC14100D69849 /* IntlDateTimeFormatPrototype.h in Headers */,
    75067527                                A1587D761B4DC1C600D69849 /* IntlDateTimeFormatPrototype.lut.h in Headers */,
     
    88238844                                0F63944015C75F1D006A597C /* DFGTypeCheckHoistingPhase.cpp in Sources */,
    88248845                                0FBE0F7616C1DB0F0082C5E8 /* DFGUnificationPhase.cpp in Sources */,
     8846                                A5398FAC1C750DA60060A963 /* HeapProfiler.cpp in Sources */,
    88258847                                0F34B14916D42010001CDA5A /* DFGUseKind.cpp in Sources */,
    88268848                                0F3B3A2B15475000003ED0FF /* DFGValidate.cpp in Sources */,
     
    89969018                                0F2B66E617B6B5AB00A7AE3F /* JSArrayBufferPrototype.cpp in Sources */,
    89979019                                0F2B66E817B6B5AB00A7AE3F /* JSArrayBufferView.cpp in Sources */,
     9020                                A5311C371C77CECA00E6B1B6 /* HeapSnapshotBuilder.cpp in Sources */,
    89989021                                A7BDAECA17F4EA1400F6140C /* JSArrayIterator.cpp in Sources */,
    89999022                                1421359B0A677F4F00A8195E /* JSBase.cpp in Sources */,
     
    92489271                                7E4EE70F0EBB7A5B005934AA /* StructureChain.cpp in Sources */,
    92499272                                2AF7382C18BBBF92008A5A37 /* StructureIDTable.cpp in Sources */,
     9273                                A54C2AB01C6544EE00A18D78 /* HeapSnapshot.cpp in Sources */,
    92509274                                C2F0F2D116BAEEE900187C19 /* StructureRareData.cpp in Sources */,
    92519275                                0FB438A319270B1D00E1FBC9 /* StructureSet.cpp in Sources */,
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r195905 r197489  
    3434#include "HeapHelperPool.h"
    3535#include "HeapIterationScope.h"
     36#include "HeapProfiler.h"
    3637#include "HeapRootVisitor.h"
     38#include "HeapSnapshot.h"
    3739#include "HeapStatistics.h"
    3840#include "HeapVerifier.h"
     
    759761}
    760762
     763bool Heap::isHeapSnapshotting() const
     764{
     765    HeapProfiler* heapProfiler = m_vm->heapProfiler();
     766    if (UNLIKELY(heapProfiler))
     767        return heapProfiler->activeSnapshotBuilder();
     768    return false;
     769}
     770
     771struct RemoveDeadHeapSnapshotNodes : MarkedBlock::CountFunctor {
     772    RemoveDeadHeapSnapshotNodes(HeapSnapshot& snapshot)
     773        : m_snapshot(snapshot)
     774    {
     775    }
     776
     777    IterationStatus operator()(JSCell* cell)
     778    {
     779        m_snapshot.sweepCell(cell);
     780        return IterationStatus::Continue;
     781    }
     782
     783    HeapSnapshot& m_snapshot;
     784};
     785
     786void Heap::removeDeadHeapSnapshotNodes()
     787{
     788    GCPHASE(RemoveDeadHeapSnapshotNodes);
     789    HeapProfiler* heapProfiler = m_vm->heapProfiler();
     790    if (UNLIKELY(heapProfiler)) {
     791        if (HeapSnapshot* snapshot = heapProfiler->mostRecentSnapshot()) {
     792            HeapIterationScope heapIterationScope(*this);
     793            RemoveDeadHeapSnapshotNodes functor(*snapshot);
     794            m_objectSpace.forEachDeadCell(heapIterationScope, functor);
     795            snapshot->shrinkToFit();
     796        }
     797    }
     798}
     799
    761800void Heap::visitProtectedObjects(HeapRootVisitor& heapRootVisitor)
    762801{
     
    11251164    deleteUnmarkedCompiledCode();
    11261165    deleteSourceProviderCaches();
     1166    removeDeadHeapSnapshotNodes();
    11271167    notifyIncrementalSweeper();
    11281168    writeBarrierCurrentlyExecutingCodeBlocks();
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r195644 r197489  
    164164    bool isSafeToCollect() const { return m_isSafeToCollect; }
    165165
     166    JS_EXPORT_PRIVATE bool isHeapSnapshotting() const;
     167
    166168    JS_EXPORT_PRIVATE void collectAllGarbageIfNotDoneRecently();
    167169    void collectAllGarbage() { collectAndSweep(FullCollection); }
     
    328330    void snapshotMarkedSpace();
    329331    void deleteSourceProviderCaches();
     332    void removeDeadHeapSnapshotNodes();
    330333    void notifyIncrementalSweeper();
    331334    void writeBarrierCurrentlyExecutingCodeBlocks();
  • trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp

    r190569 r197489  
    3232#include "CopiedSpace.h"
    3333#include "CopiedSpaceInlines.h"
     34#include "HeapProfiler.h"
     35#include "HeapSnapshotBuilder.h"
    3436#include "JSArray.h"
    3537#include "JSDestructibleObject.h"
     
    9597    if (heap()->operationInProgress() == FullCollection)
    9698        ASSERT(m_opaqueRoots.isEmpty()); // Should have merged by now.
     99
     100    if (HeapProfiler* heapProfiler = vm().heapProfiler())
     101        m_heapSnapshotBuilder = heapProfiler->activeSnapshotBuilder();
    97102}
    98103
     
    102107    m_bytesCopied = 0;
    103108    m_visitCount = 0;
     109    m_heapSnapshotBuilder = nullptr;
     110    ASSERT(!m_currentCell);
    104111    ASSERT(m_stack.isEmpty());
    105112}
     
    122129    if (!value || !value.isCell())
    123130        return;
     131
     132    if (m_heapSnapshotBuilder)
     133        m_heapSnapshotBuilder->appendEdge(m_currentCell, value.asCell());
     134
    124135    setMarkedAndAppendToMarkStack(value.asCell());
    125136}
     
    156167    m_bytesVisited += MarkedBlock::blockFor(cell)->cellSize();
    157168    m_stack.append(cell);
    158 }
     169
     170    if (m_heapSnapshotBuilder)
     171        m_heapSnapshotBuilder->appendNode(cell);
     172}
     173
     174class SetCurrentCellScope {
     175public:
     176    SetCurrentCellScope(SlotVisitor& visitor, const JSCell* cell)
     177        : m_visitor(visitor)
     178    {
     179        ASSERT(!m_visitor.m_currentCell);
     180        m_visitor.m_currentCell = const_cast<JSCell*>(cell);
     181    }
     182
     183    ~SetCurrentCellScope()
     184    {
     185        ASSERT(m_visitor.m_currentCell);
     186        m_visitor.m_currentCell = nullptr;
     187    }
     188
     189private:
     190    SlotVisitor& m_visitor;
     191};
     192
    159193
    160194ALWAYS_INLINE void SlotVisitor::visitChildren(const JSCell* cell)
    161195{
    162196    ASSERT(Heap::isMarked(cell));
     197
     198    SetCurrentCellScope currentCellScope(*this, cell);
    163199
    164200    m_currentObjectCellStateBeforeVisiting = cell->cellState();
  • trunk/Source/JavaScriptCore/heap/SlotVisitor.h

    r196369 r197489  
    3838class GCThreadSharedData;
    3939class Heap;
     40class HeapSnapshotBuilder;
    4041template<typename T> class JITWriteBarrier;
    4142class UnconditionalFinalizer;
     
    4849    WTF_MAKE_FAST_ALLOCATED;
    4950
     51    friend class SetCurrentCellScope;
    5052    friend class HeapRootVisitor; // Allowed to mark a JSValue* or JSCell** directly.
    5153    friend class Heap;
     
    112114    void dump(PrintStream&) const;
    113115
     116    bool isBuildingHeapSnapshot() const { return !!m_heapSnapshotBuilder; }
     117
    114118private:
    115119    friend class ParallelModeEnabler;
     
    137141   
    138142    Heap& m_heap;
     143
     144    HeapSnapshotBuilder* m_heapSnapshotBuilder { nullptr };
     145    JSCell* m_currentCell { nullptr };
    139146
    140147    CellState m_currentObjectCellStateBeforeVisiting { CellState::NewWhite };
  • trunk/Source/JavaScriptCore/jsc.cpp

    r197261 r197489  
    3333#include "Exception.h"
    3434#include "ExceptionHelpers.h"
     35#include "HeapProfiler.h"
     36#include "HeapSnapshotBuilder.h"
    3537#include "HeapStatistics.h"
    3638#include "InitializeThreading.h"
     
    466468};
    467469
     470class SimpleObject : public JSNonFinalObject {
     471public:
     472    SimpleObject(VM& vm, Structure* structure)
     473        : Base(vm, structure)
     474    {
     475    }
     476
     477    typedef JSNonFinalObject Base;
     478    static const bool needsDestruction = false;
     479
     480    static SimpleObject* create(VM& vm, JSGlobalObject* globalObject)
     481    {
     482        Structure* structure = createStructure(vm, globalObject, jsNull());
     483        SimpleObject* simpleObject = new (NotNull, allocateCell<SimpleObject>(vm.heap, sizeof(SimpleObject))) SimpleObject(vm, structure);
     484        simpleObject->finishCreation(vm);
     485        return simpleObject;
     486    }
     487
     488    void finishCreation(VM& vm)
     489    {
     490        Base::finishCreation(vm);
     491    }
     492
     493    static void visitChildren(JSCell* cell, SlotVisitor& visitor)
     494    {
     495        SimpleObject* thisObject = jsCast<SimpleObject*>(cell);
     496        ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     497        Base::visitChildren(thisObject, visitor);
     498        visitor.append(&thisObject->m_hiddenValue);
     499    }
     500
     501    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     502    {
     503        return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
     504    }
     505
     506    JSValue hiddenValue()
     507    {
     508        return m_hiddenValue.get();
     509    }
     510
     511    void setHiddenValue(VM& vm, JSValue value)
     512    {
     513        ASSERT(value.isCell());
     514        m_hiddenValue.set(vm, this, value);
     515    }
     516
     517    DECLARE_INFO;
     518
     519private:
     520    WriteBarrier<Unknown> m_hiddenValue;
     521};
     522
     523
    468524const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, CREATE_METHOD_TABLE(Element) };
    469525const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, CREATE_METHOD_TABLE(Masquerader) };
     
    472528const ClassInfo CustomGetter::s_info = { "CustomGetter", &Base::s_info, 0, CREATE_METHOD_TABLE(CustomGetter) };
    473529const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, CREATE_METHOD_TABLE(RuntimeArray) };
     530const ClassInfo SimpleObject::s_info = { "SimpleObject", &Base::s_info, 0, CREATE_METHOD_TABLE(SimpleObject) };
    474531
    475532ElementHandleOwner* Element::handleOwner()
     
    502559static EncodedJSValue JSC_HOST_CALL functionCreateElement(ExecState*);
    503560static EncodedJSValue JSC_HOST_CALL functionGetElement(ExecState*);
     561static EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState*);
     562static EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState*);
     563static EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState*);
    504564static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
    505565static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
     
    556616static EncodedJSValue JSC_HOST_CALL functionCheckModuleSyntax(ExecState*);
    557617static EncodedJSValue JSC_HOST_CALL functionPlatformSupportsSamplingProfiler(ExecState*);
     618static EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState*);
    558619#if ENABLE(SAMPLING_PROFILER)
    559620static EncodedJSValue JSC_HOST_CALL functionStartSamplingProfiler(ExecState*);
     
    709770        addFunction(vm, "setElementRoot", functionSetElementRoot, 2);
    710771       
     772        addConstructableFunction(vm, "SimpleObject", functionCreateSimpleObject, 0);
     773        addFunction(vm, "getHiddenValue", functionGetHiddenValue, 1);
     774        addFunction(vm, "setHiddenValue", functionSetHiddenValue, 2);
     775       
    711776        putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "DFGTrue"), 0, functionFalse1, DFGTrueIntrinsic, DontEnum);
    712777        putDirectNativeFunction(vm, this, Identifier::fromString(&vm, "OSRExit"), 0, functionUndefined1, OSRExitIntrinsic, DontEnum);
     
    748813
    749814        addFunction(vm, "platformSupportsSamplingProfiler", functionPlatformSupportsSamplingProfiler, 0);
     815        addFunction(vm, "generateHeapSnapshot", functionGenerateHeapSnapshot, 0);
    750816#if ENABLE(SAMPLING_PROFILER)
    751817        addFunction(vm, "startSamplingProfiler", functionStartSamplingProfiler, 0);
     
    11341200}
    11351201
     1202EncodedJSValue JSC_HOST_CALL functionCreateSimpleObject(ExecState* exec)
     1203{
     1204    JSLockHolder lock(exec);
     1205    return JSValue::encode(SimpleObject::create(exec->vm(), exec->lexicalGlobalObject()));
     1206}
     1207
     1208EncodedJSValue JSC_HOST_CALL functionGetHiddenValue(ExecState* exec)
     1209{
     1210    JSLockHolder lock(exec);
     1211    SimpleObject* simpleObject = jsCast<SimpleObject*>(exec->argument(0).asCell());
     1212    return JSValue::encode(simpleObject->hiddenValue());
     1213}
     1214
     1215EncodedJSValue JSC_HOST_CALL functionSetHiddenValue(ExecState* exec)
     1216{
     1217    JSLockHolder lock(exec);
     1218    SimpleObject* simpleObject = jsCast<SimpleObject*>(exec->argument(0).asCell());
     1219    JSValue value = exec->argument(1);
     1220    simpleObject->setHiddenValue(exec->vm(), value);
     1221    return JSValue::encode(jsUndefined());
     1222}
     1223
    11361224EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState* exec)
    11371225{
     
    16451733    return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
    16461734#endif
     1735}
     1736
     1737EncodedJSValue JSC_HOST_CALL functionGenerateHeapSnapshot(ExecState* exec)
     1738{
     1739    JSLockHolder lock(exec);
     1740
     1741    HeapSnapshotBuilder snapshotBuilder(exec->vm().ensureHeapProfiler());
     1742    snapshotBuilder.buildSnapshot();
     1743
     1744    String jsonString = snapshotBuilder.json();
     1745    EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
     1746    RELEASE_ASSERT(!exec->hadException());
     1747    return result;
    16471748}
    16481749
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r196308 r197489  
    5151#include "Heap.h"
    5252#include "HeapIterationScope.h"
     53#include "HeapProfiler.h"
    5354#include "HostCallReturnValue.h"
    5455#include "Identifier.h"
     
    444445}
    445446
     447HeapProfiler& VM::ensureHeapProfiler()
     448{
     449    if (!m_heapProfiler)
     450        m_heapProfiler = std::make_unique<HeapProfiler>(*this);
     451    return *m_heapProfiler;
     452}
     453
    446454#if ENABLE(SAMPLING_PROFILER)
    447455void VM::ensureSamplingProfiler(RefPtr<Stopwatch>&& stopwatch)
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r196308 r197489  
    8888class TypeProfiler;
    8989class TypeProfilerLog;
     90class HeapProfiler;
    9091class Identifier;
    9192class Interpreter;
     
    249250    JS_EXPORT_PRIVATE Watchdog& ensureWatchdog();
    250251    JS_EXPORT_PRIVATE Watchdog* watchdog() { return m_watchdog.get(); }
     252
     253    JS_EXPORT_PRIVATE HeapProfiler* heapProfiler() const { return m_heapProfiler.get(); }
     254    JS_EXPORT_PRIVATE HeapProfiler& ensureHeapProfiler();
    251255
    252256#if ENABLE(SAMPLING_PROFILER)
     
    673677    MallocPtr<EncodedJSValue> m_exceptionFuzzBuffer;
    674678    RefPtr<Watchdog> m_watchdog;
     679    std::unique_ptr<HeapProfiler> m_heapProfiler;
    675680#if ENABLE(SAMPLING_PROFILER)
    676681    RefPtr<SamplingProfiler> m_samplingProfiler;
Note: See TracChangeset for help on using the changeset viewer.