"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ResidualHeapGraphGenerator = undefined; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _invariant = require("../invariant.js"); var _invariant2 = _interopRequireDefault(_invariant); var _index = require("../values/index.js"); var _ResidualHeapInspector = require("./ResidualHeapInspector.js"); var _ResidualHeapVisitor2 = require("./ResidualHeapVisitor.js"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** * 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. */ /** * Generate a visualizable objects graph for Prepack heap. */ var ResidualHeapGraphGenerator = exports.ResidualHeapGraphGenerator = function (_ResidualHeapVisitor) { _inherits(ResidualHeapGraphGenerator, _ResidualHeapVisitor); function ResidualHeapGraphGenerator(realm, logger, modules, additionalFunctionValuesAndEffects, valueIdentifiers, valueToEdgeRecord) { _classCallCheck(this, ResidualHeapGraphGenerator); var _this = _possibleConstructorReturn(this, (ResidualHeapGraphGenerator.__proto__ || Object.getPrototypeOf(ResidualHeapGraphGenerator)).call(this, 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 = []; return _this; } // Contains the path of nodes from root to current visiting node. _createClass(ResidualHeapGraphGenerator, [{ key: "preProcessValue", // Override. value: function 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. }, { key: "postProcessValue", value: function postProcessValue(val) { if (this._shouldIgnore(val)) { return; } (0, _invariant2.default)(this._path.length > 0); this._path.pop(); } }, { key: "_getValueId", value: function _getValueId(val) { var id = this._valueIds.get(val); if (!id) { this._valueIds.set(val, ++this._idSeed); id = this._idSeed; } return id; } }, { key: "_shouldIgnore", value: function _shouldIgnore(val) { return val instanceof _index.EmptyValue || val.isIntrinsic() || _ResidualHeapInspector.ResidualHeapInspector.isLeaf(val); } }, { key: "_updateEdge", value: function _updateEdge(val) { if (this._path.length > 0) { var parent = this._path[this._path.length - 1]; this._edges.push({ fromId: this._getValueId(parent), toId: this._getValueId(val) }); } this._path.push(val); } }, { key: "_getValueLabel", value: function _getValueLabel(val) { // TODO: does not use ref count yet, figure out how to best visualize it later. var serializedId = this._valueIdentifiers.getIdentifier(val); (0, _invariant2.default)(serializedId); return val.__originalName ? serializedId.name + "(" + val.__originalName + ")" : serializedId.name; } }, { key: "_generateDotGraphData", value: function _generateDotGraphData(nodes, edges) { var content = "digraph{\n"; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = nodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var val = _step.value; var nodeId = this._getValueId(val); content += " node" + nodeId + " [shape=" + this._getValueShape(val) + " label=" + this._getValueLabel(val) + "];\n"; } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = edges[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var edge = _step2.value; content += " node" + edge.fromId + " -> node" + edge.toId + ";\n"; } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } content += "}"; return content; } }, { key: "_generateVisJSGraphData", value: function _generateVisJSGraphData(nodes, edges) { var nodesData = []; var edgesData = []; var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = nodes[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var node = _step3.value; var nodeId = this._getValueId(node); var nodeData = { id: "" + nodeId, label: this._getValueLabel(node), shape: this._getValueShape(node), color: this._getValueColor(node) }; nodesData.push(nodeData); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = edges.entries()[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var _ref = _step4.value; var _ref2 = _slicedToArray(_ref, 2); var index = _ref2[0]; var edge = _ref2[1]; var edgeData = { id: index, from: "" + edge.fromId, to: "" + edge.toId, arrows: "to" }; edgesData.push(edgeData); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } var 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. }, { key: "_getValueShape", value: function _getValueShape(val) { var 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. }, { key: "_getValueColor", value: function _getValueColor(val) { var 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; } }, { key: "generateResult", value: function generateResult(heapGraphFormat) { return heapGraphFormat === "DotLanguage" ? this._generateDotGraphData(this._visitedValues, this._edges) : this._generateVisJSGraphData(this._visitedValues, this._edges); } }]); return ResidualHeapGraphGenerator; }(_ResidualHeapVisitor2.ResidualHeapVisitor); //# sourceMappingURL=ResidualHeapGraphGenerator.js.map