blob: 0ed85d19f48e74a38b466917a2da530da4c13cb2 [file] [log] [blame]
/*
* 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.
*/
#pragma once
#include <functional>
#include <wtf/Lock.h>
#include <wtf/Vector.h>
#include <wtf/text/UniquedStringImpl.h>
#include <wtf/text/WTFString.h>
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: <https://webkit.org/b/154934> 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();
static void resetNextAvailableObjectIdentifier();
// 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<bool (const HeapSnapshotNode&)> 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<HeapSnapshot> m_snapshot;
Lock m_buildingEdgeMutex;
Vector<HeapSnapshotEdge> m_edges;
};
} // namespace JSC