AutoAlias: Automatic Variable-Precision Alias Analysis for Object-Oriented Programs
Abstract
The aliasing question (can two reference expressions point, during an execution, to the same object?) is both one of the most critical in practice, for applications ranging from compiler optimization to programmer verification, and one of the most heavily researched, with many hundreds of publications over several decades. One might then expect that good off-the-shelf solutions are widely available, ready to be plugged into a compiler or verifier. This is not the case. In practice, efficient and precise alias analysis remains an open problem. We present a practical tool, AutoAlias, which can be used to perform automatic alias analysis for object-oriented programs. Based on the theory of “duality semantics”, an application of Abstract Interpretation ideas, it is directed at object-oriented languages and has been implemented for Eiffel as an addition to the EiffelStudio environment. It offers variable-precision analysis, controllable through the choice of a constant that governs the number of fixpoint iterations: a higher number means better precision and higher computation time. All the source code of AutoAlias, as well as detailed results of analyses reported in this article, are publicly available. Practical applications so far have covered a library of data structures and algorithms and a library for GUI creation. For the former, AutoAlias achieves a precision appropriate for practical purposes and execution times in the order of 25 s for about 8000 lines of intricate code. For the GUI library, AutoAlias produces the alias analysis in around 232 s for about 150,000 lines of intricate code.
Keywords
Alias analysis Object-oriented programming Points-to Program verificationIntroduction
One of the most interesting questions that can be asked about a program is the aliasing question: can two given path expressions, say first_element.next.next and last_element.previous.previous.previous, denote the same object in the run-time object structure? Alias analysis can be a key step in many applications, from compiler optimization to verification of object-oriented programs and even [13] deadlock analysis.
Alias analysis has correspondingly produced an abundant literature, of which “Related Work” section cites a small part. The contributions of AutoAlias, the approach described in the present work, are: a context- and flow-sensitive alias analysis technique applicable to object-oriented languages, based on a general theory of object structures; good precision, matching, or exceeding the results of previous authors; an efficient implementation for object-oriented programs, currently available for Eiffel [9].
One of the applications of alias analysis, presented in Refs. [6, 11, 12], is change analysis, also known as “frame inference”: what properties can an operation change? The reason alias analysis plays a key role for frame inference in object-oriented languages is that the basic property-changing operation, assignment x := e, changes not only x and any path expression starting with x, such as x.a, x.a.b etc., but also y.x, y.x.a and so on for any y that is aliased to the current object (“this”). Expanding on the original work in Refs. [6, 11, 12], we have implemented automatic frame analysis in the AutoFrame tool, based on AutoAlias. The frame analysis effort is the topic of a companion paper [18].
The basic practical results are as follows, with detail in “AutoAlias: A Graph-Based Implementation for the Alias Calculus”. We applied AutoAlias to a library of data structures and algorithms, EiffelBase 2, of about 8000 lines of code and 45 classes, and a significantly larger (150K-LOC) graphical (GUI) library, EiffelVision. For EiffelBase 2, to obtain a precision appropriate for practical purposes, AutoAlias takes about 25 s. For EiffelVision, it takes a little less than 4 min. In both cases, the results permit detailed alias and change analysis.
The entire source code of AutoAlias is available in a public repository at [16]. The repository also contains detailed results of analyses performed in AutoAlias and reported in this article.
Some elements of this article, particularly in “The Mathematical Basis: Object Diagrams” and “The Alias Calculus” sections, will at first sight appear similar to the corresponding presentations in the earlier work cited above. One of the reasons is simply to make the presentation self-contained rather than requiring the reader to go to the earlier work. More fundamentally, however, the similarity of form should not mask the fundamental differences. The mathematical model has been profoundly refined, and the implementation is completely new. The previous work is best viewed as a prototype for the present version.
“Related Work” section presents the previous work. “The Mathematical Basis: Object Diagrams” and “The Alias Calculus” show the mathematical basis and theory on which AutoAlias relies. “AutoAlias: A Graph-Based Implementation for the Alias Calculus” section presents the implementation of AutoAlias its evaluation and results. “Future Work and Conclusion” section summarizes the work.
Related Work
The work presented here is a continuation on the original work in Refs. [6, 11, 12]. The main difference is that we present a graph-based approach to the alias analysis, whereas the previous works used a relational-based approach. The immediate advantage is in performance.
Context-sensitive, meaning that it differentiates between executions of a given instruction in different contexts. In particular, AutoAlias is call-site-sensitive, meaning that it does not coalesce the effects of different calls to the same routine, such as f (a1) and f (a2), where the routine f (a) performs b := a, and a context-insensitive analysis could deduce that this may alias both a1 and a2 to b and hence (wrongly) to each other.
Flow-sensitive, meaning that it accounts for control flow: in if c then a := x else b := x end, the standard flow-insensitive analysis would report that a and b can get aliased to x, but flow-sensitive analysis reports that exactly one of them will.
Andersen [1] presents an efficient, inter-procedural pointer analysis for the C programming language. The analysis approximates for every variable of pointer type, the set of objects it may point to during program execution. This approach addresses C or languages of that level; the present work has been applied to a full-fledged object-oriented language. In an O–O context, some of the instructions may become unnecessary. In particular, there is no notion of plain pointers.
A specialization of context sensitivity is call-site sensitivity. References [19, 20] are the pioneers to use call sites as context. Whenever a routine gets called, the context under which the called method gets analyzed is a sequence of call sites. Another specialization of context sensitivity is object sensitivity [15] and type sensitivity [22]. These approaches use object abstractions or type information as contexts. Specifically, the analysis qualifies routine’s local variables with the allocation site of the receiver object of the method call. AutoAlias follows the same spirit; however, it also uses a flow-sensitive approach allowing a better precision of the analysis. An example of flow-sensitive analysis is Ref. [5], but it too introduces imprecision, in particular in handling assignments.
The Mathematical Basis: Object Diagrams
\(O \subseteq N\) Set of objects.
\(R \subseteq O\) Set of roots.
\(S: T \rightarrow O \rightarrow \mathbb {P}(O)\) Successors (references),
Definition 1
O is finite;
\(\mid R\mid > 1\), there exists at least one root.
A path of edges \(a,b,\ldots\) on an alias diagram is associated with the expression \(a.b.\ldots\) in O–O. For a path expression \(e = a.b.\ldots\), \(e_G\) is the (possibly empty) set of end nodes of paths with edges \(a, b, \ldots\) from any root in G.
An empty path is represented by Current (Current represents the current object in O–O computations—also known as “this” or “self”). A single-element path is written as a, two or more elements as \(a.b.c\ldots\). We let “.” to also represent concatenation, e.g., if p and q are paths, then p.q, a.q, and p.a are also paths (their path concatenations). Both Current .p and p. Current mean p.
Definition 2
E is the set of expressions appearing in the program and its prefixes (set of all paths in G)
Definition 3
\(V(\mathbf Current ) = R\).
\(V(p.a) = S(a)(V (p))\).
Definition 4
“Examples” section shows some examples for a better comprehension of the definitions, as well as examples on the operations describe in the next section.
Operations on Alias Diagrams
This section describes a set of operations on an alias diagram G. Operations assume \(X \subseteq O\), \(t \in T\), and lists of the same size \(l_1\), \(l_2\) of expressions. All the operations are implicitly subscripted by the name of the diagram, e.g., link is really \(\mathbf{link}_G\); the subscript will be omitted in the absence of ambiguity.
(Un)Linking Nodes
Operations for linking
Operation | Semantics |
---|---|
link t : X | Add edge t from every root to every member of X |
unlink t | Remove every edge labeled t from roots |
unlink \(l_1\) | Shorthand for: unlink \(l_1[i]\), where \(i \in 1..size(l_1)\) |
relink t:X | Shorthand for: unlink t; link t:X |
\(G[l_1: l_2]\) | link \(l_1[i]: V_G(l_2[i])\), where \(i \in 1..size(l_1)\) |
The last operation is particularly useful to link actual arguments to formal arguments in a feature call (for more details, see rule AC-UQCall in “The Alias Calculus” section).
Rooting Nodes
Operation for rooting
Operation | Semantics |
---|---|
reroot X | Replace R by X |
This operation (along with dot distribution—see “Generalization of Dot Distribution over Alias Diagrams” section) allows the analysis to be call-site sensitive.
Including Nodes
Operations for inclusion
Operation | Semantics |
---|---|
Include o | Choose \(o \in N\), where \(o \not \in O\) and add it to O |
New Alias Diagrams
Alias diagrams union
Operation | Semantics |
---|---|
\(G_1 \cup G_2\) | Yields the union of sets defined by \(G_1\) and \(G_2\) |
\(G = G_1 \cup G_2\), where \(N = N_1 \cup N_2\), \(R = R_1 \cup R_2\) and \(S = S_1 \cup S_2\) | |
clone(G) | Yields an alias diagram \(G'\) defined over a new set of objects \(O' \subseteq N - O\) and isomorphic to G |
Rules AC_Cond and AC_Loop use these operations to create new alias diagrams for each branch (either in conditionals or loops). This allows the analysis to be flow-sensitive when analyzing conditionals and loops (see “The Alias Calculus” section for more details).
Generalization of Dot Distribution over Alias Diagrams
The basic mechanism of object-oriented computations is feature call. All computations are achieved by calling certain features on a certain object. Consider x.f, this particular call means apply feature f to the object attached toeifx. Alias diagrams are built upon this mechanism. Authors in [14] introduce the notion of “distributed dot” that distributes the period of O-O programming over a list, a set or a relation; for example, \(x\bullet [u,v,w]\) denotes the list [x.u,x.v,x.w]. We extend the mechanism to dot distribution over alias diagrams.
Definition 5
For an alias diagram G, \(x\bullet G\) adds a back-pointer \(x'\) from x to each element in R, the roots of G. In other words, the effect of \(x\bullet G\) is \(S \cup \{(x', o, R) \mid o \in V(x)\}\).
This rule enables the analysis of alias diagrams to transpose the context of a call to the context of the caller, since it may depend and act on values and properties that are set by the object that launched the current call.
Examples
Figure 2 shows the graphical representation of possible alias diagrams. The set of nodes for G (see Fig. 2b) is \(N_G = \{\underline{n_0}, n_1, n_2\}\) and the successors \(T_G = \{(a, \underline{n_0}, \{n_1\}), (d, \underline{n_0}, \{n1\}), (c, \underline{n_0}, \{n_2\}), (b, n_1, \{n_2\})\}\). Alias diagrams have at least one root, \(R_G = \{n_0\}\) (we use underlined nodes to graphically represent the set of roots).
The set of all expressions in the graph is \(E_G = \{a, b, c, d, a.b, d.b\}\). This set is used to get the set of expression completion. This set is not particularly interesting for aliasing; however, it is an important definition to be used in the Framing problem: the problem of inferring all program locations that might change. As an example, the completion path of d is \(compl_G (d) = \{d.b\}\) and the completion path of a.b is \(compl_G (a.b) = \emptyset\). Set E is also used to compute aliasing, see Definition 4. As an example, the expressions aliased to c are \(alias_G (c) = \{c, a.b, d.b\}\).
Operations on alias diagrams
The Alias Calculus
The alias calculus is a set of rules defining the effect of executing an instruction on the aliasing that may exist between expressions. Each of these rules gives, for an instruction p of a given kind and an alias diagram G that holds in the initial state, the value of \(G \gg p\), the alias diagram that holds after the execution of p.
The Programming Language
The programming language figuring in the rules of the alias calculus given below is a common-core subset of modern object-oriented languages, including the fundamental constructs found, with varying syntax and other details, in Java, C#, Eiffel, C++, and others: respectively, reference assignment, composition (sequencing), object creation (new), conditional, loop, unqualified call, and qualified call. As a result, the present work applies to any O–O language, with possible fine-tuning to account for individual differences, and so potentially does AutoAlias, although so far, we have applied it to Eiffel only.
The Calculus
The alias calculus
Rule name | Rule | Semantics |
---|---|---|
AC-Assg | \(G \gg\) (t := s) | = relink \(t:V_G(s)\) |
AC-Comp | \(G \gg\) (p;q) | = (\(G \gg p\)) \(\gg q\) |
AC-New | \(G \gg\) (create t) | =include n; link \(t:\{n\}\) |
AC-Cond | \(G \gg\) (then p else q end) | = (\(G \gg p\)) \(\cup\) (clone (\(G \gg q\))) |
AC-Loop | \(G \gg\) (loop p end) | = \(\bigcup \limits _{i \in {\mathbb {N}}}\) (\(G_i \gg p\)) |
AC-UQCall | \(G \gg\) (call f (l)) | =(\(G[f^\bullet : l] \gg {\mid }f{\mid }\)) |
AC-QCall | \(G \gg\) (x. call f (l)) | \(\mathbf reroot _{ (( \mathbf reroot _{x'\bullet G} V(x) \gg \mathbf call f(x'.l) ))} R_G\) |
Assignments
Composition
Creation
Conditionals
The AC-Cond rule (and its optimization) is sound. The example shown in Fig. 6 (or Fig. 7) elucidates the flow-sensitive approach of the analysis: the resulting alias diagram in Fig. 6e (or Fig. 7) reports that either x may be aliased to a or may be aliased to b but not both. Furthermore, the diagrams also report that a may not be aliased to b as a result of executing the instruction.
Loops
Rule AC-Loop introduces imprecision, but retains soundness. An optimization of the rules is to consider the loop condition. In the general case, determining loop termination is undecidable, but there are specific cases that can be asserted, e.g., the approach might be able to determine whether two variables v and w are already aliased, as in until v = w loop p end (same concept can be applied to condition in rule AC-Cond).
Unqualified Calls
Qualified Calls
AutoAlias: A Graph-Based Implementation for the Alias Calculus
AutoAlias is a graph-based implementation for the alias calculus, sources of the tool are available in Ref. [16] and results can be checked in Ref. [17].
One of the main concerns of a graph-based approach with respect to the relation-based one (an approach from Refs. [6, 11, 12]) is the performance of the computation, especially when dealing with conditionals and loops (including recursion). This can be seen in rules AC-Cond and AC-Loop from “The Alias Calculus” section: both rules perform union operations on graphs. “Handling Conditionals” and “Handling Loops” sections show the techniques being used when dealing with such cases. “Dynamic Binding” section explains how Dynamic Binding (and Inheritance and Polymorphism), an important property of O–O computations is being handled.
Handling Conditionals
The non-deterministic choice instruction has the form
then
\(branch_1\)
elseif
\(branch_2\)
...
else
\(branch_{n}\)
end
According to the AC-Cond rule, each branch of the conditional (\({ branch}_1\) ...\({ branch}_n\)) is analyzed with a starting alias diagram G that holds initially. Then, the resulting diagrams are cloned and union. When processing \({ branch}_i\), where \(i \in 1 \ldots n\), the implementation maintains two sets: \(A_i \in T \rightarrow O \rightarrow O\) (insertions—A for additions—of references in the alias diagram) and \(D_i \in T \rightarrow O \rightarrow O\) (deletions—D for deletions—of references). Both sets will contain triples \(({ name, source, target})\).
At the end of processing branch i, the implementation removes all the elements of \(A_i\) and add all elements of \(D_i\) to the alias graph (so as to get back to the starting state).
- (i)
clones the root of the diagram \(n-1\) times;
- (ii)
for all \(b \in 2 \ldots n\) and for all \((n,s,t) \in D_b\), adds \((n, R^b, t)\) to the alias diagram;
- (iii)
for all \(b \in 2 \ldots n\) and for all \((n,s,t) \in A_b\), adds \(({ names} (s, t), R^b, t)\) to the alias diagram, where \({ names} ({ source, target})\) is a function returning the set of names from \({ source}\) to \({ target}\) in the alias diagram;
- (iv)
changes the corresponding clone root in sets A and D;
- (v)
inserts the union of \(A_i\) and removes the union of \(D_i\) in the alias diagram.
The process is an optimization of the rules. Notice that each branch of a conditional will only change a small part of the diagram, this is being handled by just copying the edges that are being modified by the program.
Handling Loops
Consider the instruction \(G \gg\) loop p end as executing the instruction p any number of times (i) including none, and unioning the resulting alias diagrams, so it can produce G (when \(i=0\)), or \(((G \gg p) \gg p)\) (when \(i=2\)), or \((((G \gg p) \gg p) \gg p)\) (when \(i=3\)) and so on.
Use a single D (deletion) set. Here, there is no need for A sets.
Process the loop body (p) repeatedly, at each iteration adding deleted references to D.
At the end of each iteration, nothing special needs to be done.
Stop when reaching a fixpoint.
At the end of the process, re-insert the elements of D.
Maintain a single D (deletion) set, as well as a stack with each call (and its target object).
For each call, update the stack (so to handle the different ways of recursion, e.g., direct or indirect recursion).
Process the feature body repeatedly, at each call adding deleted references to D.
Stop when reaching a fixpoint using the stack calls.
At the end of the process, re-insert the elements of D.
Lemma 1
If the analysis starts from an existing graph and the program does not perform any object creations, then the iteration process (for loops) reaches a fixpoint finitely.
Proof of the Lemma
The graph is finite; each iteration does not remove any nodes or edges, and can only insert edges. This cannot go on forever. \(\square\)
- S1
The first N times processing the instruction, apply the normal rule (remove all edges labeled x from the root, create new node, create edge labeled x from the root to that node)
- S2
The Nth time processing the instruction, after doing S1, add the label fx to the new edge (i.e., alias fx to x).
- S3
Every subsequent time processing the instruction (starting with the \(N+\)1st), treat it not through the creation instruction rule but as if it were the assignment x := fx.
Dynamic Binding
One of the main mechanisms of O–O programming is inheritance. It enables users to create ‘is-a’ relations between different classes: considering A and B as types, if B inherits from A, whenever an instance of A is required, an instance of B will be acceptable. This mechanism enables entities to be polymorphic: an entity is polymorphic if at run-time, its type differs from its static type.
A must-aliasing approach will yield, after executing feature call_set in Fig. 15c, a result that depends on the dynamic type of the entity t: if during execution t is attached to an object of type T1, the result would be t.c is aliased to a and if during execution, t is attached to an object of type T2, the result would be t.b is aliased to a.
A may-aliasing approach (as the one adopted by AutoAlias) would yield that t.c may be aliased to a or that t.b may be aliased to a. The mechanism implemented by AutoAlias is to treat the instruction as a conditional; in this case, it would be:
then
t.set (a) —considering t attached to T1
else
t.set (a) —considering t attached to T2
end
The mechanism introduces imprecision but retains soundness. Notice that t.c may be aliased to a or t.b may be aliased to a, but t.b may not be aliased to t.c.
Using AutoAlias
AutoFrame
AutoFrame is a companion tool [18] that uses AutoAlias. AutoFrame produces the set of locations that are allowed to change in a routine. It statically analyzes the source code of a routine. AutoFrame relies on Autoalias to determine possibly aliasing. The most relevant results of AutoFrame so far are (i) the automatic reconstruction of the exact frame clauses, a total of 169 clauses, for an 8000+ lines data structures and algorithms. The frame inference in this case takes about 25 s on an ordinary laptop computer. (ii) The automatic generation of frame conditions of a 150,000 lines library for building GUIs. The frame inference in this case takes about 232 s.
Precision of AutoAlias
Figure 17a defines the algorithm in a C-like program. List is a structure containing two pointers: to the head (char *hd) and to the tail (List *tl) of the list. Copy is a procedure that returns a list which is a copy of the elements of the list being passed as an argument. In Fig. 17b, the List structure is implemented as a class (LST) that contains two references: to the head (hd) and to the tail (tl: LST) of the list. The procedure copy_ is an implementation of copy. The return value of a routine in Eiffel is set by assigning it to the local variable Result. The type of this local variable is the one defined as the return type in the signature of the routine (LST in this case). Hence, there is not need to create the local variable p, as in Fig. 17a, we directly use Result. In Eiffel, class attributes have read-only privileges from outside the class: they can be changed only through procedures. This protects encapsulation and consistency of the object. Hence, the instruction Result .tl := copy_ (t1) is not permitted unless the proper assigner routines are being set. Figure 17b does not show the corresponding setter routines due to space.
Program property | [8] | [2] | [7] | [3] | [4] | AutoAlias |
---|---|---|---|---|---|---|
\(P_1\): X and Y are acyclic | Yes | Yes | Yes | Yes | ||
\(P_2\): two successive heads of Y don’t alias | Yes | Yes | Yes | |||
\(P_3\): X and Y tails don’t alias | Yes | Yes | Yes | Yes | Yes | |
\(P_4\): heads of X and Y are aliased only pairwise | Yes | Yes | ||||
\(P_5\): at point \(L_3\), heads and tails of Y are completely unaliased | Yes | Yes | Yes |
Future Work and Conclusion
A widely available, widely applicable, easy-to-integrate, and fast tool for alias analysis would immediately and immensely benefit many tasks of programming language implementation and verification. AutoAlias does not yet fulfill all these criteria, but provides, in our opinion, a significant step forward. The examples to which we have applied to the tool so far, while still limited, provide encouraging evidence of the solidity and scalability of the approach. The application to change analysis, described in the companion paper, are currently the showcase, but many others are potentially open, of interest to both tool developers (in particular developers of compilers and verification tools) and application programmers.
We realize the extent of the work that remains ahead, including the following: taking into account tricky language mechanisms such as exceptions and function objects (closures in Java, delegates in C#, agents in Eiffel); taking into account calls to external software mechanisms, e.g., system calls, which can potentially put the soundness of alias analysis into question, since objects then go into the big bad world out there, where anything can happen to them (but can we still reason about them without having to adopt the worst-case disaster scenario in which nothing can be assumed any longer?); refining the analysis and improving its precision further by taking into account ever more sophisticated patterns in conditional instructions and loops.
It is our hope, however, that the present state of the work, as described in this article, advances the search for general and effective techniques of automatic alias analysis.
Notes
Acknowledgements
We are indebted to colleagues who collaborated on the previous iterations of the alias calculus work, particular Sergey Velder (ITMO University) for many important suggestions regarding the theory, Alexander Kogtenkov (Eiffel Software, also then ETH Zurich) who implemented an earlier version of the Change Calculus, and Marco Trudel (then ETH Zurich). We thank members of the Software Engineering Laboratory at Innopolis University, particularly Manuel Mazzara and Alexander Naumchev, for many fruitful discussions.
Compliance with ethical standards
Conflict of interest
The authors declare that they have no conflict of interest.
References
- 1.Andersen LO. Program analysis and specialization for the C programming language. Technical report (1994).Google Scholar
- 2.Chase DR, Wegman M, Zadeck FK. Analysis of pointers and structures. SIGPLAN Not. 1990;25(6):296–310.CrossRefGoogle Scholar
- 3.Choi J-D, Burke M, Carini P. Efficient flow-sensitive interprocedural computation of pointer-induced aliases and side effects. In: Proceedings of the 20th ACM SIGPLAN-SIGACT symposium on principles of programming languages, POPL ’93. New York: ACM; 1993. p. 232–45.Google Scholar
- 4.Deutsch A. Interprocedural may-alias analysis for pointers: beyond k-limiting. SIGPLAN Not. 1994;29(6):230–41.CrossRefGoogle Scholar
- 5.Hardekopf B, Lin C. Flow-sensitive pointer analysis for millions of lines of code. In: Proceedings of the 9th annual IEEE/ACM international symposium on code generation and optimization, CGO ’11. IEEE Computer Society: Washington, DC; 2011. p. 289–98.Google Scholar
- 6.Kogtenkov A, Meyer B, Velder S. Alias calculus, change calculus and frame inference. Sci Comput Program. 2015;97(P1):163–72.CrossRefGoogle Scholar
- 7.Landi W, Ryder BG. A safe approximate algorithm for interprocedural aliasing. In: Proceedings of the ACM SIGPLAN 1992 conference on programming language design and implementation, PLDI ’92. ACM: New York; 1992. p. 235–248.Google Scholar
- 8.Larus JR, Hilfinger PN. Detecting conflicts between structure accesses. SIGPLAN Not. 1988;23(7):24–31.CrossRefGoogle Scholar
- 9.Meyer B. Eiffel: a language and environment for software engineering. J Syst Softw. 1988;8(3):199–246.CrossRefGoogle Scholar
- 10.Meyer B. Object-oriented software construction. 2nd ed. Upper Saddle River: Prentice-Hall; 1997.zbMATHGoogle Scholar
- 11.Meyer B. Towards a theory and calculus of aliasing. J Object Technol. 2010;9(2):37–74 (column).CrossRefGoogle Scholar
- 12.Meyer B. Framing the frame problem. In: Pretschner A, Broy M, Irlbeck M, editors. Dependable software systems. New York: Springer; 2014. p. 174–85.Google Scholar
- 13.Meyer B. An automatic technique for static deadlock prevention. In: Voronkov A, Virbitskaite I, editors. Perspectives of system informatics. Berlin: Springer; 2015. p. 45–58.CrossRefGoogle Scholar
- 14.Meyer B, Kogtenkov A. Negative variables and the essence of object-oriented programming. Berlin: Springer; 2014. p. 171–87.Google Scholar
- 15.Milanova A, Rountev A, Ryder BG. Parameterized object sensitivity for points-to analysis for Java. ACM Trans Softw Eng Methodol. 2005;14(1):1–41.CrossRefGoogle Scholar
- 16.Rivera V. Autoalias and autoframe implementations; 2019. https://github.com/varivera/alias_graph_based/tree/master/autoframe commit:25d20fc529151d19760f12a3566681fd0c79b1ed.
- 17.Rivera V. Autoalias and autoframe results. https://varivera.github.io/autoalias.html. Accessed Apr 2019.
- 18.Rivera V, Bertrand M. Autoframe: automatic frame inference for object-oriented languages. Companion paper to this one, under submission (pre-print available at https://arxiv.org/pdf/1808.08751.pdf); 2019.
- 19.Sharir M, Pnueli A. Two approaches to interprocedural data flow analysis, chapter 7. Englewood Cliffs: Prentice-Hall; 1981. p. 189–234.Google Scholar
- 20.Shivers OG. Control-flow analysis of higher-order languages of taming lambda. Ph.D. thesis, Pittsburgh. UMI Order No. GAX91-26964; 1991.Google Scholar
- 21.Smaragdakis Y, Balatsouras G. Pointer analysis. Found Trends Program Lang. 2015;2(1):1–69.CrossRefGoogle Scholar
- 22.Smaragdakis Y, Bravenboer M, Lhoták O. Pick your contexts well: understanding object-sensitivity. SIGPLAN Not. 2011;46(1):17–30.CrossRefGoogle Scholar
- 23.Sridharan M, Chandra S, Dolby J, Fink SJ, Yahav E. Aliasing in object-oriented programming. Chapter alias analysis for object-oriented programs. Berlin: Springer; 2013. p. 196–232.Google Scholar