// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. var TYPE_HEIGHT = 25; var DEFAULT_NODE_BUBBLE_RADIUS = 12; var NODE_INPUT_WIDTH = 50; var MINIMUM_NODE_INPUT_APPROACH = 15 + 2 * DEFAULT_NODE_BUBBLE_RADIUS; var MINIMUM_NODE_OUTPUT_APPROACH = 15; function isNodeInitiallyVisible(node) { return node.cfg; } var Node = { isControl: function() { return this.control; }, isInput: function() { return this.opcode == 'Parameter' || this.opcode.endsWith('Constant'); }, isLive: function() { return this.live !== false; }, isJavaScript: function() { return this.opcode.startsWith('JS'); }, isSimplified: function() { if (this.isJavaScript) return false; return this.opcode.endsWith('Phi') || this.opcode.startsWith('Boolean') || this.opcode.startsWith('Number') || this.opcode.startsWith('String') || this.opcode.startsWith('Change') || this.opcode.startsWith('Object') || this.opcode.startsWith('Reference') || this.opcode.startsWith('Any') || this.opcode.endsWith('ToNumber') || (this.opcode == 'AnyToBoolean') || (this.opcode.startsWith('Load') && this.opcode.length > 4) || (this.opcode.startsWith('Store') && this.opcode.length > 5); }, isMachine: function() { return !(this.isControl() || this.isInput() || this.isJavaScript() || this.isSimplified()); }, getTotalNodeWidth: function() { var inputWidth = this.inputs.length * NODE_INPUT_WIDTH; return Math.max(inputWidth, this.width); }, getTitle: function() { var propsString; if (this.properties === undefined) { propsString = ""; } else if (this.properties === "") { propsString = "no properties"; } else { propsString = "[" + this.properties + "]"; } return this.title + "\n" + propsString + "\n" + this.opinfo; }, getDisplayLabel: function() { var result = this.id + ":" + this.label; if (result.length > 40) { return this.id + ":" + this.opcode; } else { return result; } }, getType: function() { return this.type; }, getDisplayType: function() { var type_string = this.type; if (type_string == undefined) return ""; if (type_string.length > 24) { type_string = type_string.substr(0, 25) + "..."; } return type_string; }, deepestInputRank: function() { var deepestRank = 0; this.inputs.forEach(function(e) { if (e.isVisible() && !e.isBackEdge()) { if (e.source.rank > deepestRank) { deepestRank = e.source.rank; } } }); return deepestRank; }, areAnyOutputsVisible: function() { var visibleCount = 0; this.outputs.forEach(function(e) { if (e.isVisible()) ++visibleCount; }); if (this.outputs.length == visibleCount) return 2; if (visibleCount != 0) return 1; return 0; }, setOutputVisibility: function(v) { var result = false; this.outputs.forEach(function(e) { e.visible = v; if (v) { if (!e.target.visible) { e.target.visible = true; result = true; } } }); return result; }, setInputVisibility: function(i, v) { var edge = this.inputs[i]; edge.visible = v; if (v) { if (!edge.source.visible) { edge.source.visible = true; return true; } } return false; }, getInputApproach: function(index) { return this.y - MINIMUM_NODE_INPUT_APPROACH - (index % 4) * MINIMUM_EDGE_SEPARATION - DEFAULT_NODE_BUBBLE_RADIUS }, getOutputApproach: function(graph, index) { return this.y + this.outputApproach + graph.getNodeHeight(this) + + DEFAULT_NODE_BUBBLE_RADIUS; }, getInputX: function(index) { var result = this.getTotalNodeWidth() - (NODE_INPUT_WIDTH / 2) + (index - this.inputs.length + 1) * NODE_INPUT_WIDTH; return result; }, getOutputX: function() { return this.getTotalNodeWidth() - (NODE_INPUT_WIDTH / 2); }, getFunctionRelativeSourcePosition: function(graph) { return this.pos - graph.sourcePosition; }, hasBackEdges: function() { return (this.opcode == "Loop") || ((this.opcode == "Phi" || this.opcode == "EffectPhi") && this.inputs[this.inputs.length - 1].source.opcode == "Loop"); } };