@eagleoutice/flowr 2.9.6 → 2.9.8
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 +28 -26
- package/abstract-interpretation/absint-visitor.d.ts +5 -4
- package/abstract-interpretation/absint-visitor.js +12 -11
- package/abstract-interpretation/data-frame/dataframe-domain.js +1 -2
- package/benchmark/slicer.d.ts +0 -1
- package/benchmark/slicer.js +3 -9
- package/benchmark/stats/print.js +1 -0
- package/benchmark/summarizer/data.d.ts +2 -0
- package/benchmark/summarizer/first-phase/process.js +3 -1
- package/benchmark/summarizer/second-phase/process.js +4 -0
- package/cli/repl/commands/repl-commands.d.ts +1 -0
- package/cli/repl/commands/repl-commands.js +1 -0
- package/cli/repl/commands/repl-normalize.d.ts +1 -0
- package/cli/repl/commands/repl-normalize.js +28 -1
- package/control-flow/basic-cfg-guided-visitor.d.ts +3 -3
- package/control-flow/basic-cfg-guided-visitor.js +8 -9
- package/control-flow/cfg-dead-code.js +16 -15
- 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 +384 -78
- package/control-flow/control-flow-graph.js +607 -115
- 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 +5 -4
- package/control-flow/extract-cfg.js +156 -127
- package/control-flow/happens-before.js +2 -1
- package/control-flow/semantic-cfg-guided-visitor.js +2 -1
- package/control-flow/simple-visitor.d.ts +1 -2
- package/control-flow/simple-visitor.js +20 -15
- package/control-flow/syntax-cfg-guided-visitor.js +2 -1
- package/control-flow/useless-loop.js +2 -1
- package/documentation/doc-readme.js +11 -9
- package/documentation/wiki-absint.js +4 -3
- package/documentation/wiki-cfg.js +21 -9
- package/documentation/wiki-mk/doc-context.d.ts +3 -0
- package/documentation/wiki-mk/doc-context.js +4 -1
- package/documentation/wiki-mk/doc-maker.js +1 -1
- package/linter/linter-rules.d.ts +2 -2
- package/linter/rules/dataframe-access-validation.d.ts +2 -2
- package/linter/rules/dataframe-access-validation.js +3 -3
- package/package.json +1 -1
- package/project/cache/flowr-analyzer-controlflow-cache.js +3 -0
- package/project/cfg-kind.d.ts +5 -1
- package/project/cfg-kind.js +5 -1
- package/project/plugins/file-plugins/files/flowr-namespace-file.js +3 -2
- package/project/plugins/file-plugins/files/flowr-rmarkdown-file.js +10 -2
- package/queries/catalog/control-flow-query/control-flow-query-format.js +1 -1
- package/queries/catalog/df-shape-query/df-shape-query-executor.js +12 -5
- package/r-bridge/lang-4.x/convert-values.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 +83 -53
- 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/r-regex.d.ts +4 -0
- package/util/r-regex.js +35 -3
- package/util/version.js +1 -1
- package/control-flow/invert-cfg.d.ts +0 -5
- package/control-flow/invert-cfg.js +0 -20
|
@@ -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,33 +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();
|
|
557
|
+
/** reverse edges for bidirectional mapping */
|
|
558
|
+
revEdgeInfos = new Map();
|
|
80
559
|
/** used as an optimization to avoid unnecessary lookups */
|
|
81
|
-
|
|
560
|
+
_mayBB = false;
|
|
82
561
|
/**
|
|
83
562
|
* Add a new vertex to the control flow graph.
|
|
84
563
|
* @see {@link ControlFlowGraph#addEdge|addEdge()} - to add an edge
|
|
85
564
|
*/
|
|
86
565
|
addVertex(vertex, rootVertex = true) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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`);
|
|
92
576
|
}
|
|
93
|
-
for (const elem of
|
|
94
|
-
this.bbChildren.set(elem
|
|
577
|
+
for (const elem of elems) {
|
|
578
|
+
this.bbChildren.set(exports.CfgVertex.getId(elem), vid);
|
|
95
579
|
}
|
|
96
580
|
}
|
|
97
|
-
this.
|
|
581
|
+
this.vtxInfos.set(vid, vertex);
|
|
98
582
|
if (rootVertex) {
|
|
99
|
-
this.
|
|
583
|
+
this.roots.add(vid);
|
|
100
584
|
}
|
|
101
585
|
return this;
|
|
102
586
|
}
|
|
@@ -106,51 +590,46 @@ class ControlFlowGraph {
|
|
|
106
590
|
* @see {@link ControlFlowGraph#addEdges|addEdges()} - to add multiple edges at once
|
|
107
591
|
*/
|
|
108
592
|
addEdge(from, to, edge) {
|
|
109
|
-
const edgesFrom = this.
|
|
110
|
-
if (!this.
|
|
111
|
-
this.
|
|
593
|
+
const edgesFrom = this.edgeInfos.get(from) ?? new Map();
|
|
594
|
+
if (!this.edgeInfos.has(from)) {
|
|
595
|
+
this.edgeInfos.set(from, edgesFrom);
|
|
112
596
|
}
|
|
113
597
|
edgesFrom.set(to, edge);
|
|
598
|
+
const edgesTo = this.revEdgeInfos.get(to) ?? new Map();
|
|
599
|
+
if (!this.revEdgeInfos.has(to)) {
|
|
600
|
+
this.revEdgeInfos.set(to, edgesTo);
|
|
601
|
+
}
|
|
602
|
+
edgesTo.set(from, edge);
|
|
114
603
|
return this;
|
|
115
604
|
}
|
|
116
605
|
/**
|
|
117
606
|
* Add multiple edges from a given source vertex to the control flow graph.
|
|
118
607
|
*/
|
|
119
608
|
addEdges(from, to) {
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
this.edgeInformation.set(from, edgesFrom);
|
|
123
|
-
}
|
|
124
|
-
for (const [toId, edge] of to) {
|
|
125
|
-
edgesFrom.set(toId, edge);
|
|
609
|
+
for (const [toNode, edge] of to) {
|
|
610
|
+
this.addEdge(from, toNode, edge);
|
|
126
611
|
}
|
|
127
612
|
return this;
|
|
128
613
|
}
|
|
129
614
|
outgoingEdges(node) {
|
|
130
|
-
return this.
|
|
615
|
+
return this.edgeInfos.get(node);
|
|
131
616
|
}
|
|
132
|
-
ingoingEdges(
|
|
133
|
-
|
|
134
|
-
for (const [source, outgoing] of this.edgeInformation.entries()) {
|
|
135
|
-
const o = outgoing.get(id);
|
|
136
|
-
if (o) {
|
|
137
|
-
edges.set(source, o);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return edges;
|
|
617
|
+
ingoingEdges(node) {
|
|
618
|
+
return this.revEdgeInfos.get(node);
|
|
141
619
|
}
|
|
142
620
|
rootIds() {
|
|
143
|
-
return this.
|
|
621
|
+
return this.roots;
|
|
144
622
|
}
|
|
145
623
|
vertices(includeBasicBlockElements = true) {
|
|
146
624
|
if (includeBasicBlockElements) {
|
|
147
|
-
const all = new Map(this.
|
|
625
|
+
const all = new Map(this.vtxInfos);
|
|
148
626
|
for (const [id, block] of this.bbChildren.entries()) {
|
|
149
627
|
const blockVertex = all.get(block);
|
|
150
|
-
if (blockVertex === undefined ||
|
|
628
|
+
if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
|
|
151
629
|
continue;
|
|
152
630
|
}
|
|
153
|
-
const
|
|
631
|
+
const elems = exports.CfgVertex.getBasicBlockElements(blockVertex);
|
|
632
|
+
const elem = elems.find(e => exports.CfgVertex.getId(e) === id);
|
|
154
633
|
if (elem !== undefined) {
|
|
155
634
|
all.set(id, elem);
|
|
156
635
|
}
|
|
@@ -158,7 +637,7 @@ class ControlFlowGraph {
|
|
|
158
637
|
return all;
|
|
159
638
|
}
|
|
160
639
|
else {
|
|
161
|
-
return this.
|
|
640
|
+
return this.vtxInfos;
|
|
162
641
|
}
|
|
163
642
|
}
|
|
164
643
|
getBasicBlock(elemId) {
|
|
@@ -166,20 +645,20 @@ class ControlFlowGraph {
|
|
|
166
645
|
if (block === undefined) {
|
|
167
646
|
return undefined;
|
|
168
647
|
}
|
|
169
|
-
const blockVertex = this.
|
|
170
|
-
if (blockVertex === undefined ||
|
|
648
|
+
const blockVertex = this.vtxInfos.get(block);
|
|
649
|
+
if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
|
|
171
650
|
return undefined;
|
|
172
651
|
}
|
|
173
652
|
return blockVertex;
|
|
174
653
|
}
|
|
175
654
|
edges() {
|
|
176
|
-
return this.
|
|
655
|
+
return this.edgeInfos;
|
|
177
656
|
}
|
|
178
657
|
/**
|
|
179
658
|
* Retrieve a vertex by its id.
|
|
180
659
|
*/
|
|
181
660
|
getVertex(id, includeBlocks = true) {
|
|
182
|
-
const res = this.
|
|
661
|
+
const res = this.vtxInfos.get(id);
|
|
183
662
|
if (res || !includeBlocks) {
|
|
184
663
|
return res;
|
|
185
664
|
}
|
|
@@ -187,17 +666,18 @@ class ControlFlowGraph {
|
|
|
187
666
|
if (block === undefined) {
|
|
188
667
|
return undefined;
|
|
189
668
|
}
|
|
190
|
-
const blockVertex = this.
|
|
191
|
-
if (blockVertex === undefined ||
|
|
669
|
+
const blockVertex = this.vtxInfos.get(block);
|
|
670
|
+
if (blockVertex === undefined || !exports.CfgVertex.isBlock(blockVertex)) {
|
|
192
671
|
return undefined;
|
|
193
672
|
}
|
|
194
|
-
|
|
673
|
+
const elems = exports.CfgVertex.getBasicBlockElements(blockVertex);
|
|
674
|
+
return elems.find(e => exports.CfgVertex.getId(e) === id);
|
|
195
675
|
}
|
|
196
676
|
hasVertex(id, includeBlocks = true) {
|
|
197
|
-
return this.
|
|
677
|
+
return this.vtxInfos.has(id) || (this._mayBB && includeBlocks && this.bbChildren.has(id));
|
|
198
678
|
}
|
|
199
679
|
mayHaveBasicBlocks() {
|
|
200
|
-
return this.
|
|
680
|
+
return this._mayBB;
|
|
201
681
|
}
|
|
202
682
|
/**
|
|
203
683
|
* This removes the vertex and all edges to and from it.
|
|
@@ -206,8 +686,9 @@ class ControlFlowGraph {
|
|
|
206
686
|
* @see {@link ControlFlowGraph#removeEdge|removeEdge()} - to remove a specific edge
|
|
207
687
|
*/
|
|
208
688
|
removeVertex(id) {
|
|
209
|
-
this.
|
|
210
|
-
this.
|
|
689
|
+
this.vtxInfos.delete(id);
|
|
690
|
+
this.edgeInfos.delete(id);
|
|
691
|
+
this.revEdgeInfos.delete(id);
|
|
211
692
|
this.bbChildren.delete(id);
|
|
212
693
|
// remove all bbChildren with id as target
|
|
213
694
|
for (const [a, b] of this.bbChildren.entries()) {
|
|
@@ -215,10 +696,13 @@ class ControlFlowGraph {
|
|
|
215
696
|
this.bbChildren.delete(a);
|
|
216
697
|
}
|
|
217
698
|
}
|
|
218
|
-
for (const edges of this.
|
|
699
|
+
for (const edges of this.edgeInfos.values()) {
|
|
700
|
+
edges.delete(id);
|
|
701
|
+
}
|
|
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,11 +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
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
if (
|
|
234
|
-
this.
|
|
714
|
+
const edgesFrom = this.edgeInfos.get(from);
|
|
715
|
+
if (edgesFrom) {
|
|
716
|
+
edgesFrom.delete(to);
|
|
717
|
+
if (edgesFrom.size === 0) {
|
|
718
|
+
this.edgeInfos.delete(from);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
const edgesTo = this.revEdgeInfos.get(to);
|
|
722
|
+
if (edgesTo) {
|
|
723
|
+
edgesTo.delete(from);
|
|
724
|
+
if (edgesTo.size === 0) {
|
|
725
|
+
this.revEdgeInfos.delete(to);
|
|
235
726
|
}
|
|
236
727
|
}
|
|
237
728
|
return this;
|
|
@@ -240,14 +731,14 @@ class ControlFlowGraph {
|
|
|
240
731
|
mergeTwoBasicBlocks(a, b) {
|
|
241
732
|
const aVertex = this.getVertex(a);
|
|
242
733
|
const bVertex = this.getVertex(b);
|
|
243
|
-
if (!aVertex || !bVertex ||
|
|
734
|
+
if (!aVertex || !bVertex || !exports.CfgVertex.isBlock(aVertex) || !exports.CfgVertex.isBlock(bVertex)) {
|
|
244
735
|
return this;
|
|
245
736
|
}
|
|
246
|
-
const bElems = bVertex
|
|
247
|
-
aVertex
|
|
737
|
+
const bElems = exports.CfgVertex.getBasicBlockElements(bVertex);
|
|
738
|
+
exports.CfgVertex.setBasicBlockElements(aVertex, [...exports.CfgVertex.getBasicBlockElements(aVertex), ...bElems]);
|
|
248
739
|
// update cache
|
|
249
740
|
for (const elem of bElems) {
|
|
250
|
-
this.bbChildren.set(elem
|
|
741
|
+
this.bbChildren.set(exports.CfgVertex.getId(elem), a);
|
|
251
742
|
}
|
|
252
743
|
// drop all edges from a to b
|
|
253
744
|
this.removeEdge(a, b);
|
|
@@ -260,6 +751,7 @@ class ControlFlowGraph {
|
|
|
260
751
|
return this;
|
|
261
752
|
}
|
|
262
753
|
/**
|
|
754
|
+
* **This Operation is in-place and modifies the current graph.**
|
|
263
755
|
* Merge another control flow graph into this one.
|
|
264
756
|
* @param other - the other control flow graph to merge into this one
|
|
265
757
|
* @param forceNested - should the other graph be assumed to be fully nested (e.g., within a function definition).
|
|
@@ -267,24 +759,24 @@ class ControlFlowGraph {
|
|
|
267
759
|
* This is the pendant of {@link DataflowGraph#mergeWith|mergeWith()} on a {@link DataflowGraph}.
|
|
268
760
|
*/
|
|
269
761
|
mergeWith(other, forceNested = false) {
|
|
270
|
-
this.
|
|
271
|
-
const roots = other.
|
|
272
|
-
if (this.
|
|
273
|
-
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) {
|
|
274
766
|
this.addVertex(node, forceNested ? false : roots.has(id));
|
|
275
767
|
}
|
|
276
768
|
}
|
|
277
769
|
else {
|
|
278
|
-
for (const [id, node] of other.
|
|
279
|
-
this.
|
|
770
|
+
for (const [id, node] of other.vtxInfos) {
|
|
771
|
+
this.vtxInfos.set(id, node);
|
|
280
772
|
}
|
|
281
773
|
if (!forceNested) {
|
|
282
774
|
for (const root of roots) {
|
|
283
|
-
this.
|
|
775
|
+
this.roots.add(root);
|
|
284
776
|
}
|
|
285
777
|
}
|
|
286
778
|
}
|
|
287
|
-
for (const [from, edges] of other.
|
|
779
|
+
for (const [from, edges] of other.edgeInfos) {
|
|
288
780
|
this.addEdges(from, edges);
|
|
289
781
|
}
|
|
290
782
|
return this;
|