@@ -206,21 +206,15 @@ class OperandNode extends Node, TOperandNode {
206206 * A `StoreNode` is a node that has been (or is about to be) the
207207 * source or target of a `storeStep`.
208208 */
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 {
216210 /** Holds if this node should receive flow from `addr`. */
217211 abstract predicate flowInto ( Instruction addr ) ;
218212
219213 override Declaration getEnclosingCallable ( ) { result = this .getFunction ( ) }
220214
221215 /** Holds if this `StoreNode` is the root of the address computation used by a store operation. */
222216 predicate isTerminal ( ) {
223- not exists ( this .getAPredecessor ( ) ) and
217+ not exists ( this .getInner ( ) ) and
224218 not storeStep ( this , _, _)
225219 }
226220
@@ -233,20 +227,21 @@ abstract class StoreNode extends Node {
233227 /**
234228 * Gets the `StoreNode` that computes the address used by this `StoreNode`.
235229 */
236- abstract StoreNode getAPredecessor ( ) ;
230+ abstract StoreNode getInner ( ) ;
237231
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 }
240234}
241235
242- private class StoreNodeInstr extends StoreNode , TStoreNodeInstr {
236+ class StoreNodeInstr extends StoreNode , TStoreNodeInstr {
243237 Instruction instr ;
244238
245239 StoreNodeInstr ( ) { this = TStoreNodeInstr ( instr ) }
246240
247241 override predicate flowInto ( Instruction addr ) { this .getInstruction ( ) = addr }
248242
249- override Instruction getInstruction ( ) { result = instr }
243+ /** Gets the underlying instruction. */
244+ Instruction getInstruction ( ) { result = instr }
250245
251246 override Function getFunction ( ) { result = this .getInstruction ( ) .getEnclosingFunction ( ) }
252247
@@ -262,19 +257,45 @@ private class StoreNodeInstr extends StoreNode, TStoreNodeInstr {
262257 Ssa:: explicitWrite ( _, result , this .getInstruction ( ) )
263258 }
264259
265- override StoreNode getAPredecessor ( ) {
260+ override StoreNodeInstr getInner ( ) {
266261 Ssa:: addressFlow ( result .getInstruction ( ) , this .getInstruction ( ) )
267262 }
268263}
269264
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 {
271291 ArgumentOperand operand ;
272292
273293 StoreNodeOperand ( ) { this = TStoreNodeOperand ( operand ) }
274294
275295 override predicate flowInto ( Instruction addr ) { this .getOperand ( ) .getDef ( ) = addr }
276296
277- override Operand getOperand ( ) { result = operand }
297+ /** Gets the underlying operand. */
298+ Operand getOperand ( ) { result = operand }
278299
279300 override Function getFunction ( ) { result = operand .getDef ( ) .getEnclosingFunction ( ) }
280301
@@ -288,7 +309,32 @@ private class StoreNodeOperand extends StoreNode, TStoreNodeOperand {
288309 Ssa:: explicitWrite ( _, result , operand .getDef ( ) )
289310 }
290311
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 ( ) }
292338}
293339
294340/**
@@ -326,22 +372,20 @@ class ReadNode extends Node, TReadNode {
326372 * Gets a read node with an underlying instruction that is used by this
327373 * underlying instruction to compute an address of a load instruction.
328374 */
329- final ReadNode getAPredecessor ( ) {
330- Ssa:: addressFlow ( result .getInstruction ( ) , this .getInstruction ( ) )
331- }
375+ final ReadNode getInner ( ) { Ssa:: addressFlow ( result .getInstruction ( ) , this .getInstruction ( ) ) }
332376
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 }
335379
336380 /** Holds if this read node computes a value that will not be used for any future read nodes. */
337381 final predicate isTerminal ( ) {
338- not exists ( this .getASuccessor ( ) ) and
382+ not exists ( this .getOuter ( ) ) and
339383 not readStep ( this , _, _)
340384 }
341385
342386 /** Holds if this read node computes a value that has not yet been used for any read operations. */
343387 final predicate isInitial ( ) {
344- not exists ( this .getAPredecessor ( ) ) and
388+ not exists ( this .getInner ( ) ) and
345389 not readStep ( _, _, this )
346390 }
347391}
@@ -787,7 +831,7 @@ private module ReadNodeFlow {
787831 /** Holds if the read node `nodeTo` should receive flow from the read node `nodeFrom`. */
788832 predicate flowThrough ( ReadNode nodeFrom , ReadNode nodeTo ) {
789833 not readStep ( nodeFrom , _, _) and
790- nodeFrom .getASuccessor ( ) = nodeTo
834+ nodeFrom .getOuter ( ) = nodeTo
791835 }
792836
793837 /**
@@ -800,7 +844,7 @@ private module ReadNodeFlow {
800844 // Use-use flow to another use of the same variable instruction
801845 Ssa:: ssaFlow ( nFrom , nodeTo )
802846 or
803- not exists ( nFrom .getAPredecessor ( ) ) and
847+ not exists ( nFrom .getInner ( ) ) and
804848 exists ( Node store |
805849 Ssa:: explicitWrite ( _, store .asInstruction ( ) , nFrom .getInstruction ( ) ) and
806850 Ssa:: ssaFlow ( store , nodeTo )
@@ -833,15 +877,15 @@ private module StoreNodeFlow {
833877 predicate flowThrough ( StoreNode nFrom , StoreNode nodeTo ) {
834878 // Flow through a post update node that doesn't need a store step.
835879 not storeStep ( nFrom , _, _) and
836- nodeTo .getASuccessor ( ) = nFrom
880+ nodeTo .getOuter ( ) = nFrom
837881 }
838882
839883 /**
840884 * Holds if flow should leave the store node `nodeFrom` and enter the node `nodeTo`.
841885 * This happens because we have traversed an entire chain of field dereferences
842886 * after a store operation.
843887 */
844- predicate flowOutOf ( StoreNode nFrom , Node nodeTo ) {
888+ predicate flowOutOf ( StoreNodeInstr nFrom , Node nodeTo ) {
845889 nFrom .isTerminal ( ) and
846890 Ssa:: ssaFlow ( nFrom , nodeTo )
847891 }
0 commit comments