Programming languages with dynamic memory allocation, such as Java, allow creating and manipulating cyclic data structures. The presence of cyclic data structures in the program memory (the heap) is a challenging issue in the context of termination analysis [4, 5, 1, 14], resource usage analysis [15, 7, 2], garbage collection [11], etc. Consider the loop “while (x!=null) do x:=x.next;”. If x points to an acyclic data structure before the loop, then the depth of the data structure to which x points strictly decreases after each iteration; therefore, the number of iterations is bounded by the initial depth of (the structure pointed to by) x. Automatic inference of such information is typically done by (1) abstracting the loop to a numeric loop “while(x)← {x>0,x>x′},while(x′)”; and (2) bounding the number of iterations of the numeric loop. The numeric loop means that, if the loop entry is reached with x pointing to a data structure with depth x > 0, then it will eventually be reached again with x pointing to a structure with depth x′ < x. The key point is that “x!=null” is abstracted to the condition x > 0, meaning that the depth of a non-null variable cannot be 0; moreover, abstracting “x:=x.next” to x > x′ means that the depth decreases when accessing fields. While the former is meaningful for any structure, the latter holds only if x is acyclic. Therefore, acyclicity information is essential in order to apply such abstractions. In mainstream programming languages with dynamic memory manipulation, data structures can only be modified by means of field updates. If, before x. f :=y, x and y are guaranteed to point to disjoint parts of the heap, then there is no possibility to create a cycle. On the other hand, if they are not disjoint, i.e., share a common part of the heap, then a cyclic structure might be created. This simple observation has been used in previous work [12] in order to declare x and y, among others, as cyclic whenever they were sharing before the update. Such approach is simple and efficient. However, there can be an important loss of precision in typical programming patterns. E.g., consider “y:=x.next.next;x.next:=y;” (which typically removes an element from a linked list), and let x be initially acyclic. After the first command, x and y clearly share, so that they should be finally declared as cyclic, even if, clearly, they are not. When considering x. f :=y, the precision of the acyclicity information can be improved if it is possible to know how x and y share. There are four possible cases: (1) x and y alias; (2) x reaches y; (3) y reaches x; (4) they both reach a common location. The update x:=y. f might create a cycle only in cases (1) and (3). This abstract summarizes an acyclicity analysis which is based on the above observation as described in [9]. The analysis has been first developed in [10]; more recent work [9] formalizes it in the theory of abstract interpretation, and reports on an implementation for Java bytecode. The analysis defines an abstract domain I τ rc which captures the reachability information among program variables (i.e., whether there can be a path in the heap from the location `v bound to some variable v and the location `w bound to some w), and the acyclicity of data structures (i.e., whether there can be a cyclic path starting from the location bound to some variable). A provably sound abstract semantics C τ ζ J K( ) of a simple objectoriented language is developed, that works on I τ rc, and can often guarantee the acyclicity of Directed Acyclic Graphs (DAGs), which most likely will be considered as cyclic if only sharing, not reachability, is taken into account. The semantics has been implemented in the COSTA [3] COSt and Termination Analyzer as a component whose result is an essential information for proving the termination or inferring the resource usage of programs.
[1]
Ben Wegbreit,et al.
Mechanical program analysis
,
1975,
CACM.
[2]
Patrick Cousot,et al.
Systematic design of program analysis frameworks
,
1979,
POPL.
[3]
Saumya K. Debray,et al.
Cost analysis of logic programs
,
1993,
TOPL.
[4]
Laurie J. Hendren,et al.
Is it a tree, a DAG, or a cyclic graph? A shape analysis for heap-directed pointers in C
,
1996,
POPL '96.
[5]
Rafael Dueire Lins,et al.
Garbage collection: algorithms for automatic dynamic memory management
,
1996
.
[6]
Stefano Secci,et al.
Pair-Sharing Analysis of Object-Oriented Programs
,
2005,
SAS.
[7]
Fausto Spoto,et al.
Detecting Non-cyclicity by Abstract Compilation into Boolean Functions
,
2006,
VMCAI.
[8]
Andreas Podelski,et al.
Termination proofs for systems code
,
2006,
PLDI '06.
[9]
Peter W. O'Hearn,et al.
Automatic Termination Proofs for Programs with Shape-Shifting Heaps
,
2006,
CAV.
[10]
Elvira Albert,et al.
COSTA: Design and Implementation of a Cost and Termination Analyzer for Java Bytecode
,
2008,
FMCO.
[11]
Elvira Albert,et al.
Cost Analysis of Java Bytecode
,
2007,
ESOP.
[12]
S. Genaim,et al.
Constancy Analysis
,
2008
.
[13]
Elvira Albert,et al.
Termination Analysis of Java Bytecode
,
2008,
FMOODS.
[14]
Étienne Payet,et al.
A termination analyzer for Java bytecode based on path-length
,
2010,
TOPL.
[15]
S. Genaim,et al.
Automatic Inference of Acyclicity ( long version with proofs ? )
,
2012
.