@eagleoutice/flowr 2.9.7 → 2.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -21
- package/abstract-interpretation/absint-visitor.d.ts +5 -4
- package/abstract-interpretation/absint-visitor.js +12 -11
- package/control-flow/basic-cfg-guided-visitor.d.ts +3 -3
- package/control-flow/basic-cfg-guided-visitor.js +7 -6
- package/control-flow/cfg-dead-code.js +12 -9
- package/control-flow/cfg-properties.d.ts +2 -2
- package/control-flow/cfg-properties.js +3 -2
- package/control-flow/cfg-to-basic-blocks.js +9 -12
- package/control-flow/control-flow-graph.d.ts +382 -78
- package/control-flow/control-flow-graph.js +591 -106
- package/control-flow/dfg-cfg-guided-visitor.d.ts +4 -4
- package/control-flow/dfg-cfg-guided-visitor.js +3 -3
- package/control-flow/diff-cfg.js +35 -29
- package/control-flow/extract-cfg.d.ts +3 -3
- package/control-flow/extract-cfg.js +145 -125
- package/control-flow/happens-before.js +2 -1
- package/control-flow/semantic-cfg-guided-visitor.js +2 -1
- package/control-flow/simple-visitor.js +8 -6
- package/control-flow/syntax-cfg-guided-visitor.js +2 -1
- package/control-flow/useless-loop.js +2 -1
- package/documentation/wiki-cfg.js +21 -9
- package/documentation/wiki-mk/doc-maker.js +1 -1
- package/package.json +1 -1
- package/project/context/flowr-file.d.ts +5 -0
- package/project/context/flowr-file.js +7 -0
- package/project/plugins/file-plugins/files/flowr-description-file.d.ts +1 -0
- package/project/plugins/file-plugins/files/flowr-description-file.js +5 -0
- package/project/plugins/file-plugins/files/flowr-namespace-file.d.ts +4 -0
- package/project/plugins/file-plugins/files/flowr-namespace-file.js +8 -0
- package/project/plugins/file-plugins/files/flowr-news-file.d.ts +4 -0
- package/project/plugins/file-plugins/files/flowr-news-file.js +8 -0
- package/queries/catalog/control-flow-query/control-flow-query-format.js +1 -1
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.d.ts +2 -1
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +19 -19
- package/search/search-executor/search-generators.js +2 -2
- package/util/assert.d.ts +3 -3
- package/util/mermaid/cfg.d.ts +1 -7
- package/util/mermaid/cfg.js +37 -44
- package/util/version.js +1 -1
|
@@ -1,67 +1,544 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ControlFlowGraph = exports.CfgVertexType = void 0;
|
|
4
|
-
exports.edgeTypeToString = edgeTypeToString;
|
|
5
|
-
exports.equalVertex = equalVertex;
|
|
6
|
-
exports.isMarkerVertex = isMarkerVertex;
|
|
7
|
-
exports.getVertexRootId = getVertexRootId;
|
|
3
|
+
exports.ControlFlowGraph = exports.CfgEdge = exports.CfgVertex = exports.CfgVertexType = void 0;
|
|
8
4
|
exports.emptyControlFlowInformation = emptyControlFlowInformation;
|
|
5
|
+
const node_id_1 = require("../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
6
|
+
const convert_values_1 = require("../r-bridge/lang-4.x/convert-values");
|
|
9
7
|
const assert_1 = require("../util/assert");
|
|
8
|
+
/**
|
|
9
|
+
* The type of a vertex in the {@link ControlFlowGraph}.
|
|
10
|
+
* Please use the helper object (e.g. {@link CfgVertex#getType|getType()}) to work with vertices instead of directly accessing the properties.
|
|
11
|
+
*/
|
|
10
12
|
var CfgVertexType;
|
|
11
13
|
(function (CfgVertexType) {
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
/**
|
|
15
|
+
* The explicit exit-nodes to ensure the hammock property.
|
|
16
|
+
* @see {@link CfgVertex.makeMarker|CfgVertex.makeMarker()} - for a helper function to create end marker vertices
|
|
17
|
+
*/
|
|
18
|
+
CfgVertexType[CfgVertexType["Marker"] = 0] = "Marker";
|
|
19
|
+
/**
|
|
20
|
+
* something like an if, assignment, ... even though in the classical sense of R they are still expressions
|
|
21
|
+
* @see {@link CfgVertex.makeStatement|CfgVertex.makeStatement()} - for a helper function to create statement vertices
|
|
22
|
+
*/
|
|
23
|
+
CfgVertexType[CfgVertexType["Statement"] = 1] = "Statement";
|
|
24
|
+
/**
|
|
25
|
+
* something like an addition, ...
|
|
26
|
+
* @see {@link CfgVertex.makeExpression|CfgVertex.makeExpression()} - for a helper function to create expression vertices
|
|
27
|
+
*/
|
|
28
|
+
CfgVertexType[CfgVertexType["Expression"] = 2] = "Expression";
|
|
29
|
+
/**
|
|
30
|
+
* a (as far as R allows this) 'basic' block
|
|
31
|
+
* @see {@link CfgVertex.makeBlock|CfgVertex.makeBlock()} - for a helper function to create basic block vertices
|
|
32
|
+
*/
|
|
33
|
+
CfgVertexType[CfgVertexType["Block"] = 3] = "Block";
|
|
20
34
|
})(CfgVertexType || (exports.CfgVertexType = CfgVertexType = {}));
|
|
21
35
|
/**
|
|
22
|
-
*
|
|
36
|
+
* Helper object for {@link CfgVertex} - a vertex in the {@link ControlFlowGraph} that may have markers attached to it (e.g., for function calls).
|
|
23
37
|
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
exports.CfgVertex = {
|
|
39
|
+
/**
|
|
40
|
+
* Create a new expression vertex with the given id, children, call targets, and markers.
|
|
41
|
+
* @param id - the id of the vertex, which should directly relate to the AST node
|
|
42
|
+
* @param children - child nodes attached to this one
|
|
43
|
+
* @param callTargets - if the vertex calls a function, this links all targets of this call
|
|
44
|
+
* @param mid - the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers
|
|
45
|
+
* @param end - the ids of the end-markers attached to this vertex, which should directly relate to the AST nodes of the end markers
|
|
46
|
+
* @see {@link CfgVertex#isExpression|isExpression()} - for a way to check whether a vertex is an expression vertex
|
|
47
|
+
*/
|
|
48
|
+
makeExpression(id, { children, mid, end, callTargets } = {}) {
|
|
49
|
+
if (children === undefined && callTargets === undefined) {
|
|
50
|
+
if (mid === undefined && end === undefined) {
|
|
51
|
+
return [CfgVertexType.Expression, id];
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
return [CfgVertexType.Expression, id, mid, end];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return [CfgVertexType.Expression, id, mid, end, children, callTargets];
|
|
58
|
+
},
|
|
59
|
+
/**
|
|
60
|
+
* A convenience function to create a new expression vertex with a canonical end marker ({@link CfgVertex#toExitId|toExitId()}) based on the given id and the given id as root id for the end marker.
|
|
61
|
+
* @param id - the id of the vertex, which should directly relate to the AST node
|
|
62
|
+
* @param children - child nodes attached to this one
|
|
63
|
+
* @param callTargets - if the vertex calls a function, this links all targets of this call
|
|
64
|
+
* @param mid - the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers
|
|
65
|
+
* @see {@link CfgVertex#makeExpression|makeExpression()} - for a way to create expression vertices with a custom end marker
|
|
66
|
+
* @see {@link CfgVertex#makeExitMarker|makeExitMarker()} - for a helper function to create end marker vertices with a canonical id#
|
|
67
|
+
* @see {@link CfgVertex#toExitId|toExitId()} - for a way to convert the given id to a canonical end marker id
|
|
68
|
+
*/
|
|
69
|
+
makeExpressionWithEnd(id, { children, mid, callTargets } = {}) {
|
|
70
|
+
return exports.CfgVertex.makeExpression(id, { children, mid, end: [exports.CfgVertex.toExitId(id)], callTargets });
|
|
71
|
+
},
|
|
72
|
+
/**
|
|
73
|
+
* A convenience function to create a new statement vertex with a canonical end marker ({@link CfgVertex#toExitId|toExitId()}) based on the given id and the given id as root id for the end marker.
|
|
74
|
+
* @param id - the id of the vertex, which should directly relate to the AST node
|
|
75
|
+
* @param children - child nodes attached to this one
|
|
76
|
+
* @param callTargets - if the vertex calls a function, this links all targets of this call
|
|
77
|
+
* @param mid - the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers
|
|
78
|
+
* @see {@link CfgVertex#makeExpression|makeExpression()} - for a way to create expression vertices with a custom end marker
|
|
79
|
+
* @see {@link CfgVertex#makeExitMarker|makeExitMarker()} - for a helper function to create end marker vertices with a canonical id#
|
|
80
|
+
* @see {@link CfgVertex#toExitId|toExitId()} - for a way to convert the given id to a canonical end marker id
|
|
81
|
+
*/
|
|
82
|
+
makeStatementWithEnd(id, { children, mid, callTargets } = {}) {
|
|
83
|
+
return exports.CfgVertex.makeStatement(id, { children, mid, end: [exports.CfgVertex.toExitId(id)], callTargets });
|
|
84
|
+
},
|
|
85
|
+
/**
|
|
86
|
+
* Create a new statement vertex with the given id, children, call targets, and markers.
|
|
87
|
+
* @param id - the id of the vertex, which should directly relate to the AST node
|
|
88
|
+
* @param children - child nodes attached to this one
|
|
89
|
+
* @param callTargets - if the vertex calls a function, this links all targets of this call
|
|
90
|
+
* @param mid - the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers
|
|
91
|
+
* @param end - the ids of the end-markers attached to this vertex, which should directly relate to the AST nodes of the end markers
|
|
92
|
+
* @see {@link CfgVertex#isStatement|isStatement()} - for a way to check whether a vertex is a statement vertex
|
|
93
|
+
*/
|
|
94
|
+
makeStatement(id, { children, mid, end, callTargets } = {}) {
|
|
95
|
+
if (children === undefined && callTargets === undefined) {
|
|
96
|
+
if (mid === undefined && end === undefined) {
|
|
97
|
+
return [CfgVertexType.Statement, id];
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
return [CfgVertexType.Statement, id, mid, end];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return [CfgVertexType.Statement, id, mid, end, children, callTargets];
|
|
104
|
+
},
|
|
105
|
+
/**
|
|
106
|
+
* A convenience function to create a new vertex which is either a statement or an expression.
|
|
107
|
+
*/
|
|
108
|
+
makeExprOrStm(id, type, { children, mid, end, callTargets } = {}) {
|
|
109
|
+
if (children === undefined && callTargets === undefined) {
|
|
110
|
+
if (mid === undefined && end === undefined) {
|
|
111
|
+
return [type, id];
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
return [type, id, mid, end];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return [type, id, mid, end, children, callTargets];
|
|
118
|
+
},
|
|
119
|
+
/**
|
|
120
|
+
* Create a new marker vertex with the given id, root id, children, and call targets.
|
|
121
|
+
* @param id - the id of the vertex, which should directly relate to the AST node
|
|
122
|
+
* @param rootId - the id of the AST node this end marker corresponds to
|
|
123
|
+
* @see {@link CfgVertex#isMarker|isMarker()} - for a way to check whether a vertex is an end marker vertex
|
|
124
|
+
* @see {@link CfgVertex#getRootId|getRootId()} - for a way to get the root id of an end marker vertex
|
|
125
|
+
* @see {@link CfgVertex#makeExitMarker|makeExitMarker()} - for a helper function to create end marker vertices with a canonical id
|
|
126
|
+
*/
|
|
127
|
+
makeMarker(id, rootId) {
|
|
128
|
+
if (exports.CfgVertex.fromExitId(id) === rootId) {
|
|
129
|
+
return id;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
return [CfgVertexType.Marker, id, rootId];
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
/**
|
|
136
|
+
* A convenience function to create a new marker vertex with a canonical id ({@link CfgVertex#toExitId|toExitId()}) based on the given id and the given id as root id.
|
|
137
|
+
* @see {@link CfgVertex#makeMarker|makeMarker()} - for a way to create end marker vertices with a custom id
|
|
138
|
+
*/
|
|
139
|
+
makeExitMarker(id) {
|
|
140
|
+
return exports.CfgVertex.toExitId(id);
|
|
141
|
+
},
|
|
142
|
+
/**
|
|
143
|
+
* Create a new basic block vertex with the given id, elements, children, and call targets.
|
|
144
|
+
* @param id - the id of the vertex, which should directly relate to the AST node
|
|
145
|
+
* @param elems - the vertices that are part of this block, only connected by FDs, vertices should never occur in multiple bbs
|
|
146
|
+
* @see {@link CfgVertex#isBlock|isBlock()} - for a way to check whether a vertex is a basic block vertex
|
|
147
|
+
*/
|
|
148
|
+
makeBlock(id, elems) {
|
|
149
|
+
return [CfgVertexType.Block, id, elems];
|
|
150
|
+
},
|
|
151
|
+
/**
|
|
152
|
+
* Check whether the given vertex is an expression vertex.
|
|
153
|
+
* @see {@link CfgVertex#makeExpression|makeExpression()} - for a way to create expression vertices
|
|
154
|
+
* @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex instead of checking against a given type
|
|
155
|
+
*/
|
|
156
|
+
isExpression(vertex) {
|
|
157
|
+
return Array.isArray(vertex) && vertex[0] === CfgVertexType.Expression;
|
|
158
|
+
},
|
|
159
|
+
/**
|
|
160
|
+
* Check whether the given vertex is a statement vertex.
|
|
161
|
+
* @see {@link CfgVertex#makeStatement|makeStatement()} - for a way to create statement vertices
|
|
162
|
+
* @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex instead of checking against a given type
|
|
163
|
+
*/
|
|
164
|
+
isStatement(vertex) {
|
|
165
|
+
return Array.isArray(vertex) && vertex[0] === CfgVertexType.Statement;
|
|
166
|
+
},
|
|
167
|
+
/**
|
|
168
|
+
* Check whether the given vertex is an end marker vertex.
|
|
169
|
+
* @see {@link CfgVertex#makeMarker|makeMarker()} - for a way to create end marker vertices
|
|
170
|
+
* @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex instead of checking against a given type
|
|
171
|
+
*/
|
|
172
|
+
isMarker(vertex) {
|
|
173
|
+
return vertex !== undefined && (!Array.isArray(vertex) || vertex[0] === CfgVertexType.Marker);
|
|
174
|
+
},
|
|
175
|
+
/**
|
|
176
|
+
* Check whether the given vertex is a basic block vertex.
|
|
177
|
+
* @see {@link CfgVertex#makeBlock|makeBlock()} - for a way to create basic block vertices
|
|
178
|
+
* @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex instead of checking against a given type
|
|
179
|
+
*/
|
|
180
|
+
isBlock(vertex) {
|
|
181
|
+
return Array.isArray(vertex) && vertex[0] === CfgVertexType.Block;
|
|
182
|
+
},
|
|
183
|
+
/**
|
|
184
|
+
* Get the type of the given vertex.
|
|
185
|
+
* @example
|
|
186
|
+
* ```ts
|
|
187
|
+
* const vertex: CfgVertex = CfgVertex.makeExpr('node-1')
|
|
188
|
+
* console.log(CfgVertex.getType(vertex)); // Output: CfgVertexType.Expression
|
|
189
|
+
* ```
|
|
190
|
+
* @see {@link CfgVertex#isExpression|isExpression()}, {@link CfgVertex#isStatement|isStatement()}, {@link CfgVertex#isMarker|isMarker()}, {@link CfgVertex#isBlock|isBlock()} - for ways to check the type of a vertex against a specific type instead of getting the type and checking it against a specific type
|
|
191
|
+
* @see {@link CfgVertex#getId|getId()} - for a way to get the id of a vertex
|
|
192
|
+
* @see {@link CfgVertex#typeToString|typeToString()} - for a way to convert the type of a vertex to a string for easier debugging and visualization
|
|
193
|
+
*/
|
|
194
|
+
getType(vertex) {
|
|
195
|
+
return Array.isArray(vertex) ? vertex[0] : CfgVertexType.Marker;
|
|
196
|
+
},
|
|
197
|
+
/**
|
|
198
|
+
* Convert the given vertex type to a string for easier debugging and visualization.
|
|
199
|
+
* @see {@link CfgVertexType} - for the possible vertex types
|
|
200
|
+
* @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex and convert it to a string
|
|
201
|
+
*/
|
|
202
|
+
typeToString(type) {
|
|
203
|
+
switch (type) {
|
|
204
|
+
case CfgVertexType.Marker:
|
|
205
|
+
return 'marker';
|
|
206
|
+
case CfgVertexType.Statement:
|
|
207
|
+
return 'statement';
|
|
208
|
+
case CfgVertexType.Expression:
|
|
209
|
+
return 'expression';
|
|
210
|
+
case CfgVertexType.Block:
|
|
211
|
+
return 'block';
|
|
212
|
+
default:
|
|
213
|
+
(0, assert_1.assertUnreachable)(type);
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
/**
|
|
217
|
+
* Get the id of the given vertex, which should directly relate to the AST node.
|
|
218
|
+
* @example
|
|
219
|
+
* ```ts
|
|
220
|
+
* const vertex: CfgVertex = CfgVertex.makeExpr('node-1')
|
|
221
|
+
* console.log(CfgVertex.getId(vertex)); // Output: 'node-1'
|
|
222
|
+
* ```
|
|
223
|
+
* @see {@link CfgVertex#getType|getType()} - for a way to get the type of a vertex
|
|
224
|
+
* @see {@link CfgVertex#getRootId|getRootId()} - for a way to get the root id of a vertex
|
|
225
|
+
*/
|
|
226
|
+
getId(vertex) {
|
|
227
|
+
return vertex === undefined ? undefined : (Array.isArray(vertex) ? vertex[1] : vertex);
|
|
228
|
+
},
|
|
229
|
+
/**
|
|
230
|
+
* Check whether two vertices are equal, i.e., they have the same type, id, and if they are basic block vertices, they also have the same elements in the same order.
|
|
231
|
+
*/
|
|
232
|
+
equal(a, b) {
|
|
233
|
+
if (!Array.isArray(a) || !Array.isArray(b)) {
|
|
234
|
+
return a === b;
|
|
235
|
+
}
|
|
236
|
+
else if (a === b) {
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
else if (a[0] !== b[0] || a[1] !== b[1]) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
else if (a[0] === CfgVertexType.Block && b[0] === CfgVertexType.Block) {
|
|
243
|
+
return a[2].length === b[2].length && a[2].every((e, i) => exports.CfgVertex.equal(e, b[2][i]));
|
|
244
|
+
}
|
|
245
|
+
else if (a[0] === CfgVertexType.Marker && b[0] === CfgVertexType.Marker) {
|
|
246
|
+
return a[2] === b[2];
|
|
247
|
+
}
|
|
248
|
+
return true;
|
|
249
|
+
},
|
|
250
|
+
/**
|
|
251
|
+
* Get the root id of a vertex, i.e., the id of the AST node it corresponds to.
|
|
252
|
+
* For normal vertices, this is the same as the id of the vertex itself, for end marker vertices, this is the root id stored in the vertex.
|
|
253
|
+
* @see {@link CfgVertex#unpackRoot|unpackRoot()} - for a way to unpack the root id of a marker vertex
|
|
254
|
+
*/
|
|
255
|
+
getRootId(vertex) {
|
|
256
|
+
return exports.CfgVertex.isMarker(vertex) ? exports.CfgVertex.unpackRootId(vertex) : vertex[1];
|
|
257
|
+
},
|
|
258
|
+
/**
|
|
259
|
+
* Unpack the root id of a marker vertex, i.e., get the root id stored in the vertex or derive it from the canonical id if it is not explicitly stored.
|
|
260
|
+
* @see {@link CfgVertex#getRootId|getRootId()} - for a way to get the root id of a vertex, which uses this function for marker vertices
|
|
261
|
+
*/
|
|
262
|
+
unpackRootId(vertex) {
|
|
263
|
+
return Array.isArray(vertex) ? vertex[2] ?? exports.CfgVertex.fromExitId(vertex[1]) : exports.CfgVertex.fromExitId(vertex);
|
|
264
|
+
},
|
|
265
|
+
/**
|
|
266
|
+
* Get the elements of a basic block vertex, i.e., the vertices that are part of this block, only connected by FDs, vertices should never occur in multiple bbs.
|
|
267
|
+
* @see {@link CfgVertex#isBlock|isBlock()} - for a way to check whether a vertex is a basic block vertex before trying to get the elements
|
|
268
|
+
* @see {@link CfgVertex#setBasicBlockElements|setBasicBlockElements()} - for a way to set the elements of a basic block vertex
|
|
269
|
+
*/
|
|
270
|
+
getBasicBlockElements(vertex) {
|
|
271
|
+
return vertex[2];
|
|
272
|
+
},
|
|
273
|
+
/**
|
|
274
|
+
* **Sets in-place**
|
|
275
|
+
* Set the elements of a basic block vertex, i.e., the vertices that are part of this block, only connected by FDs, vertices should never occur in multiple bbs.
|
|
276
|
+
* @see {@link CfgVertex#isBlock|isBlock()} - for a way to check whether a vertex is a basic block vertex before trying to set the elements
|
|
277
|
+
* @see {@link CfgVertex#getBasicBlockElements|getBasicBlockElements()} - for a way to get the elements of a basic block vertex
|
|
278
|
+
*/
|
|
279
|
+
setBasicBlockElements(vertex, elems) {
|
|
280
|
+
vertex[2] = elems;
|
|
281
|
+
},
|
|
282
|
+
/**
|
|
283
|
+
* Get the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers.
|
|
284
|
+
* @see {@link CfgVertex#getMid|getMid()} - for a way to get the ids of the mid-markers attached to this vertex
|
|
285
|
+
* @see {@link CfgVertex#setEnd|setEnd()} - for a way to set the ids of the end-markers attached to this vertex
|
|
286
|
+
*/
|
|
287
|
+
getEnd(vertex) {
|
|
288
|
+
if (vertex === undefined) {
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
const type = exports.CfgVertex.getType(vertex);
|
|
292
|
+
if (type === CfgVertexType.Statement || type === CfgVertexType.Expression) {
|
|
293
|
+
return vertex[3];
|
|
294
|
+
}
|
|
295
|
+
return undefined;
|
|
296
|
+
},
|
|
297
|
+
/**
|
|
298
|
+
* **Sets in-place**
|
|
299
|
+
* Set the ids of the end-markers attached to this vertex, which should directly relate to the AST nodes of the end markers.
|
|
300
|
+
* @see {@link CfgVertex#getEnd|getEnd()} - for a way to get the ids of the end-markers attached to this vertex
|
|
301
|
+
*/
|
|
302
|
+
setEnd(vertex, endMarkers) {
|
|
303
|
+
vertex[3] = endMarkers;
|
|
304
|
+
},
|
|
305
|
+
/**
|
|
306
|
+
* Get the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers.
|
|
307
|
+
*/
|
|
308
|
+
getMid(vertex) {
|
|
309
|
+
if (vertex === undefined) {
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
const type = exports.CfgVertex.getType(vertex);
|
|
313
|
+
if (type === CfgVertexType.Statement || type === CfgVertexType.Expression) {
|
|
314
|
+
return vertex[2];
|
|
315
|
+
}
|
|
316
|
+
return undefined;
|
|
317
|
+
},
|
|
318
|
+
/**
|
|
319
|
+
* **Sets in-place**
|
|
320
|
+
* Set the ids of the mid-markers attached to this vertex, which should directly relate to the AST nodes of the mid markers.
|
|
321
|
+
* @see {@link CfgVertex#getMid|getMid()} - for a way to get the ids of the mid-markers attached to this vertex
|
|
322
|
+
* @see {@link CfgVertex#setEnd|setEnd()} - for a way to set the ids of the end-markers attached to this vertex
|
|
323
|
+
*/
|
|
324
|
+
setMid(vertex, midMarkers) {
|
|
325
|
+
vertex[2] = midMarkers;
|
|
326
|
+
},
|
|
327
|
+
/**
|
|
328
|
+
* Converts the given id to a, canonical, basic block lift (i.e., it adds 'bb-' as a prefix).
|
|
329
|
+
*/
|
|
330
|
+
toBasicBlockId(id) {
|
|
331
|
+
return `bb-${id}`;
|
|
332
|
+
},
|
|
333
|
+
/**
|
|
334
|
+
* Converts the given id to a canonical, end marker lift (i.e., it adds '-end' as a suffix).
|
|
335
|
+
* @see {@link CfgVertex#fromExitId|fromExitId()} - for a way to convert the given id from a canonical end marker lift to the original id (i.e., it removes '-end' as a suffix if it is present)
|
|
336
|
+
*/
|
|
337
|
+
toExitId(id) {
|
|
338
|
+
return `${id}-e`;
|
|
339
|
+
},
|
|
340
|
+
/**
|
|
341
|
+
* Converts the given id from a canonical end marker lift to the original id (i.e., it removes '-end' as a suffix if it is present).
|
|
342
|
+
* @see {@link CfgVertex#toExitId|toExitId()} - for a way to convert the given id to a canonical end marker lift (i.e., it adds '-end' as a suffix)
|
|
343
|
+
*/
|
|
344
|
+
fromExitId(exitId) {
|
|
345
|
+
if (typeof exitId === 'string' && exitId.endsWith('-e')) {
|
|
346
|
+
return (0, node_id_1.normalizeIdToNumberIfPossible)(exitId.slice(0, -2));
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
return exitId;
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
/**
|
|
353
|
+
* Get the call targets of a statement or expression vertex, which links all targets of this call.
|
|
354
|
+
*/
|
|
355
|
+
getCallTargets(vertex) {
|
|
356
|
+
if (vertex === undefined) {
|
|
357
|
+
return undefined;
|
|
358
|
+
}
|
|
359
|
+
const type = exports.CfgVertex.getType(vertex);
|
|
360
|
+
if (type === CfgVertexType.Statement || type === CfgVertexType.Expression) {
|
|
361
|
+
return vertex[5];
|
|
362
|
+
}
|
|
363
|
+
return undefined;
|
|
364
|
+
},
|
|
365
|
+
/**
|
|
366
|
+
* **Sets in-place**
|
|
367
|
+
* Set the call targets of a statement or expression vertex, which links all targets of this call.
|
|
368
|
+
* @see {@link CfgVertex#getCallTargets|getCallTargets()} - for a way to get the call targets of a statement or expression vertex
|
|
369
|
+
* @see {@link CfgVertex#mapCallTargets|mapCallTargets()} - for a way to map the call targets of a statement or expression vertex to new call targets
|
|
370
|
+
*/
|
|
371
|
+
setCallTargets(vertex, callTargets) {
|
|
372
|
+
vertex[5] = callTargets;
|
|
373
|
+
},
|
|
374
|
+
/**
|
|
375
|
+
* Map the call targets of a statement or expression vertex, which links all targets of this call, to new call targets using the given mapping function.
|
|
376
|
+
* @see {@link CfgVertex#getCallTargets|getCallTargets()} - for a way to get the call targets of a statement or expression vertex
|
|
377
|
+
* @see {@link CfgVertex#setCallTargets|setCallTargets()} - for a way to set the call targets of a statement or expression vertex to new call targets
|
|
378
|
+
*/
|
|
379
|
+
mapCallTargets(vertex, mapFn) {
|
|
380
|
+
const currentTargets = exports.CfgVertex.getCallTargets(vertex);
|
|
381
|
+
const newTargets = mapFn(currentTargets);
|
|
382
|
+
exports.CfgVertex.setCallTargets(vertex, newTargets);
|
|
383
|
+
},
|
|
384
|
+
/**
|
|
385
|
+
* Get the children of a statement or expression vertex, i.e., the child nodes attached to this one.
|
|
386
|
+
*/
|
|
387
|
+
getChildren(vertex) {
|
|
388
|
+
if (vertex === undefined) {
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
const type = exports.CfgVertex.getType(vertex);
|
|
392
|
+
if (type === CfgVertexType.Statement || type === CfgVertexType.Expression) {
|
|
393
|
+
return vertex[4];
|
|
394
|
+
}
|
|
395
|
+
return undefined;
|
|
32
396
|
}
|
|
33
|
-
}
|
|
397
|
+
};
|
|
34
398
|
/**
|
|
35
|
-
*
|
|
399
|
+
* Helper object for {@link CfgEdge} - an edge in the {@link ControlFlowGraph}.
|
|
36
400
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
401
|
+
exports.CfgEdge = {
|
|
402
|
+
/**
|
|
403
|
+
* Check whether the given edge is a flow dependency edge.
|
|
404
|
+
*/
|
|
405
|
+
isFlowDependency(edge) {
|
|
406
|
+
return edge === 0 /* CfgEdgeType.Fd */;
|
|
407
|
+
},
|
|
408
|
+
/**
|
|
409
|
+
* Check whether the given edge is a control dependency edge.
|
|
410
|
+
*/
|
|
411
|
+
isControlDependency(edge) {
|
|
412
|
+
return Array.isArray(edge) && edge.length === 2;
|
|
413
|
+
},
|
|
414
|
+
/**
|
|
415
|
+
* Create a flow dependency edge.
|
|
416
|
+
*/
|
|
417
|
+
makeFd() {
|
|
418
|
+
return 0 /* CfgEdgeType.Fd */;
|
|
419
|
+
},
|
|
420
|
+
/**
|
|
421
|
+
* Create a control dependency edge with the given cause and condition.
|
|
422
|
+
* @param controlId - the id of the vertex that causes the control dependency
|
|
423
|
+
* @param whenTrue - whether the control dependency is satisfied with a true condition or is it negated (e.g., else-branch)
|
|
424
|
+
* @see {@link CfgEdge#makeCdTrue|makeCdTrue()} - for a version of this function that assumes the control dependency is satisfied with a true condition
|
|
425
|
+
* @see {@link CfgEdge#makeCdFalse|makeCdFalse()} - for a version of this function that assumes the control dependency is negated (e.g., else-branch)
|
|
426
|
+
*/
|
|
427
|
+
makeCd(controlId, whenTrue) {
|
|
428
|
+
return [controlId, whenTrue];
|
|
429
|
+
},
|
|
430
|
+
/**
|
|
431
|
+
* Create a control dependency edge with the given cause and a true condition.
|
|
432
|
+
* @param controlId - the id of the vertex that causes the control dependency
|
|
433
|
+
* @see {@link CfgEdge#makeCd|makeCd()} - for a version of this function that allows to specify the condition as well
|
|
434
|
+
*/
|
|
435
|
+
makeCdTrue(controlId) {
|
|
436
|
+
return [controlId, convert_values_1.RTrue];
|
|
437
|
+
},
|
|
438
|
+
/**
|
|
439
|
+
* Create a control dependency edge with the given cause and a negated condition (e.g., else-branch).
|
|
440
|
+
* @param controlId - the id of the vertex that causes the control dependency
|
|
441
|
+
* @see {@link CfgEdge#makeCd|makeCd()} - for a version of this function that allows to specify the condition as well
|
|
442
|
+
*/
|
|
443
|
+
makeCdFalse(controlId) {
|
|
444
|
+
return [controlId, convert_values_1.RFalse];
|
|
445
|
+
},
|
|
446
|
+
/**
|
|
447
|
+
* Get the cause of a control dependency edge, i.e., the id of the vertex that causes the control dependency.
|
|
448
|
+
* If the edge is not a control dependency edge, this returns undefined.
|
|
449
|
+
*
|
|
450
|
+
* This is the pendant of {@link CfgEdge#isControlDependency|isControlDependency()} on a {@link CfgEdge}.
|
|
451
|
+
* @see {@link CfgEdge#unpackCause|unpackCause()} - for a version of this function that assumes the edge is a control dependency edge and hence does not return undefined
|
|
452
|
+
*/
|
|
453
|
+
getCause(edge) {
|
|
454
|
+
if (exports.CfgEdge.isControlDependency(edge)) {
|
|
455
|
+
return edge[0];
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
return undefined;
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
/**
|
|
462
|
+
* Get the cause of a control dependency edge, i.e., the id of the vertex that causes the control dependency.
|
|
463
|
+
*/
|
|
464
|
+
unpackCause(edge) {
|
|
465
|
+
return edge[0];
|
|
466
|
+
},
|
|
467
|
+
/**
|
|
468
|
+
* Get whether the control dependency edge is satisfied with a true condition or is it negated (e.g., else-branch).
|
|
469
|
+
* If the edge is not a control dependency edge, this returns undefined.
|
|
470
|
+
*
|
|
471
|
+
* This is the pendant of {@link CfgEdge#isControlDependency|isControlDependency()} on a {@link CfgEdge}.
|
|
472
|
+
* @see {@link CfgEdge#unpackWhen|unpackWhen()} - for a version of this function that assumes the edge is a control dependency edge and hence does not return undefined
|
|
473
|
+
*/
|
|
474
|
+
getWhen(edge) {
|
|
475
|
+
if (exports.CfgEdge.isControlDependency(edge)) {
|
|
476
|
+
return edge[1];
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
return undefined;
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
/**
|
|
483
|
+
* Get whether the control dependency edge is satisfied with a true condition or is it negated (e.g., else-branch).
|
|
484
|
+
*/
|
|
485
|
+
unpackWhen(edge) {
|
|
486
|
+
return edge[1];
|
|
487
|
+
},
|
|
488
|
+
/**
|
|
489
|
+
* Check whether two edges are equal.
|
|
490
|
+
*/
|
|
491
|
+
equals(a, b) {
|
|
492
|
+
if (exports.CfgEdge.isFlowDependency(a) && exports.CfgEdge.isFlowDependency(b)) {
|
|
493
|
+
return true;
|
|
494
|
+
}
|
|
495
|
+
else if (exports.CfgEdge.isControlDependency(a) && exports.CfgEdge.isControlDependency(b)) {
|
|
496
|
+
return a[0] === b[0] && a[1] === b[1];
|
|
497
|
+
}
|
|
39
498
|
return false;
|
|
499
|
+
},
|
|
500
|
+
/**
|
|
501
|
+
* Check whether the given edge is of the given type.
|
|
502
|
+
* @see {@link CfgEdge#getType|getType()} - for a version of this function that returns the type of the edge instead of checking against a given type
|
|
503
|
+
*/
|
|
504
|
+
isOfType(edge, type) {
|
|
505
|
+
return exports.CfgEdge.getType(edge) === type;
|
|
506
|
+
},
|
|
507
|
+
/**
|
|
508
|
+
* Get the type of the given edge.
|
|
509
|
+
* @see {@link CfgEdge#isOfType|isOfType()} - for a version of this function that checks whether the edge is of a given type
|
|
510
|
+
*/
|
|
511
|
+
getType(edge) {
|
|
512
|
+
return exports.CfgEdge.isFlowDependency(edge) ? 0 /* CfgEdgeType.Fd */ : 1 /* CfgEdgeType.Cd */;
|
|
513
|
+
},
|
|
514
|
+
/**
|
|
515
|
+
* Provide a string representation of the given edge, e.g., for debugging or visualization purposes.
|
|
516
|
+
* @see {@link CfgEdge#toString|toString()} - for a version of this function that also includes the details of the edge (e.g., cause and condition for control dependency edges)
|
|
517
|
+
*/
|
|
518
|
+
typeToString(edge) {
|
|
519
|
+
if (exports.CfgEdge.isFlowDependency(edge)) {
|
|
520
|
+
return 'FD';
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
return 'CD';
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
/**
|
|
527
|
+
* Provide a string representation of the given edge, including its details (e.g., cause and condition for control dependency edges), e.g., for debugging or visualization purposes.
|
|
528
|
+
* @see {@link CfgEdge#typeToString|typeToString()} - for a version of this function that only includes the type of the edge
|
|
529
|
+
*/
|
|
530
|
+
toString(edge) {
|
|
531
|
+
if (exports.CfgEdge.isFlowDependency(edge)) {
|
|
532
|
+
return 'FD';
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
return `CD(${edge[0]}, ${edge[1] === convert_values_1.RTrue ? 'T' : 'F'})`;
|
|
536
|
+
}
|
|
40
537
|
}
|
|
41
|
-
|
|
42
|
-
return a.elems.length === b.elems.length && a.elems.every((e, i) => e.id === b.elems[i].id);
|
|
43
|
-
}
|
|
44
|
-
else if (a.type === CfgVertexType.EndMarker && b.type === CfgVertexType.EndMarker) {
|
|
45
|
-
return a.root === b.root;
|
|
46
|
-
}
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Checks whether a vertex is a marker vertex (i.e., does not correspond to an actual AST node
|
|
51
|
-
* but is a marker in the control flow graph).
|
|
52
|
-
*/
|
|
53
|
-
function isMarkerVertex(vertex) {
|
|
54
|
-
return vertex.type === CfgVertexType.EndMarker;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Get the root id of a vertex, i.e., the id of the AST node it corresponds to.
|
|
58
|
-
*/
|
|
59
|
-
function getVertexRootId(vertex) {
|
|
60
|
-
return isMarkerVertex(vertex) ? vertex.root : vertex.id;
|
|
61
|
-
}
|
|
538
|
+
};
|
|
62
539
|
/**
|
|
63
540
|
* This class represents the control flow graph of an R program.
|
|
64
|
-
* The control flow may be hierarchical when confronted with function definitions (see {@link
|
|
541
|
+
* The control flow may be hierarchical when confronted with function definitions (see {@link CfgVertex} and {@link CFG#rootVertexIds|rootVertexIds()}).
|
|
65
542
|
*
|
|
66
543
|
* There are two very simple visitors to traverse a CFG:
|
|
67
544
|
* - {@link visitCfgInOrder} visits the graph in the order of the vertices
|
|
@@ -70,35 +547,40 @@ function getVertexRootId(vertex) {
|
|
|
70
547
|
* If you want to prohibit modification, please refer to the {@link ReadOnlyControlFlowGraph} interface.
|
|
71
548
|
*/
|
|
72
549
|
class ControlFlowGraph {
|
|
73
|
-
|
|
550
|
+
roots = new Set();
|
|
74
551
|
/** Nesting-Independent vertex information, mapping the id to the vertex */
|
|
75
|
-
|
|
552
|
+
vtxInfos = new Map();
|
|
76
553
|
/** the basic block children map contains a mapping of ids to all vertices that are nested in basic blocks, mapping them to the Id of the block they appear in */
|
|
77
554
|
bbChildren = new Map();
|
|
78
555
|
/** basic block agnostic edges */
|
|
79
|
-
|
|
556
|
+
edgeInfos = new Map();
|
|
80
557
|
/** reverse edges for bidirectional mapping */
|
|
81
|
-
|
|
558
|
+
revEdgeInfos = new Map();
|
|
82
559
|
/** used as an optimization to avoid unnecessary lookups */
|
|
83
|
-
|
|
560
|
+
_mayBB = false;
|
|
84
561
|
/**
|
|
85
562
|
* Add a new vertex to the control flow graph.
|
|
86
563
|
* @see {@link ControlFlowGraph#addEdge|addEdge()} - to add an edge
|
|
87
564
|
*/
|
|
88
565
|
addVertex(vertex, rootVertex = true) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
566
|
+
const vid = exports.CfgVertex.getId(vertex);
|
|
567
|
+
(0, assert_1.guard)(!this.vtxInfos.has(vid), `Node with id ${vid} already exists`);
|
|
568
|
+
if (exports.CfgVertex.isBlock(vertex)) {
|
|
569
|
+
this._mayBB = true;
|
|
570
|
+
const elems = exports.CfgVertex.getBasicBlockElements(vertex);
|
|
571
|
+
if (elems.some(e => {
|
|
572
|
+
const eid = exports.CfgVertex.getId(e);
|
|
573
|
+
return this.bbChildren.has(eid) || this.roots.has(eid);
|
|
574
|
+
})) {
|
|
575
|
+
throw new Error(`Vertex ${vid} contains vertices that are already part of the graph`);
|
|
94
576
|
}
|
|
95
|
-
for (const elem of
|
|
96
|
-
this.bbChildren.set(elem
|
|
577
|
+
for (const elem of elems) {
|
|
578
|
+
this.bbChildren.set(exports.CfgVertex.getId(elem), vid);
|
|
97
579
|
}
|
|
98
580
|
}
|
|
99
|
-
this.
|
|
581
|
+
this.vtxInfos.set(vid, vertex);
|
|
100
582
|
if (rootVertex) {
|
|
101
|
-
this.
|
|
583
|
+
this.roots.add(vid);
|
|
102
584
|
}
|
|
103
585
|
return this;
|
|
104
586
|
}
|
|
@@ -108,14 +590,14 @@ class ControlFlowGraph {
|
|
|
108
590
|
* @see {@link ControlFlowGraph#addEdges|addEdges()} - to add multiple edges at once
|
|
109
591
|
*/
|
|
110
592
|
addEdge(from, to, edge) {
|
|
111
|
-
const edgesFrom = this.
|
|
112
|
-
if (!this.
|
|
113
|
-
this.
|
|
593
|
+
const edgesFrom = this.edgeInfos.get(from) ?? new Map();
|
|
594
|
+
if (!this.edgeInfos.has(from)) {
|
|
595
|
+
this.edgeInfos.set(from, edgesFrom);
|
|
114
596
|
}
|
|
115
597
|
edgesFrom.set(to, edge);
|
|
116
|
-
const edgesTo = this.
|
|
117
|
-
if (!this.
|
|
118
|
-
this.
|
|
598
|
+
const edgesTo = this.revEdgeInfos.get(to) ?? new Map();
|
|
599
|
+
if (!this.revEdgeInfos.has(to)) {
|
|
600
|
+
this.revEdgeInfos.set(to, edgesTo);
|
|
119
601
|
}
|
|
120
602
|
edgesTo.set(from, edge);
|
|
121
603
|
return this;
|
|
@@ -130,23 +612,24 @@ class ControlFlowGraph {
|
|
|
130
612
|
return this;
|
|
131
613
|
}
|
|
132
614
|
outgoingEdges(node) {
|
|
133
|
-
return this.
|
|
615
|
+
return this.edgeInfos.get(node);
|
|
134
616
|
}
|
|
135
617
|
ingoingEdges(node) {
|
|
136
|
-
return this.
|
|
618
|
+
return this.revEdgeInfos.get(node);
|
|
137
619
|
}
|
|
138
620
|
rootIds() {
|
|
139
|
-
return this.
|
|
621
|
+
return this.roots;
|
|
140
622
|
}
|
|
141
623
|
vertices(includeBasicBlockElements = true) {
|
|
142
624
|
if (includeBasicBlockElements) {
|
|
143
|
-
const all = new Map(this.
|
|
625
|
+
const all = new Map(this.vtxInfos);
|
|
144
626
|
for (const [id, block] of this.bbChildren.entries()) {
|
|
145
627
|
const blockVertex = all.get(block);
|
|
146
|
-
if (blockVertex === undefined ||
|
|
628
|
+
if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
|
|
147
629
|
continue;
|
|
148
630
|
}
|
|
149
|
-
const
|
|
631
|
+
const elems = exports.CfgVertex.getBasicBlockElements(blockVertex);
|
|
632
|
+
const elem = elems.find(e => exports.CfgVertex.getId(e) === id);
|
|
150
633
|
if (elem !== undefined) {
|
|
151
634
|
all.set(id, elem);
|
|
152
635
|
}
|
|
@@ -154,7 +637,7 @@ class ControlFlowGraph {
|
|
|
154
637
|
return all;
|
|
155
638
|
}
|
|
156
639
|
else {
|
|
157
|
-
return this.
|
|
640
|
+
return this.vtxInfos;
|
|
158
641
|
}
|
|
159
642
|
}
|
|
160
643
|
getBasicBlock(elemId) {
|
|
@@ -162,20 +645,20 @@ class ControlFlowGraph {
|
|
|
162
645
|
if (block === undefined) {
|
|
163
646
|
return undefined;
|
|
164
647
|
}
|
|
165
|
-
const blockVertex = this.
|
|
166
|
-
if (blockVertex === undefined ||
|
|
648
|
+
const blockVertex = this.vtxInfos.get(block);
|
|
649
|
+
if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
|
|
167
650
|
return undefined;
|
|
168
651
|
}
|
|
169
652
|
return blockVertex;
|
|
170
653
|
}
|
|
171
654
|
edges() {
|
|
172
|
-
return this.
|
|
655
|
+
return this.edgeInfos;
|
|
173
656
|
}
|
|
174
657
|
/**
|
|
175
658
|
* Retrieve a vertex by its id.
|
|
176
659
|
*/
|
|
177
660
|
getVertex(id, includeBlocks = true) {
|
|
178
|
-
const res = this.
|
|
661
|
+
const res = this.vtxInfos.get(id);
|
|
179
662
|
if (res || !includeBlocks) {
|
|
180
663
|
return res;
|
|
181
664
|
}
|
|
@@ -183,17 +666,18 @@ class ControlFlowGraph {
|
|
|
183
666
|
if (block === undefined) {
|
|
184
667
|
return undefined;
|
|
185
668
|
}
|
|
186
|
-
const blockVertex = this.
|
|
187
|
-
if (blockVertex === undefined ||
|
|
669
|
+
const blockVertex = this.vtxInfos.get(block);
|
|
670
|
+
if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
|
|
188
671
|
return undefined;
|
|
189
672
|
}
|
|
190
|
-
|
|
673
|
+
const elems = exports.CfgVertex.getBasicBlockElements(blockVertex);
|
|
674
|
+
return elems.find(e => exports.CfgVertex.getId(e) === id);
|
|
191
675
|
}
|
|
192
676
|
hasVertex(id, includeBlocks = true) {
|
|
193
|
-
return this.
|
|
677
|
+
return this.vtxInfos.has(id) || (this._mayBB && includeBlocks && this.bbChildren.has(id));
|
|
194
678
|
}
|
|
195
679
|
mayHaveBasicBlocks() {
|
|
196
|
-
return this.
|
|
680
|
+
return this._mayBB;
|
|
197
681
|
}
|
|
198
682
|
/**
|
|
199
683
|
* This removes the vertex and all edges to and from it.
|
|
@@ -202,9 +686,9 @@ class ControlFlowGraph {
|
|
|
202
686
|
* @see {@link ControlFlowGraph#removeEdge|removeEdge()} - to remove a specific edge
|
|
203
687
|
*/
|
|
204
688
|
removeVertex(id) {
|
|
205
|
-
this.
|
|
206
|
-
this.
|
|
207
|
-
this.
|
|
689
|
+
this.vtxInfos.delete(id);
|
|
690
|
+
this.edgeInfos.delete(id);
|
|
691
|
+
this.revEdgeInfos.delete(id);
|
|
208
692
|
this.bbChildren.delete(id);
|
|
209
693
|
// remove all bbChildren with id as target
|
|
210
694
|
for (const [a, b] of this.bbChildren.entries()) {
|
|
@@ -212,13 +696,13 @@ class ControlFlowGraph {
|
|
|
212
696
|
this.bbChildren.delete(a);
|
|
213
697
|
}
|
|
214
698
|
}
|
|
215
|
-
for (const edges of this.
|
|
699
|
+
for (const edges of this.edgeInfos.values()) {
|
|
216
700
|
edges.delete(id);
|
|
217
701
|
}
|
|
218
|
-
for (const edges of this.
|
|
702
|
+
for (const edges of this.revEdgeInfos.values()) {
|
|
219
703
|
edges.delete(id);
|
|
220
704
|
}
|
|
221
|
-
this.
|
|
705
|
+
this.roots.delete(id);
|
|
222
706
|
return this;
|
|
223
707
|
}
|
|
224
708
|
/**
|
|
@@ -227,18 +711,18 @@ class ControlFlowGraph {
|
|
|
227
711
|
* @see {@link ControlFlowGraph#removeVertex|removeVertex()} - to remove a vertex and all its edges
|
|
228
712
|
*/
|
|
229
713
|
removeEdge(from, to) {
|
|
230
|
-
const edgesFrom = this.
|
|
714
|
+
const edgesFrom = this.edgeInfos.get(from);
|
|
231
715
|
if (edgesFrom) {
|
|
232
716
|
edgesFrom.delete(to);
|
|
233
717
|
if (edgesFrom.size === 0) {
|
|
234
|
-
this.
|
|
718
|
+
this.edgeInfos.delete(from);
|
|
235
719
|
}
|
|
236
720
|
}
|
|
237
|
-
const edgesTo = this.
|
|
721
|
+
const edgesTo = this.revEdgeInfos.get(to);
|
|
238
722
|
if (edgesTo) {
|
|
239
723
|
edgesTo.delete(from);
|
|
240
724
|
if (edgesTo.size === 0) {
|
|
241
|
-
this.
|
|
725
|
+
this.revEdgeInfos.delete(to);
|
|
242
726
|
}
|
|
243
727
|
}
|
|
244
728
|
return this;
|
|
@@ -247,14 +731,14 @@ class ControlFlowGraph {
|
|
|
247
731
|
mergeTwoBasicBlocks(a, b) {
|
|
248
732
|
const aVertex = this.getVertex(a);
|
|
249
733
|
const bVertex = this.getVertex(b);
|
|
250
|
-
if (!aVertex || !bVertex ||
|
|
734
|
+
if (!aVertex || !bVertex || !exports.CfgVertex.isBlock(aVertex) || !exports.CfgVertex.isBlock(bVertex)) {
|
|
251
735
|
return this;
|
|
252
736
|
}
|
|
253
|
-
const bElems = bVertex
|
|
254
|
-
aVertex
|
|
737
|
+
const bElems = exports.CfgVertex.getBasicBlockElements(bVertex);
|
|
738
|
+
exports.CfgVertex.setBasicBlockElements(aVertex, [...exports.CfgVertex.getBasicBlockElements(aVertex), ...bElems]);
|
|
255
739
|
// update cache
|
|
256
740
|
for (const elem of bElems) {
|
|
257
|
-
this.bbChildren.set(elem
|
|
741
|
+
this.bbChildren.set(exports.CfgVertex.getId(elem), a);
|
|
258
742
|
}
|
|
259
743
|
// drop all edges from a to b
|
|
260
744
|
this.removeEdge(a, b);
|
|
@@ -267,6 +751,7 @@ class ControlFlowGraph {
|
|
|
267
751
|
return this;
|
|
268
752
|
}
|
|
269
753
|
/**
|
|
754
|
+
* **This Operation is in-place and modifies the current graph.**
|
|
270
755
|
* Merge another control flow graph into this one.
|
|
271
756
|
* @param other - the other control flow graph to merge into this one
|
|
272
757
|
* @param forceNested - should the other graph be assumed to be fully nested (e.g., within a function definition).
|
|
@@ -274,24 +759,24 @@ class ControlFlowGraph {
|
|
|
274
759
|
* This is the pendant of {@link DataflowGraph#mergeWith|mergeWith()} on a {@link DataflowGraph}.
|
|
275
760
|
*/
|
|
276
761
|
mergeWith(other, forceNested = false) {
|
|
277
|
-
this.
|
|
278
|
-
const roots = other.
|
|
279
|
-
if (this.
|
|
280
|
-
for (const [id, node] of other.
|
|
762
|
+
this._mayBB ||= other._mayBB;
|
|
763
|
+
const roots = other.roots;
|
|
764
|
+
if (this._mayBB) {
|
|
765
|
+
for (const [id, node] of other.vtxInfos) {
|
|
281
766
|
this.addVertex(node, forceNested ? false : roots.has(id));
|
|
282
767
|
}
|
|
283
768
|
}
|
|
284
769
|
else {
|
|
285
|
-
for (const [id, node] of other.
|
|
286
|
-
this.
|
|
770
|
+
for (const [id, node] of other.vtxInfos) {
|
|
771
|
+
this.vtxInfos.set(id, node);
|
|
287
772
|
}
|
|
288
773
|
if (!forceNested) {
|
|
289
774
|
for (const root of roots) {
|
|
290
|
-
this.
|
|
775
|
+
this.roots.add(root);
|
|
291
776
|
}
|
|
292
777
|
}
|
|
293
778
|
}
|
|
294
|
-
for (const [from, edges] of other.
|
|
779
|
+
for (const [from, edges] of other.edgeInfos) {
|
|
295
780
|
this.addEdges(from, edges);
|
|
296
781
|
}
|
|
297
782
|
return this;
|