@@ -206,21 +206,15 @@ class OperandNode extends Node, TOperandNode {
206
206
* A `StoreNode` is a node that has been (or is about to be) the
207
207
* source or target of a `storeStep`.
208
208
*/
209
- abstract class StoreNode extends Node {
210
- /** Gets the underlying instruction, if any. */
211
- Instruction getInstruction ( ) { none ( ) }
212
-
213
- /** Gets the underlying operand, if any. */
214
- Operand getOperand ( ) { none ( ) }
215
-
209
+ abstract private class StoreNode extends Node {
216
210
/** Holds if this node should receive flow from `addr`. */
217
211
abstract predicate flowInto ( Instruction addr ) ;
218
212
219
213
override Declaration getEnclosingCallable ( ) { result = this .getFunction ( ) }
220
214
221
215
/** Holds if this `StoreNode` is the root of the address computation used by a store operation. */
222
216
predicate isTerminal ( ) {
223
- not exists ( this .getAPredecessor ( ) ) and
217
+ not exists ( this .getInner ( ) ) and
224
218
not storeStep ( this , _, _)
225
219
}
226
220
@@ -233,20 +227,21 @@ abstract class StoreNode extends Node {
233
227
/**
234
228
* Gets the `StoreNode` that computes the address used by this `StoreNode`.
235
229
*/
236
- abstract StoreNode getAPredecessor ( ) ;
230
+ abstract StoreNode getInner ( ) ;
237
231
238
- /** The inverse of `StoreNode.getAPredecessor `. */
239
- final StoreNode getASuccessor ( ) { result .getAPredecessor ( ) = this }
232
+ /** The inverse of `StoreNode.getInner `. */
233
+ final StoreNode getOuter ( ) { result .getInner ( ) = this }
240
234
}
241
235
242
- private class StoreNodeInstr extends StoreNode , TStoreNodeInstr {
236
+ class StoreNodeInstr extends StoreNode , TStoreNodeInstr {
243
237
Instruction instr ;
244
238
245
239
StoreNodeInstr ( ) { this = TStoreNodeInstr ( instr ) }
246
240
247
241
override predicate flowInto ( Instruction addr ) { this .getInstruction ( ) = addr }
248
242
249
- override Instruction getInstruction ( ) { result = instr }
243
+ /** Gets the underlying instruction. */
244
+ Instruction getInstruction ( ) { result = instr }
250
245
251
246
override Function getFunction ( ) { result = this .getInstruction ( ) .getEnclosingFunction ( ) }
252
247
@@ -262,19 +257,45 @@ private class StoreNodeInstr extends StoreNode, TStoreNodeInstr {
262
257
Ssa:: explicitWrite ( _, result , this .getInstruction ( ) )
263
258
}
264
259
265
- override StoreNode getAPredecessor ( ) {
260
+ override StoreNodeInstr getInner ( ) {
266
261
Ssa:: addressFlow ( result .getInstruction ( ) , this .getInstruction ( ) )
267
262
}
268
263
}
269
264
270
- private class StoreNodeOperand extends StoreNode , TStoreNodeOperand {
265
+ /**
266
+ * To avoid having `PostUpdateNode`s with multiple pre-update nodes (which can cause performance
267
+ * problems) we attach the `PostUpdateNode` that represent output arguments to an operand instead of
268
+ * an instruction.
269
+ *
270
+ * To see why we need this, consider the expression `b->set(new C())`. The IR of this expression looks
271
+ * like (simplified):
272
+ * ```
273
+ * r1(glval<unknown>) = FunctionAddress[set] :
274
+ * r2(glval<unknown>) = FunctionAddress[operator new] :
275
+ * r3(unsigned long) = Constant[8] :
276
+ * r4(void *) = Call[operator new] : func:r2, 0:r3
277
+ * r5(C *) = Convert : r4
278
+ * r6(glval<unknown>) = FunctionAddress[C] :
279
+ * v1(void) = Call[C] : func:r6, this:r5
280
+ * v2(void) = Call[set] : func:r1, this:r0, 0:r5
281
+ * ```
282
+ *
283
+ * Notice that both the call to `C` and the call to `set` will have an argument that is the
284
+ * result of calling `operator new` (i.e., `r4`). If we only have `PostUpdateNode`s that are
285
+ * instructions, both `PostUpdateNode`s would have `r4` as their pre-update node.
286
+ *
287
+ * We avoid this issue by having a `PostUpdateNode` for each argument, and let the pre-update node of
288
+ * each `PostUpdateNode` be the argument _operand_, instead of the defining instruction.
289
+ */
290
+ class StoreNodeOperand extends StoreNode , TStoreNodeOperand {
271
291
ArgumentOperand operand ;
272
292
273
293
StoreNodeOperand ( ) { this = TStoreNodeOperand ( operand ) }
274
294
275
295
override predicate flowInto ( Instruction addr ) { this .getOperand ( ) .getDef ( ) = addr }
276
296
277
- override Operand getOperand ( ) { result = operand }
297
+ /** Gets the underlying operand. */
298
+ Operand getOperand ( ) { result = operand }
278
299
279
300
override Function getFunction ( ) { result = operand .getDef ( ) .getEnclosingFunction ( ) }
280
301
@@ -288,7 +309,32 @@ private class StoreNodeOperand extends StoreNode, TStoreNodeOperand {
288
309
Ssa:: explicitWrite ( _, result , operand .getDef ( ) )
289
310
}
290
311
291
- override StoreNode getAPredecessor ( ) { operand .getDef ( ) = result .getInstruction ( ) }
312
+ /**
313
+ * The result of `StoreNodeOperand.getInner` is the `StoreNodeInstr` representation the instruction
314
+ * that defines this operand. This means the graph of `getInner` looks like this:
315
+ * ```
316
+ * I---I---I
317
+ * \ \ \
318
+ * O O O
319
+ * ```
320
+ * where each `StoreNodeOperand` "hooks" into the chain computed by `StoreNodeInstr.getInner`.
321
+ * This means that the chain of `getInner` calls on the argument `&o.f` on an expression
322
+ * like `func(&o.f)` is:
323
+ * ```
324
+ * r4---r3---r2
325
+ * \
326
+ * 0:r4
327
+ * ```
328
+ * where the IR for `func(&o.f)` looks like (simplified):
329
+ * ```
330
+ * r1(glval<unknown>) = FunctionAddress[func] :
331
+ * r2(glval<O>) = VariableAddress[o] :
332
+ * r3(glval<int>) = FieldAddress[f] : r2
333
+ * r4(int *) = CopyValue : r3
334
+ * v1(void) = Call[func] : func:r1, 0:r4
335
+ * ```
336
+ */
337
+ override StoreNodeInstr getInner ( ) { operand .getDef ( ) = result .getInstruction ( ) }
292
338
}
293
339
294
340
/**
@@ -326,22 +372,20 @@ class ReadNode extends Node, TReadNode {
326
372
* Gets a read node with an underlying instruction that is used by this
327
373
* underlying instruction to compute an address of a load instruction.
328
374
*/
329
- final ReadNode getAPredecessor ( ) {
330
- Ssa:: addressFlow ( result .getInstruction ( ) , this .getInstruction ( ) )
331
- }
375
+ final ReadNode getInner ( ) { Ssa:: addressFlow ( result .getInstruction ( ) , this .getInstruction ( ) ) }
332
376
333
- /** The inverse of `ReadNode.getAPredecessor `. */
334
- final ReadNode getASuccessor ( ) { result .getAPredecessor ( ) = this }
377
+ /** The inverse of `ReadNode.getInner `. */
378
+ final ReadNode getOuter ( ) { result .getInner ( ) = this }
335
379
336
380
/** Holds if this read node computes a value that will not be used for any future read nodes. */
337
381
final predicate isTerminal ( ) {
338
- not exists ( this .getASuccessor ( ) ) and
382
+ not exists ( this .getOuter ( ) ) and
339
383
not readStep ( this , _, _)
340
384
}
341
385
342
386
/** Holds if this read node computes a value that has not yet been used for any read operations. */
343
387
final predicate isInitial ( ) {
344
- not exists ( this .getAPredecessor ( ) ) and
388
+ not exists ( this .getInner ( ) ) and
345
389
not readStep ( _, _, this )
346
390
}
347
391
}
@@ -787,7 +831,7 @@ private module ReadNodeFlow {
787
831
/** Holds if the read node `nodeTo` should receive flow from the read node `nodeFrom`. */
788
832
predicate flowThrough ( ReadNode nodeFrom , ReadNode nodeTo ) {
789
833
not readStep ( nodeFrom , _, _) and
790
- nodeFrom .getASuccessor ( ) = nodeTo
834
+ nodeFrom .getOuter ( ) = nodeTo
791
835
}
792
836
793
837
/**
@@ -800,7 +844,7 @@ private module ReadNodeFlow {
800
844
// Use-use flow to another use of the same variable instruction
801
845
Ssa:: ssaFlow ( nFrom , nodeTo )
802
846
or
803
- not exists ( nFrom .getAPredecessor ( ) ) and
847
+ not exists ( nFrom .getInner ( ) ) and
804
848
exists ( Node store |
805
849
Ssa:: explicitWrite ( _, store .asInstruction ( ) , nFrom .getInstruction ( ) ) and
806
850
Ssa:: ssaFlow ( store , nodeTo )
@@ -833,15 +877,15 @@ private module StoreNodeFlow {
833
877
predicate flowThrough ( StoreNode nFrom , StoreNode nodeTo ) {
834
878
// Flow through a post update node that doesn't need a store step.
835
879
not storeStep ( nFrom , _, _) and
836
- nodeTo .getASuccessor ( ) = nFrom
880
+ nodeTo .getOuter ( ) = nFrom
837
881
}
838
882
839
883
/**
840
884
* Holds if flow should leave the store node `nodeFrom` and enter the node `nodeTo`.
841
885
* This happens because we have traversed an entire chain of field dereferences
842
886
* after a store operation.
843
887
*/
844
- predicate flowOutOf ( StoreNode nFrom , Node nodeTo ) {
888
+ predicate flowOutOf ( StoreNodeInstr nFrom , Node nodeTo ) {
845
889
nFrom .isTerminal ( ) and
846
890
Ssa:: ssaFlow ( nFrom , nodeTo )
847
891
}
0 commit comments