/* * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HeapSnapshotBuilder_h #define HeapSnapshotBuilder_h #include #include #include #include #include namespace JSC { class HeapProfiler; class HeapSnapshot; class JSCell; struct HeapSnapshotNode { HeapSnapshotNode(JSCell* cell, unsigned identifier) : cell(cell) , identifier(identifier) { } JSCell* cell; unsigned identifier; }; enum class EdgeType : uint8_t { Internal, // Normal strong reference. No name. Property, // Named property. In `object.property` the name is "property" Index, // Indexed property. In `array[0]` name is index "0". Variable, // Variable held by a scope. In `let x, f=() => x++` name is "x" in f's captured scope. // FIXME: Heap Snapshot should include "Weak" edges }; struct HeapSnapshotEdge { HeapSnapshotEdge(JSCell* fromCell, JSCell* toCell) : type(EdgeType::Internal) { from.cell = fromCell; to.cell = toCell; } HeapSnapshotEdge(JSCell* fromCell, JSCell* toCell, EdgeType type, UniquedStringImpl* name) : type(type) { ASSERT(type == EdgeType::Property || type == EdgeType::Variable); from.cell = fromCell; to.cell = toCell; u.name = name; } HeapSnapshotEdge(JSCell* fromCell, JSCell* toCell, uint32_t index) : type(EdgeType::Index) { from.cell = fromCell; to.cell = toCell; u.index = index; } union { JSCell *cell; unsigned identifier; } from; union { JSCell *cell; unsigned identifier; } to; union { UniquedStringImpl* name; uint32_t index; } u; EdgeType type; }; class JS_EXPORT_PRIVATE HeapSnapshotBuilder { WTF_MAKE_FAST_ALLOCATED; public: HeapSnapshotBuilder(HeapProfiler&); ~HeapSnapshotBuilder(); static unsigned nextAvailableObjectIdentifier; static unsigned getNextObjectIdentifier(); // Performs a garbage collection that builds a snapshot of all live cells. void buildSnapshot(); // A marked cell. void appendNode(JSCell*); // A reference from one cell to another. void appendEdge(JSCell* from, JSCell* to); 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); String json(); String json(std::function allowNodeCallback); private: // Finalized snapshots are not modified during building. So searching them // for an existing node can be done concurrently without a lock. bool hasExistingNodeForCell(JSCell*); HeapProfiler& m_profiler; // SlotVisitors run in parallel. Lock m_buildingNodeMutex; std::unique_ptr m_snapshot; Lock m_buildingEdgeMutex; Vector m_edges; }; } // namespace JSC #endif // HeapSnapshotBuilder_h