prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
208 lines (159 loc) • 5.39 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ResidualHeapGraphGenerator = void 0;
var _invariant = _interopRequireDefault(require("../invariant.js"));
var _index = require("../values/index.js");
var _HeapInspector = require("../utils/HeapInspector.js");
var _ResidualHeapVisitor = require("./ResidualHeapVisitor.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
/* strict-local */
/**
* Generate a visualizable objects graph for Prepack heap.
*/
class ResidualHeapGraphGenerator extends _ResidualHeapVisitor.ResidualHeapVisitor {
constructor(realm, logger, modules, additionalFunctionValuesAndEffects, valueIdentifiers, valueToEdgeRecord) {
super(realm, logger, modules, additionalFunctionValuesAndEffects);
this._valueToEdgeRecord = valueToEdgeRecord;
this._valueIdentifiers = valueIdentifiers;
this._visitedValues = new Set();
this._valueIds = new Map();
this._idSeed = 0;
this._path = [];
this._edges = [];
}
// Override.
preProcessValue(val) {
if (this._shouldIgnore(val)) {
return true;
}
this._updateEdge(val);
if (this._visitedValues.has(val)) {
return false; // Already visited.
}
this._visitedValues.add(val);
return true;
} // Override.
postProcessValue(val) {
if (this._shouldIgnore(val)) {
return;
}
(0, _invariant.default)(this._path.length > 0);
this._path.pop();
}
_getValueId(val) {
let id = this._valueIds.get(val);
if (id === undefined) {
this._valueIds.set(val, ++this._idSeed);
id = this._idSeed;
}
return id;
}
_shouldIgnore(val) {
return val instanceof _index.EmptyValue || val.isIntrinsic() || _HeapInspector.HeapInspector.isLeaf(val);
}
_updateEdge(val) {
if (this._path.length > 0) {
const parent = this._path[this._path.length - 1];
this._edges.push({
fromId: this._getValueId(parent),
toId: this._getValueId(val)
});
}
this._path.push(val);
}
_getValueLabel(val) {
// TODO: does not use ref count yet, figure out how to best visualize it later.
const serializedId = this._valueIdentifiers.getIdentifier(val);
(0, _invariant.default)(serializedId);
return val.__originalName !== undefined ? `${serializedId.name}(${val.__originalName})` : serializedId.name;
}
_generateDotGraphData(nodes, edges) {
let content = "digraph{\n";
for (const val of nodes) {
const nodeId = this._getValueId(val);
content += ` node${nodeId} [shape=${this._getValueShape(val)} label=${this._getValueLabel(val)}];\n`;
}
for (const edge of edges) {
content += ` node${edge.fromId} -> node${edge.toId};\n`;
}
content += "}";
return content;
}
_generateVisJSGraphData(nodes, edges) {
let nodesData = [];
let edgesData = [];
for (let node of nodes) {
const nodeId = this._getValueId(node);
let nodeData = {
id: `${nodeId}`,
label: this._getValueLabel(node),
shape: this._getValueShape(node),
color: this._getValueColor(node)
};
nodesData.push(nodeData);
}
for (let [index, edge] of edges.entries()) {
let edgeData = {
id: index,
from: `${edge.fromId}`,
to: `${edge.toId}`,
arrows: "to"
};
edgesData.push(edgeData);
}
let graphData = {
nodes: nodesData,
edges: edgesData
};
return JSON.stringify(graphData);
} // TODO: find a way to comment the meaning of shape => value mapping in final graph language.
_getValueShape(val) {
let shape = null;
if (val instanceof _index.FunctionValue) {
shape = "circle";
} else if (val instanceof _index.AbstractValue) {
shape = "diamond";
} else if (val instanceof _index.ProxyValue) {
shape = "triangle";
} else if (val instanceof _index.SymbolValue) {
shape = "star";
} else if (val instanceof _index.ObjectValue) {
shape = "box";
} else {
shape = "ellipse";
}
return shape;
} // TODO: find a way to comment the meaning of shape => value mapping in final graph language.
_getValueColor(val) {
let shape = null;
if (val instanceof _index.FunctionValue) {
shape = "red";
} else if (val instanceof _index.AbstractValue) {
shape = "green";
} else if (val instanceof _index.ProxyValue) {
shape = "orange";
} else if (val instanceof _index.SymbolValue) {
shape = "yellow";
} else if (val instanceof _index.ObjectValue) {
shape = "#3BB9FF"; // light blue
} else {
shape = "grey";
}
return shape;
}
generateResult(heapGraphFormat) {
return heapGraphFormat === "DotLanguage" ? this._generateDotGraphData(this._visitedValues, this._edges) : this._generateVisJSGraphData(this._visitedValues, this._edges);
}
}
exports.ResidualHeapGraphGenerator = ResidualHeapGraphGenerator;
//# sourceMappingURL=ResidualHeapGraphGenerator.js.map